Commit | Line | Data |
---|---|---|
d7e09d03 PT |
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> | |
d7e09d03 PT |
40 | #include <linux/pagemap.h> |
41 | #include <asm/div64.h> | |
42 | #include <linux/seq_file.h> | |
43 | #include <linux/namei.h> | |
44 | #include <linux/lustre_intent.h> | |
45 | ||
46 | #include <obd_support.h> | |
47 | #include <lustre/lustre_idl.h> | |
48 | #include <lustre_lib.h> | |
49 | #include <lustre_net.h> | |
50 | #include <lustre_dlm.h> | |
51 | #include <obd_class.h> | |
52 | #include <lprocfs_status.h> | |
53 | #include "lmv_internal.h" | |
54 | ||
55 | static int lmv_intent_remote(struct obd_export *exp, void *lmm, | |
56 | int lmmsize, struct lookup_intent *it, | |
57 | const struct lu_fid *parent_fid, int flags, | |
58 | struct ptlrpc_request **reqp, | |
59 | ldlm_blocking_callback cb_blocking, | |
60 | __u64 extra_lock_flags) | |
61 | { | |
62 | struct obd_device *obd = exp->exp_obd; | |
63 | struct lmv_obd *lmv = &obd->u.lmv; | |
64 | struct ptlrpc_request *req = NULL; | |
65 | struct lustre_handle plock; | |
66 | struct md_op_data *op_data; | |
67 | struct lmv_tgt_desc *tgt; | |
68 | struct mdt_body *body; | |
69 | int pmode; | |
70 | int rc = 0; | |
d7e09d03 PT |
71 | |
72 | body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY); | |
73 | if (body == NULL) | |
0a3bdb00 | 74 | return -EPROTO; |
d7e09d03 PT |
75 | |
76 | LASSERT((body->valid & OBD_MD_MDS)); | |
77 | ||
78 | /* | |
79 | * Unfortunately, we have to lie to MDC/MDS to retrieve | |
80 | * attributes llite needs and provideproper locking. | |
81 | */ | |
82 | if (it->it_op & IT_LOOKUP) | |
83 | it->it_op = IT_GETATTR; | |
84 | ||
85 | /* | |
86 | * We got LOOKUP lock, but we really need attrs. | |
87 | */ | |
88 | pmode = it->d.lustre.it_lock_mode; | |
89 | if (pmode) { | |
90 | plock.cookie = it->d.lustre.it_lock_handle; | |
91 | it->d.lustre.it_lock_mode = 0; | |
92 | it->d.lustre.it_data = NULL; | |
93 | } | |
94 | ||
95 | LASSERT(fid_is_sane(&body->fid1)); | |
96 | ||
97 | tgt = lmv_find_target(lmv, &body->fid1); | |
98 | if (IS_ERR(tgt)) | |
99 | GOTO(out, rc = PTR_ERR(tgt)); | |
100 | ||
101 | OBD_ALLOC_PTR(op_data); | |
102 | if (op_data == NULL) | |
103 | GOTO(out, rc = -ENOMEM); | |
104 | ||
105 | op_data->op_fid1 = body->fid1; | |
106 | /* Sent the parent FID to the remote MDT */ | |
107 | if (parent_fid != NULL) { | |
108 | /* The parent fid is only for remote open to | |
109 | * check whether the open is from OBF, | |
110 | * see mdt_cross_open */ | |
111 | LASSERT(it->it_op & IT_OPEN); | |
112 | op_data->op_fid2 = *parent_fid; | |
113 | /* Add object FID to op_fid3, in case it needs to check stale | |
114 | * (M_CHECK_STALE), see mdc_finish_intent_lock */ | |
115 | op_data->op_fid3 = body->fid1; | |
116 | } | |
117 | ||
118 | op_data->op_bias = MDS_CROSS_REF; | |
119 | CDEBUG(D_INODE, "REMOTE_INTENT with fid="DFID" -> mds #%d\n", | |
120 | PFID(&body->fid1), tgt->ltd_idx); | |
121 | ||
122 | it->d.lustre.it_disposition &= ~DISP_ENQ_COMPLETE; | |
123 | rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, | |
124 | flags, &req, cb_blocking, extra_lock_flags); | |
125 | if (rc) | |
126 | GOTO(out_free_op_data, rc); | |
127 | ||
128 | /* | |
129 | * LLite needs LOOKUP lock to track dentry revocation in order to | |
130 | * maintain dcache consistency. Thus drop UPDATE|PERM lock here | |
131 | * and put LOOKUP in request. | |
132 | */ | |
133 | if (it->d.lustre.it_lock_mode != 0) { | |
134 | it->d.lustre.it_remote_lock_handle = | |
135 | it->d.lustre.it_lock_handle; | |
136 | it->d.lustre.it_remote_lock_mode = it->d.lustre.it_lock_mode; | |
137 | } | |
138 | ||
139 | it->d.lustre.it_lock_handle = plock.cookie; | |
140 | it->d.lustre.it_lock_mode = pmode; | |
141 | ||
d7e09d03 PT |
142 | out_free_op_data: |
143 | OBD_FREE_PTR(op_data); | |
144 | out: | |
145 | if (rc && pmode) | |
146 | ldlm_lock_decref(&plock, pmode); | |
147 | ||
148 | ptlrpc_req_finished(*reqp); | |
149 | *reqp = req; | |
150 | return rc; | |
151 | } | |
152 | ||
153 | /* | |
154 | * IT_OPEN is intended to open (and create, possible) an object. Parent (pid) | |
155 | * may be split dir. | |
156 | */ | |
157 | int lmv_intent_open(struct obd_export *exp, struct md_op_data *op_data, | |
158 | void *lmm, int lmmsize, struct lookup_intent *it, | |
159 | int flags, struct ptlrpc_request **reqp, | |
160 | ldlm_blocking_callback cb_blocking, | |
161 | __u64 extra_lock_flags) | |
162 | { | |
163 | struct obd_device *obd = exp->exp_obd; | |
164 | struct lmv_obd *lmv = &obd->u.lmv; | |
165 | struct lmv_tgt_desc *tgt; | |
166 | struct mdt_body *body; | |
167 | int rc; | |
d7e09d03 PT |
168 | |
169 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); | |
170 | if (IS_ERR(tgt)) | |
0a3bdb00 | 171 | return PTR_ERR(tgt); |
d7e09d03 PT |
172 | |
173 | /* If it is ready to open the file by FID, do not need | |
174 | * allocate FID at all, otherwise it will confuse MDT */ | |
175 | if ((it->it_op & IT_CREAT) && | |
176 | !(it->it_flags & MDS_OPEN_BY_FID)) { | |
177 | /* | |
178 | * For open with IT_CREATE and for IT_CREATE cases allocate new | |
179 | * fid and setup FLD for it. | |
180 | */ | |
181 | op_data->op_fid3 = op_data->op_fid2; | |
182 | rc = lmv_fid_alloc(exp, &op_data->op_fid2, op_data); | |
183 | if (rc != 0) | |
0a3bdb00 | 184 | return rc; |
d7e09d03 PT |
185 | } |
186 | ||
187 | CDEBUG(D_INODE, "OPEN_INTENT with fid1="DFID", fid2="DFID"," | |
188 | " name='%s' -> mds #%d\n", PFID(&op_data->op_fid1), | |
189 | PFID(&op_data->op_fid2), op_data->op_name, tgt->ltd_idx); | |
190 | ||
191 | rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, flags, | |
192 | reqp, cb_blocking, extra_lock_flags); | |
193 | if (rc != 0) | |
0a3bdb00 | 194 | return rc; |
d7e09d03 PT |
195 | /* |
196 | * Nothing is found, do not access body->fid1 as it is zero and thus | |
197 | * pointless. | |
198 | */ | |
199 | if ((it->d.lustre.it_disposition & DISP_LOOKUP_NEG) && | |
200 | !(it->d.lustre.it_disposition & DISP_OPEN_CREATE) && | |
201 | !(it->d.lustre.it_disposition & DISP_OPEN_OPEN)) | |
0a3bdb00 | 202 | return rc; |
d7e09d03 PT |
203 | |
204 | body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY); | |
205 | if (body == NULL) | |
0a3bdb00 | 206 | return -EPROTO; |
d7e09d03 PT |
207 | /* |
208 | * Not cross-ref case, just get out of here. | |
209 | */ | |
210 | if (likely(!(body->valid & OBD_MD_MDS))) | |
0a3bdb00 | 211 | return 0; |
d7e09d03 PT |
212 | |
213 | /* | |
214 | * Okay, MDS has returned success. Probably name has been resolved in | |
215 | * remote inode. | |
216 | */ | |
217 | rc = lmv_intent_remote(exp, lmm, lmmsize, it, &op_data->op_fid1, flags, | |
218 | reqp, cb_blocking, extra_lock_flags); | |
219 | if (rc != 0) { | |
220 | LASSERT(rc < 0); | |
221 | /* | |
222 | * This is possible, that some userspace application will try to | |
223 | * open file as directory and we will have -ENOTDIR here. As | |
224 | * this is normal situation, we should not print error here, | |
225 | * only debug info. | |
226 | */ | |
227 | CDEBUG(D_INODE, "Can't handle remote %s: dir "DFID"("DFID"):" | |
228 | "%*s: %d\n", LL_IT2STR(it), PFID(&op_data->op_fid2), | |
229 | PFID(&op_data->op_fid1), op_data->op_namelen, | |
230 | op_data->op_name, rc); | |
0a3bdb00 | 231 | return rc; |
d7e09d03 PT |
232 | } |
233 | ||
0a3bdb00 | 234 | return rc; |
d7e09d03 PT |
235 | } |
236 | ||
237 | /* | |
238 | * Handler for: getattr, lookup and revalidate cases. | |
239 | */ | |
240 | int lmv_intent_lookup(struct obd_export *exp, struct md_op_data *op_data, | |
241 | void *lmm, int lmmsize, struct lookup_intent *it, | |
242 | int flags, struct ptlrpc_request **reqp, | |
243 | ldlm_blocking_callback cb_blocking, | |
244 | __u64 extra_lock_flags) | |
245 | { | |
246 | struct obd_device *obd = exp->exp_obd; | |
247 | struct lmv_obd *lmv = &obd->u.lmv; | |
248 | struct lmv_tgt_desc *tgt = NULL; | |
249 | struct mdt_body *body; | |
250 | int rc = 0; | |
d7e09d03 PT |
251 | |
252 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); | |
253 | if (IS_ERR(tgt)) | |
0a3bdb00 | 254 | return PTR_ERR(tgt); |
d7e09d03 PT |
255 | |
256 | if (!fid_is_sane(&op_data->op_fid2)) | |
257 | fid_zero(&op_data->op_fid2); | |
258 | ||
259 | CDEBUG(D_INODE, "LOOKUP_INTENT with fid1="DFID", fid2="DFID | |
260 | ", name='%s' -> mds #%d\n", PFID(&op_data->op_fid1), | |
261 | PFID(&op_data->op_fid2), | |
262 | op_data->op_name ? op_data->op_name : "<NULL>", | |
263 | tgt->ltd_idx); | |
264 | ||
265 | op_data->op_bias &= ~MDS_CROSS_REF; | |
266 | ||
267 | rc = md_intent_lock(tgt->ltd_exp, op_data, lmm, lmmsize, it, | |
268 | flags, reqp, cb_blocking, extra_lock_flags); | |
269 | ||
270 | if (rc < 0 || *reqp == NULL) | |
0a3bdb00 | 271 | return rc; |
d7e09d03 PT |
272 | |
273 | /* | |
274 | * MDS has returned success. Probably name has been resolved in | |
275 | * remote inode. Let's check this. | |
276 | */ | |
277 | body = req_capsule_server_get(&(*reqp)->rq_pill, &RMF_MDT_BODY); | |
278 | if (body == NULL) | |
0a3bdb00 | 279 | return -EPROTO; |
d7e09d03 PT |
280 | /* Not cross-ref case, just get out of here. */ |
281 | if (likely(!(body->valid & OBD_MD_MDS))) | |
0a3bdb00 | 282 | return 0; |
d7e09d03 PT |
283 | |
284 | rc = lmv_intent_remote(exp, lmm, lmmsize, it, NULL, flags, reqp, | |
285 | cb_blocking, extra_lock_flags); | |
286 | ||
0a3bdb00 | 287 | return rc; |
d7e09d03 PT |
288 | } |
289 | ||
290 | int lmv_intent_lock(struct obd_export *exp, struct md_op_data *op_data, | |
291 | void *lmm, int lmmsize, struct lookup_intent *it, | |
292 | int flags, struct ptlrpc_request **reqp, | |
293 | ldlm_blocking_callback cb_blocking, | |
294 | __u64 extra_lock_flags) | |
295 | { | |
296 | struct obd_device *obd = exp->exp_obd; | |
297 | int rc; | |
d7e09d03 PT |
298 | |
299 | LASSERT(it != NULL); | |
300 | LASSERT(fid_is_sane(&op_data->op_fid1)); | |
301 | ||
302 | CDEBUG(D_INODE, "INTENT LOCK '%s' for '%*s' on "DFID"\n", | |
303 | LL_IT2STR(it), op_data->op_namelen, op_data->op_name, | |
304 | PFID(&op_data->op_fid1)); | |
305 | ||
306 | rc = lmv_check_connect(obd); | |
307 | if (rc) | |
0a3bdb00 | 308 | return rc; |
d7e09d03 PT |
309 | |
310 | if (it->it_op & (IT_LOOKUP | IT_GETATTR | IT_LAYOUT)) | |
311 | rc = lmv_intent_lookup(exp, op_data, lmm, lmmsize, it, | |
312 | flags, reqp, cb_blocking, | |
313 | extra_lock_flags); | |
314 | else if (it->it_op & IT_OPEN) | |
315 | rc = lmv_intent_open(exp, op_data, lmm, lmmsize, it, | |
316 | flags, reqp, cb_blocking, | |
317 | extra_lock_flags); | |
318 | else | |
319 | LBUG(); | |
0a3bdb00 | 320 | return rc; |
d7e09d03 | 321 | } |