1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  */
36 
37 #define DEBUG_SUBSYSTEM S_LMV
38 #include <linux/slab.h>
39 #include <linux/module.h>
40 #include <linux/pagemap.h>
41 #include <asm/div64.h>
42 #include <linux/seq_file.h>
43 #include <linux/namei.h>
44 #include "../include/lustre_intent.h"
45 #include "../include/obd_support.h"
46 #include "../include/lustre/lustre_idl.h"
47 #include "../include/lustre_lib.h"
48 #include "../include/lustre_net.h"
49 #include "../include/lustre_dlm.h"
50 #include "../include/obd_class.h"
51 #include "../include/lprocfs_status.h"
52 #include "lmv_internal.h"
53 
lmv_intent_remote(struct obd_export * exp,void * lmm,int lmmsize,struct lookup_intent * it,const struct lu_fid * parent_fid,int flags,struct ptlrpc_request ** reqp,ldlm_blocking_callback cb_blocking,__u64 extra_lock_flags)54 static int lmv_intent_remote(struct obd_export *exp, void *lmm,
55 			     int lmmsize, struct lookup_intent *it,
56 			     const struct lu_fid *parent_fid, int flags,
57 			     struct ptlrpc_request **reqp,
58 			     ldlm_blocking_callback cb_blocking,
59 			     __u64 extra_lock_flags)
60 {
61 	struct obd_device	*obd = exp->exp_obd;
62 	struct lmv_obd		*lmv = &obd->u.lmv;
63 	struct ptlrpc_request	*req = NULL;
64 	struct lustre_handle	plock;
65 	struct md_op_data	*op_data;
66 	struct lmv_tgt_desc	*tgt;
67 	struct mdt_body		*body;
68 	int			pmode;
69 	int			rc = 0;
70 
71 	body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
72 	if (body == NULL)
73 		return -EPROTO;
74 
75 	LASSERT((body->valid & OBD_MD_MDS));
76 
77 	/*
78 	 * Unfortunately, we have to lie to MDC/MDS to retrieve
79 	 * attributes llite needs and provideproper locking.
80 	 */
81 	if (it->it_op & IT_LOOKUP)
82 		it->it_op = IT_GETATTR;
83 
84 	/*
85 	 * We got LOOKUP lock, but we really need attrs.
86 	 */
87 	pmode = it->d.lustre.it_lock_mode;
88 	if (pmode) {
89 		plock.cookie = it->d.lustre.it_lock_handle;
90 		it->d.lustre.it_lock_mode = 0;
91 		it->d.lustre.it_data = NULL;
92 	}
93 
94 	LASSERT(fid_is_sane(&body->fid1));
95 
96 	tgt = lmv_find_target(lmv, &body->fid1);
97 	if (IS_ERR(tgt)) {
98 		rc = PTR_ERR(tgt);
99 		goto out;
100 	}
101 
102 	op_data = kzalloc(sizeof(*op_data), GFP_NOFS);
103 	if (!op_data) {
104 		rc = -ENOMEM;
105 		goto out;
106 	}
107 
108 	op_data->op_fid1 = body->fid1;
109 	/* Sent the parent FID to the remote MDT */
110 	if (parent_fid != NULL) {
111 		/* The parent fid is only for remote open to
112 		 * check whether the open is from OBF,
113 		 * see mdt_cross_open */
114 		LASSERT(it->it_op & IT_OPEN);
115 		op_data->op_fid2 = *parent_fid;
116 		/* Add object FID to op_fid3, in case it needs to check stale
117 		 * (M_CHECK_STALE), see mdc_finish_intent_lock */
118 		op_data->op_fid3 = body->fid1;
119 	}
120 
121 	op_data->op_bias = MDS_CROSS_REF;
122 	CDEBUG(D_INODE, "REMOTE_INTENT with fid="DFID" -> mds #%d\n",
123 	       PFID(&body->fid1), tgt->ltd_idx);
124 
125 	rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it,
126 			    flags, &req, cb_blocking, extra_lock_flags);
127 	if (rc)
128 		goto out_free_op_data;
129 
130 	/*
131 	 * LLite needs LOOKUP lock to track dentry revocation in order to
132 	 * maintain dcache consistency. Thus drop UPDATE|PERM lock here
133 	 * and put LOOKUP in request.
134 	 */
135 	if (it->d.lustre.it_lock_mode != 0) {
136 		it->d.lustre.it_remote_lock_handle =
137 					it->d.lustre.it_lock_handle;
138 		it->d.lustre.it_remote_lock_mode = it->d.lustre.it_lock_mode;
139 	}
140 
141 	it->d.lustre.it_lock_handle = plock.cookie;
142 	it->d.lustre.it_lock_mode = pmode;
143 
144 out_free_op_data:
145 	kfree(op_data);
146 out:
147 	if (rc && pmode)
148 		ldlm_lock_decref(&plock, pmode);
149 
150 	ptlrpc_req_finished(*reqp);
151 	*reqp = req;
152 	return rc;
153 }
154 
155 /*
156  * IT_OPEN is intended to open (and create, possible) an object. Parent (pid)
157  * may be split dir.
158  */
lmv_intent_open(struct obd_export * exp,struct md_op_data * op_data,void * lmm,int lmmsize,struct lookup_intent * it,int flags,struct ptlrpc_request ** reqp,ldlm_blocking_callback cb_blocking,__u64 extra_lock_flags)159 int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data,
160 		    void *lmm, int lmmsize, struct lookup_intent *it,
161 		    int flags, struct ptlrpc_request **reqp,
162 		    ldlm_blocking_callback cb_blocking,
163 		    __u64 extra_lock_flags)
164 {
165 	struct obd_device	*obd = exp->exp_obd;
166 	struct lmv_obd		*lmv = &obd->u.lmv;
167 	struct lmv_tgt_desc	*tgt;
168 	struct mdt_body		*body;
169 	int			rc;
170 
171 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
172 	if (IS_ERR(tgt))
173 		return PTR_ERR(tgt);
174 
175 	/* If it is ready to open the file by FID, do not need
176 	 * allocate FID at all, otherwise it will confuse MDT */
177 	if ((it->it_op & IT_CREAT) &&
178 	    !(it->it_flags & MDS_OPEN_BY_FID)) {
179 		/*
180 		 * For open with IT_CREATE and for IT_CREATE cases allocate new
181 		 * fid and setup FLD for it.
182 		 */
183 		op_data->op_fid3 = op_data->op_fid2;
184 		rc = lmv_fid_alloc(exp, &op_data->op_fid2, op_data);
185 		if (rc != 0)
186 			return rc;
187 	}
188 
189 	CDEBUG(D_INODE, "OPEN_INTENT with fid1=" DFID ", fid2=" DFID ", name='%s' -> mds #%d\n",
190 	       PFID(&op_data->op_fid1),
191 	       PFID(&op_data->op_fid2), op_data->op_name, tgt->ltd_idx);
192 
193 	rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, flags,
194 			    reqp, cb_blocking, extra_lock_flags);
195 	if (rc != 0)
196 		return rc;
197 	/*
198 	 * Nothing is found, do not access body->fid1 as it is zero and thus
199 	 * pointless.
200 	 */
201 	if ((it->d.lustre.it_disposition & DISP_LOOKUP_NEG) &&
202 	    !(it->d.lustre.it_disposition & DISP_OPEN_CREATE) &&
203 	    !(it->d.lustre.it_disposition & DISP_OPEN_OPEN))
204 		return rc;
205 
206 	body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
207 	if (body == NULL)
208 		return -EPROTO;
209 	/*
210 	 * Not cross-ref case, just get out of here.
211 	 */
212 	if (likely(!(body->valid & OBD_MD_MDS)))
213 		return 0;
214 
215 	/*
216 	 * Okay, MDS has returned success. Probably name has been resolved in
217 	 * remote inode.
218 	 */
219 	rc = lmv_intent_remote(exp, lmm, lmmsize, it, &op_data->op_fid1, flags,
220 			       reqp, cb_blocking, extra_lock_flags);
221 	if (rc != 0) {
222 		LASSERT(rc < 0);
223 		/*
224 		 * This is possible, that some userspace application will try to
225 		 * open file as directory and we will have -ENOTDIR here. As
226 		 * this is normal situation, we should not print error here,
227 		 * only debug info.
228 		 */
229 		CDEBUG(D_INODE, "Can't handle remote %s: dir " DFID "(" DFID "):%*s: %d\n",
230 		       LL_IT2STR(it), PFID(&op_data->op_fid2),
231 		       PFID(&op_data->op_fid1), op_data->op_namelen,
232 		       op_data->op_name, rc);
233 		return rc;
234 	}
235 
236 	return rc;
237 }
238 
239 /*
240  * Handler for: getattr, lookup and revalidate cases.
241  */
lmv_intent_lookup(struct obd_export * exp,struct md_op_data * op_data,void * lmm,int lmmsize,struct lookup_intent * it,int flags,struct ptlrpc_request ** reqp,ldlm_blocking_callback cb_blocking,__u64 extra_lock_flags)242 int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data,
243 		      void *lmm, int lmmsize, struct lookup_intent *it,
244 		      int flags, struct ptlrpc_request **reqp,
245 		      ldlm_blocking_callback cb_blocking,
246 		      __u64 extra_lock_flags)
247 {
248 	struct obd_device      *obd = exp->exp_obd;
249 	struct lmv_obd	 *lmv = &obd->u.lmv;
250 	struct lmv_tgt_desc    *tgt = NULL;
251 	struct mdt_body	*body;
252 	int		     rc = 0;
253 
254 	tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1);
255 	if (IS_ERR(tgt))
256 		return PTR_ERR(tgt);
257 
258 	if (!fid_is_sane(&op_data->op_fid2))
259 		fid_zero(&op_data->op_fid2);
260 
261 	CDEBUG(D_INODE, "LOOKUP_INTENT with fid1="DFID", fid2="DFID
262 	       ", name='%s' -> mds #%d\n", PFID(&op_data->op_fid1),
263 	       PFID(&op_data->op_fid2),
264 	       op_data->op_name ? op_data->op_name : "<NULL>",
265 	       tgt->ltd_idx);
266 
267 	op_data->op_bias &= ~MDS_CROSS_REF;
268 
269 	rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it,
270 			     flags, reqp, cb_blocking, extra_lock_flags);
271 
272 	if (rc < 0 || *reqp == NULL)
273 		return rc;
274 
275 	/*
276 	 * MDS has returned success. Probably name has been resolved in
277 	 * remote inode. Let's check this.
278 	 */
279 	body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY);
280 	if (body == NULL)
281 		return -EPROTO;
282 	/* Not cross-ref case, just get out of here. */
283 	if (likely(!(body->valid & OBD_MD_MDS)))
284 		return 0;
285 
286 	rc = lmv_intent_remote(exp, lmm, lmmsize, it, NULL, flags, reqp,
287 			       cb_blocking, extra_lock_flags);
288 
289 	return rc;
290 }
291 
lmv_intent_lock(struct obd_export * exp,struct md_op_data * op_data,void * lmm,int lmmsize,struct lookup_intent * it,int flags,struct ptlrpc_request ** reqp,ldlm_blocking_callback cb_blocking,__u64 extra_lock_flags)292 int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data,
293 		    void *lmm, int lmmsize, struct lookup_intent *it,
294 		    int flags, struct ptlrpc_request **reqp,
295 		    ldlm_blocking_callback cb_blocking,
296 		    __u64 extra_lock_flags)
297 {
298 	struct obd_device *obd = exp->exp_obd;
299 	int		rc;
300 
301 	LASSERT(it != NULL);
302 	LASSERT(fid_is_sane(&op_data->op_fid1));
303 
304 	CDEBUG(D_INODE, "INTENT LOCK '%s' for '%*s' on "DFID"\n",
305 	       LL_IT2STR(it), op_data->op_namelen, op_data->op_name,
306 	       PFID(&op_data->op_fid1));
307 
308 	rc = lmv_check_connect(obd);
309 	if (rc)
310 		return rc;
311 
312 	if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_LAYOUT))
313 		rc = lmv_intent_lookup(exp, op_data, lmm, lmmsize, it,
314 				       flags, reqp, cb_blocking,
315 				       extra_lock_flags);
316 	else if (it->it_op & IT_OPEN)
317 		rc = lmv_intent_open(exp, op_data, lmm, lmmsize, it,
318 				     flags, reqp, cb_blocking,
319 				     extra_lock_flags);
320 	else
321 		LBUG();
322 	return rc;
323 }
324