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 | |
6a5b99a4 | 18 | * http://www.gnu.org/licenses/gpl-2.0.html |
d7e09d03 | 19 | * |
d7e09d03 PT |
20 | * GPL HEADER END |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. | |
24 | * Use is subject to license terms. | |
25 | * | |
1dc563a6 | 26 | * Copyright (c) 2011, 2015, Intel Corporation. |
d7e09d03 PT |
27 | */ |
28 | /* | |
29 | * This file is part of Lustre, http://www.lustre.org/ | |
30 | * Lustre is a trademark of Sun Microsystems, Inc. | |
31 | */ | |
32 | ||
33 | #define DEBUG_SUBSYSTEM S_LMV | |
34 | #include <linux/slab.h> | |
35 | #include <linux/module.h> | |
36 | #include <linux/init.h> | |
d7e09d03 PT |
37 | #include <linux/pagemap.h> |
38 | #include <linux/mm.h> | |
39 | #include <asm/div64.h> | |
40 | #include <linux/seq_file.h> | |
41 | #include <linux/namei.h> | |
e8fd99fd | 42 | #include <linux/uaccess.h> |
d7e09d03 | 43 | |
a8c495ac GKH |
44 | #include "../include/lustre/lustre_idl.h" |
45 | #include "../include/obd_support.h" | |
46 | #include "../include/lustre_lib.h" | |
47 | #include "../include/lustre_net.h" | |
48 | #include "../include/obd_class.h" | |
8e9dfe8a | 49 | #include "../include/lustre_lmv.h" |
a8c495ac | 50 | #include "../include/lprocfs_status.h" |
2de35386 | 51 | #include "../include/cl_object.h" |
a8c495ac GKH |
52 | #include "../include/lustre_lite.h" |
53 | #include "../include/lustre_fid.h" | |
8877d3bf | 54 | #include "../include/lustre/lustre_ioctl.h" |
e2780478 | 55 | #include "../include/lustre_kernelcomm.h" |
d7e09d03 PT |
56 | #include "lmv_internal.h" |
57 | ||
2de35386 | 58 | /* This hash is only for testing purpose */ |
59 | static inline unsigned int | |
60 | lmv_hash_all_chars(unsigned int count, const char *name, int namelen) | |
61 | { | |
62 | const unsigned char *p = (const unsigned char *)name; | |
63 | unsigned int c = 0; | |
64 | ||
65 | while (--namelen >= 0) | |
66 | c += p[namelen]; | |
67 | ||
68 | c = c % count; | |
69 | ||
70 | return c; | |
71 | } | |
72 | ||
73 | static inline unsigned int | |
74 | lmv_hash_fnv1a(unsigned int count, const char *name, int namelen) | |
75 | { | |
76 | __u64 hash; | |
77 | ||
78 | hash = lustre_hash_fnv_1a_64(name, namelen); | |
79 | ||
80 | return do_div(hash, count); | |
81 | } | |
82 | ||
8f18c8a4 | 83 | int lmv_name_to_stripe_index(__u32 lmv_hash_type, unsigned int stripe_count, |
2de35386 | 84 | const char *name, int namelen) |
85 | { | |
8f18c8a4 | 86 | __u32 hash_type = lmv_hash_type & LMV_HASH_TYPE_MASK; |
2de35386 | 87 | int idx; |
88 | ||
89 | LASSERT(namelen > 0); | |
8f18c8a4 | 90 | if (stripe_count <= 1) |
2de35386 | 91 | return 0; |
92 | ||
8f18c8a4 | 93 | /* for migrating object, always start from 0 stripe */ |
94 | if (lmv_hash_type & LMV_HASH_FLAG_MIGRATION) | |
95 | return 0; | |
96 | ||
97 | switch (hash_type) { | |
2de35386 | 98 | case LMV_HASH_TYPE_ALL_CHARS: |
8f18c8a4 | 99 | idx = lmv_hash_all_chars(stripe_count, name, namelen); |
2de35386 | 100 | break; |
101 | case LMV_HASH_TYPE_FNV_1A_64: | |
8f18c8a4 | 102 | idx = lmv_hash_fnv1a(stripe_count, name, namelen); |
2de35386 | 103 | break; |
104 | default: | |
893ab747 | 105 | idx = -EBADFD; |
106 | break; | |
2de35386 | 107 | } |
108 | ||
75ac62fc | 109 | CDEBUG(D_INFO, "name %.*s hash_type %d idx %d\n", namelen, name, |
8f18c8a4 | 110 | hash_type, idx); |
75ac62fc | 111 | |
2de35386 | 112 | return idx; |
113 | } | |
114 | ||
d7e09d03 PT |
115 | static void lmv_activate_target(struct lmv_obd *lmv, |
116 | struct lmv_tgt_desc *tgt, | |
117 | int activate) | |
118 | { | |
119 | if (tgt->ltd_active == activate) | |
120 | return; | |
121 | ||
122 | tgt->ltd_active = activate; | |
123 | lmv->desc.ld_active_tgt_count += (activate ? 1 : -1); | |
124 | } | |
125 | ||
126 | /** | |
127 | * Error codes: | |
128 | * | |
129 | * -EINVAL : UUID can't be found in the LMV's target list | |
130 | * -ENOTCONN: The UUID is found, but the target connection is bad (!) | |
131 | * -EBADF : The UUID is found, but the OBD of the wrong type (!) | |
132 | */ | |
a043a102 | 133 | static int lmv_set_mdc_active(struct lmv_obd *lmv, const struct obd_uuid *uuid, |
d7e09d03 PT |
134 | int activate) |
135 | { | |
73bb1da6 | 136 | struct lmv_tgt_desc *uninitialized_var(tgt); |
d7e09d03 | 137 | struct obd_device *obd; |
a043a102 | 138 | u32 i; |
d7e09d03 | 139 | int rc = 0; |
d7e09d03 PT |
140 | |
141 | CDEBUG(D_INFO, "Searching in lmv %p for uuid %s (activate=%d)\n", | |
142 | lmv, uuid->uuid, activate); | |
143 | ||
144 | spin_lock(&lmv->lmv_lock); | |
145 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
146 | tgt = lmv->tgts[i]; | |
2cbdaa45 | 147 | if (!tgt || !tgt->ltd_exp) |
d7e09d03 PT |
148 | continue; |
149 | ||
55f5a824 | 150 | CDEBUG(D_INFO, "Target idx %d is %s conn %#llx\n", i, |
d7e09d03 PT |
151 | tgt->ltd_uuid.uuid, tgt->ltd_exp->exp_handle.h_cookie); |
152 | ||
153 | if (obd_uuid_equals(uuid, &tgt->ltd_uuid)) | |
154 | break; | |
155 | } | |
156 | ||
4d54556f JL |
157 | if (i == lmv->desc.ld_tgt_count) { |
158 | rc = -EINVAL; | |
159 | goto out_lmv_lock; | |
160 | } | |
d7e09d03 PT |
161 | |
162 | obd = class_exp2obd(tgt->ltd_exp); | |
2cbdaa45 | 163 | if (!obd) { |
4d54556f JL |
164 | rc = -ENOTCONN; |
165 | goto out_lmv_lock; | |
166 | } | |
d7e09d03 PT |
167 | |
168 | CDEBUG(D_INFO, "Found OBD %s=%s device %d (%p) type %s at LMV idx %d\n", | |
169 | obd->obd_name, obd->obd_uuid.uuid, obd->obd_minor, obd, | |
170 | obd->obd_type->typ_name, i); | |
171 | LASSERT(strcmp(obd->obd_type->typ_name, LUSTRE_MDC_NAME) == 0); | |
172 | ||
173 | if (tgt->ltd_active == activate) { | |
174 | CDEBUG(D_INFO, "OBD %p already %sactive!\n", obd, | |
175 | activate ? "" : "in"); | |
4d54556f | 176 | goto out_lmv_lock; |
d7e09d03 PT |
177 | } |
178 | ||
179 | CDEBUG(D_INFO, "Marking OBD %p %sactive\n", obd, | |
180 | activate ? "" : "in"); | |
181 | lmv_activate_target(lmv, tgt, activate); | |
d7e09d03 PT |
182 | |
183 | out_lmv_lock: | |
184 | spin_unlock(&lmv->lmv_lock); | |
185 | return rc; | |
186 | } | |
187 | ||
5dc8d7b4 | 188 | static struct obd_uuid *lmv_get_uuid(struct obd_export *exp) |
d7e09d03 PT |
189 | { |
190 | struct lmv_obd *lmv = &exp->exp_obd->u.lmv; | |
0fdd2b8d | 191 | struct lmv_tgt_desc *tgt = lmv->tgts[0]; |
d7e09d03 | 192 | |
0fdd2b8d | 193 | return tgt ? obd_get_uuid(tgt->ltd_exp) : NULL; |
d7e09d03 PT |
194 | } |
195 | ||
196 | static int lmv_notify(struct obd_device *obd, struct obd_device *watched, | |
197 | enum obd_notify_event ev, void *data) | |
198 | { | |
199 | struct obd_connect_data *conn_data; | |
200 | struct lmv_obd *lmv = &obd->u.lmv; | |
201 | struct obd_uuid *uuid; | |
202 | int rc = 0; | |
d7e09d03 PT |
203 | |
204 | if (strcmp(watched->obd_type->typ_name, LUSTRE_MDC_NAME)) { | |
205 | CERROR("unexpected notification of %s %s!\n", | |
206 | watched->obd_type->typ_name, | |
207 | watched->obd_name); | |
0a3bdb00 | 208 | return -EINVAL; |
d7e09d03 PT |
209 | } |
210 | ||
211 | uuid = &watched->u.cli.cl_target_uuid; | |
212 | if (ev == OBD_NOTIFY_ACTIVE || ev == OBD_NOTIFY_INACTIVE) { | |
213 | /* | |
214 | * Set MDC as active before notifying the observer, so the | |
215 | * observer can use the MDC normally. | |
216 | */ | |
217 | rc = lmv_set_mdc_active(lmv, uuid, | |
218 | ev == OBD_NOTIFY_ACTIVE); | |
219 | if (rc) { | |
220 | CERROR("%sactivation of %s failed: %d\n", | |
221 | ev == OBD_NOTIFY_ACTIVE ? "" : "de", | |
222 | uuid->uuid, rc); | |
0a3bdb00 | 223 | return rc; |
d7e09d03 PT |
224 | } |
225 | } else if (ev == OBD_NOTIFY_OCD) { | |
226 | conn_data = &watched->u.cli.cl_import->imp_connect_data; | |
227 | /* | |
228 | * XXX: Make sure that ocd_connect_flags from all targets are | |
229 | * the same. Otherwise one of MDTs runs wrong version or | |
230 | * something like this. --umka | |
231 | */ | |
232 | obd->obd_self_export->exp_connect_data = *conn_data; | |
233 | } | |
234 | #if 0 | |
235 | else if (ev == OBD_NOTIFY_DISCON) { | |
236 | /* | |
237 | * For disconnect event, flush fld cache for failout MDS case. | |
238 | */ | |
239 | fld_client_flush(&lmv->lmv_fld); | |
240 | } | |
241 | #endif | |
242 | /* | |
243 | * Pass the notification up the chain. | |
244 | */ | |
245 | if (obd->obd_observer) | |
246 | rc = obd_notify(obd->obd_observer, watched, ev, data); | |
247 | ||
0a3bdb00 | 248 | return rc; |
d7e09d03 PT |
249 | } |
250 | ||
251 | /** | |
252 | * This is fake connect function. Its purpose is to initialize lmv and say | |
253 | * caller that everything is okay. Real connection will be performed later. | |
254 | */ | |
255 | static int lmv_connect(const struct lu_env *env, | |
256 | struct obd_export **exp, struct obd_device *obd, | |
257 | struct obd_uuid *cluuid, struct obd_connect_data *data, | |
258 | void *localdata) | |
259 | { | |
d7e09d03 PT |
260 | struct lmv_obd *lmv = &obd->u.lmv; |
261 | struct lustre_handle conn = { 0 }; | |
262 | int rc = 0; | |
d7e09d03 PT |
263 | |
264 | /* | |
265 | * We don't want to actually do the underlying connections more than | |
266 | * once, so keep track. | |
267 | */ | |
268 | lmv->refcount++; | |
269 | if (lmv->refcount > 1) { | |
270 | *exp = NULL; | |
0a3bdb00 | 271 | return 0; |
d7e09d03 PT |
272 | } |
273 | ||
274 | rc = class_connect(&conn, obd, cluuid); | |
275 | if (rc) { | |
276 | CERROR("class_connection() returned %d\n", rc); | |
0a3bdb00 | 277 | return rc; |
d7e09d03 PT |
278 | } |
279 | ||
280 | *exp = class_conn2export(&conn); | |
281 | class_export_get(*exp); | |
282 | ||
283 | lmv->exp = *exp; | |
284 | lmv->connected = 0; | |
285 | lmv->cluuid = *cluuid; | |
286 | ||
287 | if (data) | |
288 | lmv->conn_data = *data; | |
289 | ||
b5fa70d7 OD |
290 | lmv->lmv_tgts_kobj = kobject_create_and_add("target_obds", |
291 | &obd->obd_kobj); | |
d7e09d03 PT |
292 | /* |
293 | * All real clients should perform actual connection right away, because | |
294 | * it is possible, that LMV will not have opportunity to connect targets | |
295 | * and MDC stuff will be called directly, for instance while reading | |
296 | * ../mdc/../kbytesfree procfs file, etc. | |
297 | */ | |
a739735c | 298 | if (data && data->ocd_connect_flags & OBD_CONNECT_REAL) |
d7e09d03 PT |
299 | rc = lmv_check_connect(obd); |
300 | ||
b5fa70d7 OD |
301 | if (rc && lmv->lmv_tgts_kobj) |
302 | kobject_put(lmv->lmv_tgts_kobj); | |
d7e09d03 | 303 | |
0a3bdb00 | 304 | return rc; |
d7e09d03 PT |
305 | } |
306 | ||
307 | static void lmv_set_timeouts(struct obd_device *obd) | |
308 | { | |
d7e09d03 | 309 | struct lmv_obd *lmv; |
a043a102 | 310 | u32 i; |
d7e09d03 PT |
311 | |
312 | lmv = &obd->u.lmv; | |
313 | if (lmv->server_timeout == 0) | |
314 | return; | |
315 | ||
316 | if (lmv->connected == 0) | |
317 | return; | |
318 | ||
319 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
0fdd2b8d DE |
320 | struct lmv_tgt_desc *tgt = lmv->tgts[i]; |
321 | ||
d7e09d03 | 322 | tgt = lmv->tgts[i]; |
0fdd2b8d | 323 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) |
d7e09d03 PT |
324 | continue; |
325 | ||
326 | obd_set_info_async(NULL, tgt->ltd_exp, sizeof(KEY_INTERMDS), | |
327 | KEY_INTERMDS, 0, NULL, NULL); | |
328 | } | |
329 | } | |
330 | ||
331 | static int lmv_init_ea_size(struct obd_export *exp, int easize, | |
44779340 | 332 | int def_easize, int cookiesize, int def_cookiesize) |
d7e09d03 PT |
333 | { |
334 | struct obd_device *obd = exp->exp_obd; | |
335 | struct lmv_obd *lmv = &obd->u.lmv; | |
a043a102 | 336 | u32 i; |
d7e09d03 PT |
337 | int rc = 0; |
338 | int change = 0; | |
d7e09d03 PT |
339 | |
340 | if (lmv->max_easize < easize) { | |
341 | lmv->max_easize = easize; | |
342 | change = 1; | |
343 | } | |
344 | if (lmv->max_def_easize < def_easize) { | |
345 | lmv->max_def_easize = def_easize; | |
346 | change = 1; | |
347 | } | |
348 | if (lmv->max_cookiesize < cookiesize) { | |
349 | lmv->max_cookiesize = cookiesize; | |
350 | change = 1; | |
351 | } | |
44779340 BB |
352 | if (lmv->max_def_cookiesize < def_cookiesize) { |
353 | lmv->max_def_cookiesize = def_cookiesize; | |
354 | change = 1; | |
355 | } | |
d7e09d03 | 356 | if (change == 0) |
0a3bdb00 | 357 | return 0; |
d7e09d03 PT |
358 | |
359 | if (lmv->connected == 0) | |
0a3bdb00 | 360 | return 0; |
d7e09d03 PT |
361 | |
362 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
0fdd2b8d DE |
363 | struct lmv_tgt_desc *tgt = lmv->tgts[i]; |
364 | ||
365 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) { | |
d7e09d03 PT |
366 | CWARN("%s: NULL export for %d\n", obd->obd_name, i); |
367 | continue; | |
368 | } | |
369 | ||
0fdd2b8d | 370 | rc = md_init_ea_size(tgt->ltd_exp, easize, def_easize, |
44779340 | 371 | cookiesize, def_cookiesize); |
d7e09d03 | 372 | if (rc) { |
19b2056f | 373 | CERROR("%s: obd_init_ea_size() failed on MDT target %d: rc = %d\n", |
2d00bd17 | 374 | obd->obd_name, i, rc); |
d7e09d03 PT |
375 | break; |
376 | } | |
377 | } | |
0a3bdb00 | 378 | return rc; |
d7e09d03 PT |
379 | } |
380 | ||
381 | #define MAX_STRING_SIZE 128 | |
382 | ||
5dc8d7b4 | 383 | static int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt) |
d7e09d03 | 384 | { |
d7e09d03 PT |
385 | struct lmv_obd *lmv = &obd->u.lmv; |
386 | struct obd_uuid *cluuid = &lmv->cluuid; | |
387 | struct obd_uuid lmv_mdc_uuid = { "LMV_MDC_UUID" }; | |
388 | struct obd_device *mdc_obd; | |
389 | struct obd_export *mdc_exp; | |
390 | struct lu_fld_target target; | |
391 | int rc; | |
d7e09d03 PT |
392 | |
393 | mdc_obd = class_find_client_obd(&tgt->ltd_uuid, LUSTRE_MDC_NAME, | |
394 | &obd->obd_uuid); | |
395 | if (!mdc_obd) { | |
396 | CERROR("target %s not attached\n", tgt->ltd_uuid.uuid); | |
0a3bdb00 | 397 | return -EINVAL; |
d7e09d03 PT |
398 | } |
399 | ||
400 | CDEBUG(D_CONFIG, "connect to %s(%s) - %s, %s FOR %s\n", | |
f0a87680 OD |
401 | mdc_obd->obd_name, mdc_obd->obd_uuid.uuid, |
402 | tgt->ltd_uuid.uuid, obd->obd_uuid.uuid, cluuid->uuid); | |
d7e09d03 PT |
403 | |
404 | if (!mdc_obd->obd_set_up) { | |
405 | CERROR("target %s is not set up\n", tgt->ltd_uuid.uuid); | |
0a3bdb00 | 406 | return -EINVAL; |
d7e09d03 PT |
407 | } |
408 | ||
409 | rc = obd_connect(NULL, &mdc_exp, mdc_obd, &lmv_mdc_uuid, | |
410 | &lmv->conn_data, NULL); | |
411 | if (rc) { | |
412 | CERROR("target %s connect error %d\n", tgt->ltd_uuid.uuid, rc); | |
0a3bdb00 | 413 | return rc; |
d7e09d03 PT |
414 | } |
415 | ||
416 | /* | |
417 | * Init fid sequence client for this mdc and add new fld target. | |
418 | */ | |
419 | rc = obd_fid_init(mdc_obd, mdc_exp, LUSTRE_SEQ_METADATA); | |
420 | if (rc) | |
0a3bdb00 | 421 | return rc; |
d7e09d03 PT |
422 | |
423 | target.ft_srv = NULL; | |
424 | target.ft_exp = mdc_exp; | |
425 | target.ft_idx = tgt->ltd_idx; | |
426 | ||
427 | fld_client_add_target(&lmv->lmv_fld, &target); | |
428 | ||
429 | rc = obd_register_observer(mdc_obd, obd); | |
430 | if (rc) { | |
431 | obd_disconnect(mdc_exp); | |
432 | CERROR("target %s register_observer error %d\n", | |
433 | tgt->ltd_uuid.uuid, rc); | |
0a3bdb00 | 434 | return rc; |
d7e09d03 PT |
435 | } |
436 | ||
437 | if (obd->obd_observer) { | |
438 | /* | |
439 | * Tell the observer about the new target. | |
440 | */ | |
441 | rc = obd_notify(obd->obd_observer, mdc_exp->exp_obd, | |
442 | OBD_NOTIFY_ACTIVE, | |
443 | (void *)(tgt - lmv->tgts[0])); | |
444 | if (rc) { | |
445 | obd_disconnect(mdc_exp); | |
0a3bdb00 | 446 | return rc; |
d7e09d03 PT |
447 | } |
448 | } | |
449 | ||
450 | tgt->ltd_active = 1; | |
451 | tgt->ltd_exp = mdc_exp; | |
452 | lmv->desc.ld_active_tgt_count++; | |
453 | ||
44779340 BB |
454 | md_init_ea_size(tgt->ltd_exp, lmv->max_easize, lmv->max_def_easize, |
455 | lmv->max_cookiesize, lmv->max_def_cookiesize); | |
d7e09d03 PT |
456 | |
457 | CDEBUG(D_CONFIG, "Connected to %s(%s) successfully (%d)\n", | |
f0a87680 OD |
458 | mdc_obd->obd_name, mdc_obd->obd_uuid.uuid, |
459 | atomic_read(&obd->obd_refcount)); | |
d7e09d03 | 460 | |
b5fa70d7 OD |
461 | if (lmv->lmv_tgts_kobj) |
462 | /* Even if we failed to create the link, that's fine */ | |
463 | rc = sysfs_create_link(lmv->lmv_tgts_kobj, &mdc_obd->obd_kobj, | |
464 | mdc_obd->obd_name); | |
0a3bdb00 | 465 | return 0; |
d7e09d03 PT |
466 | } |
467 | ||
468 | static void lmv_del_target(struct lmv_obd *lmv, int index) | |
469 | { | |
2cbdaa45 | 470 | if (!lmv->tgts[index]) |
d7e09d03 PT |
471 | return; |
472 | ||
8bcf30c3 | 473 | kfree(lmv->tgts[index]); |
d7e09d03 PT |
474 | lmv->tgts[index] = NULL; |
475 | return; | |
476 | } | |
477 | ||
478 | static int lmv_add_target(struct obd_device *obd, struct obd_uuid *uuidp, | |
f0a87680 | 479 | __u32 index, int gen) |
d7e09d03 PT |
480 | { |
481 | struct lmv_obd *lmv = &obd->u.lmv; | |
482 | struct lmv_tgt_desc *tgt; | |
711942df | 483 | int orig_tgt_count = 0; |
d7e09d03 | 484 | int rc = 0; |
d7e09d03 PT |
485 | |
486 | CDEBUG(D_CONFIG, "Target uuid: %s. index %d\n", uuidp->uuid, index); | |
487 | ||
019e9351 | 488 | mutex_lock(&lmv->lmv_init_mutex); |
d7e09d03 PT |
489 | |
490 | if (lmv->desc.ld_tgt_count == 0) { | |
491 | struct obd_device *mdc_obd; | |
492 | ||
493 | mdc_obd = class_find_client_obd(uuidp, LUSTRE_MDC_NAME, | |
494 | &obd->obd_uuid); | |
495 | if (!mdc_obd) { | |
019e9351 | 496 | mutex_unlock(&lmv->lmv_init_mutex); |
d7e09d03 PT |
497 | CERROR("%s: Target %s not attached: rc = %d\n", |
498 | obd->obd_name, uuidp->uuid, -EINVAL); | |
0a3bdb00 | 499 | return -EINVAL; |
d7e09d03 PT |
500 | } |
501 | } | |
502 | ||
2cbdaa45 | 503 | if ((index < lmv->tgts_size) && lmv->tgts[index]) { |
d7e09d03 | 504 | tgt = lmv->tgts[index]; |
2d00bd17 JP |
505 | CERROR("%s: UUID %s already assigned at LOV target index %d: rc = %d\n", |
506 | obd->obd_name, | |
d7e09d03 | 507 | obd_uuid2str(&tgt->ltd_uuid), index, -EEXIST); |
019e9351 | 508 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 509 | return -EEXIST; |
d7e09d03 PT |
510 | } |
511 | ||
512 | if (index >= lmv->tgts_size) { | |
513 | /* We need to reallocate the lmv target array. */ | |
514 | struct lmv_tgt_desc **newtgts, **old = NULL; | |
515 | __u32 newsize = 1; | |
516 | __u32 oldsize = 0; | |
517 | ||
518 | while (newsize < index + 1) | |
302727b6 | 519 | newsize <<= 1; |
8bcf30c3 | 520 | newtgts = kcalloc(newsize, sizeof(*newtgts), GFP_NOFS); |
2cbdaa45 | 521 | if (!newtgts) { |
019e9351 | 522 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 523 | return -ENOMEM; |
d7e09d03 PT |
524 | } |
525 | ||
526 | if (lmv->tgts_size) { | |
527 | memcpy(newtgts, lmv->tgts, | |
528 | sizeof(*newtgts) * lmv->tgts_size); | |
529 | old = lmv->tgts; | |
530 | oldsize = lmv->tgts_size; | |
531 | } | |
532 | ||
533 | lmv->tgts = newtgts; | |
534 | lmv->tgts_size = newsize; | |
535 | smp_rmb(); | |
13879e5d | 536 | kfree(old); |
d7e09d03 PT |
537 | |
538 | CDEBUG(D_CONFIG, "tgts: %p size: %d\n", lmv->tgts, | |
539 | lmv->tgts_size); | |
540 | } | |
541 | ||
8bcf30c3 | 542 | tgt = kzalloc(sizeof(*tgt), GFP_NOFS); |
d7e09d03 | 543 | if (!tgt) { |
019e9351 | 544 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 545 | return -ENOMEM; |
d7e09d03 PT |
546 | } |
547 | ||
548 | mutex_init(&tgt->ltd_fid_mutex); | |
549 | tgt->ltd_idx = index; | |
550 | tgt->ltd_uuid = *uuidp; | |
551 | tgt->ltd_active = 0; | |
552 | lmv->tgts[index] = tgt; | |
711942df | 553 | if (index >= lmv->desc.ld_tgt_count) { |
554 | orig_tgt_count = lmv->desc.ld_tgt_count; | |
d7e09d03 | 555 | lmv->desc.ld_tgt_count = index + 1; |
711942df | 556 | } |
d7e09d03 PT |
557 | |
558 | if (lmv->connected) { | |
559 | rc = lmv_connect_mdc(obd, tgt); | |
560 | if (rc) { | |
561 | spin_lock(&lmv->lmv_lock); | |
711942df | 562 | if (lmv->desc.ld_tgt_count == index + 1) |
563 | lmv->desc.ld_tgt_count = orig_tgt_count; | |
d7e09d03 PT |
564 | memset(tgt, 0, sizeof(*tgt)); |
565 | spin_unlock(&lmv->lmv_lock); | |
566 | } else { | |
567 | int easize = sizeof(struct lmv_stripe_md) + | |
44779340 BB |
568 | lmv->desc.ld_tgt_count * sizeof(struct lu_fid); |
569 | lmv_init_ea_size(obd->obd_self_export, easize, 0, 0, 0); | |
d7e09d03 PT |
570 | } |
571 | } | |
572 | ||
019e9351 | 573 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 574 | return rc; |
d7e09d03 PT |
575 | } |
576 | ||
577 | int lmv_check_connect(struct obd_device *obd) | |
578 | { | |
579 | struct lmv_obd *lmv = &obd->u.lmv; | |
580 | struct lmv_tgt_desc *tgt; | |
a043a102 | 581 | u32 i; |
d7e09d03 PT |
582 | int rc; |
583 | int easize; | |
d7e09d03 PT |
584 | |
585 | if (lmv->connected) | |
0a3bdb00 | 586 | return 0; |
d7e09d03 | 587 | |
019e9351 | 588 | mutex_lock(&lmv->lmv_init_mutex); |
d7e09d03 | 589 | if (lmv->connected) { |
019e9351 | 590 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 591 | return 0; |
d7e09d03 PT |
592 | } |
593 | ||
594 | if (lmv->desc.ld_tgt_count == 0) { | |
019e9351 | 595 | mutex_unlock(&lmv->lmv_init_mutex); |
d7e09d03 | 596 | CERROR("%s: no targets configured.\n", obd->obd_name); |
0a3bdb00 | 597 | return -EINVAL; |
d7e09d03 PT |
598 | } |
599 | ||
0fdd2b8d DE |
600 | LASSERT(lmv->tgts); |
601 | ||
602 | if (!lmv->tgts[0]) { | |
603 | mutex_unlock(&lmv->lmv_init_mutex); | |
604 | CERROR("%s: no target configured for index 0.\n", | |
605 | obd->obd_name); | |
606 | return -EINVAL; | |
607 | } | |
608 | ||
d7e09d03 PT |
609 | CDEBUG(D_CONFIG, "Time to connect %s to %s\n", |
610 | lmv->cluuid.uuid, obd->obd_name); | |
611 | ||
d7e09d03 PT |
612 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { |
613 | tgt = lmv->tgts[i]; | |
2cbdaa45 | 614 | if (!tgt) |
d7e09d03 PT |
615 | continue; |
616 | rc = lmv_connect_mdc(obd, tgt); | |
617 | if (rc) | |
4d54556f | 618 | goto out_disc; |
d7e09d03 PT |
619 | } |
620 | ||
621 | lmv_set_timeouts(obd); | |
622 | class_export_put(lmv->exp); | |
623 | lmv->connected = 1; | |
0bc6f19e | 624 | easize = lmv_mds_md_size(lmv->desc.ld_tgt_count, LMV_MAGIC); |
44779340 | 625 | lmv_init_ea_size(obd->obd_self_export, easize, 0, 0, 0); |
019e9351 | 626 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 627 | return 0; |
d7e09d03 PT |
628 | |
629 | out_disc: | |
630 | while (i-- > 0) { | |
631 | int rc2; | |
50ffcb7e | 632 | |
d7e09d03 | 633 | tgt = lmv->tgts[i]; |
2cbdaa45 | 634 | if (!tgt) |
d7e09d03 PT |
635 | continue; |
636 | tgt->ltd_active = 0; | |
637 | if (tgt->ltd_exp) { | |
638 | --lmv->desc.ld_active_tgt_count; | |
639 | rc2 = obd_disconnect(tgt->ltd_exp); | |
640 | if (rc2) { | |
2d00bd17 | 641 | CERROR("LMV target %s disconnect on MDC idx %d: error %d\n", |
d7e09d03 PT |
642 | tgt->ltd_uuid.uuid, i, rc2); |
643 | } | |
644 | } | |
645 | } | |
646 | class_disconnect(lmv->exp); | |
019e9351 | 647 | mutex_unlock(&lmv->lmv_init_mutex); |
0a3bdb00 | 648 | return rc; |
d7e09d03 PT |
649 | } |
650 | ||
651 | static int lmv_disconnect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt) | |
652 | { | |
d7e09d03 PT |
653 | struct lmv_obd *lmv = &obd->u.lmv; |
654 | struct obd_device *mdc_obd; | |
655 | int rc; | |
d7e09d03 | 656 | |
d7e09d03 PT |
657 | mdc_obd = class_exp2obd(tgt->ltd_exp); |
658 | ||
659 | if (mdc_obd) { | |
660 | mdc_obd->obd_force = obd->obd_force; | |
661 | mdc_obd->obd_fail = obd->obd_fail; | |
662 | mdc_obd->obd_no_recov = obd->obd_no_recov; | |
d7e09d03 | 663 | |
ced41eba OD |
664 | if (lmv->lmv_tgts_kobj) |
665 | sysfs_remove_link(lmv->lmv_tgts_kobj, | |
666 | mdc_obd->obd_name); | |
667 | } | |
d7e09d03 | 668 | |
d7e09d03 PT |
669 | rc = obd_fid_fini(tgt->ltd_exp->exp_obd); |
670 | if (rc) | |
b64767de | 671 | CERROR("Can't finalize fids factory\n"); |
d7e09d03 PT |
672 | |
673 | CDEBUG(D_INFO, "Disconnected from %s(%s) successfully\n", | |
674 | tgt->ltd_exp->exp_obd->obd_name, | |
675 | tgt->ltd_exp->exp_obd->obd_uuid.uuid); | |
676 | ||
677 | obd_register_observer(tgt->ltd_exp->exp_obd, NULL); | |
678 | rc = obd_disconnect(tgt->ltd_exp); | |
679 | if (rc) { | |
680 | if (tgt->ltd_active) { | |
681 | CERROR("Target %s disconnect error %d\n", | |
682 | tgt->ltd_uuid.uuid, rc); | |
683 | } | |
684 | } | |
685 | ||
686 | lmv_activate_target(lmv, tgt, 0); | |
687 | tgt->ltd_exp = NULL; | |
0a3bdb00 | 688 | return 0; |
d7e09d03 PT |
689 | } |
690 | ||
691 | static int lmv_disconnect(struct obd_export *exp) | |
692 | { | |
693 | struct obd_device *obd = class_exp2obd(exp); | |
d7e09d03 PT |
694 | struct lmv_obd *lmv = &obd->u.lmv; |
695 | int rc; | |
a043a102 | 696 | u32 i; |
d7e09d03 PT |
697 | |
698 | if (!lmv->tgts) | |
699 | goto out_local; | |
700 | ||
701 | /* | |
702 | * Only disconnect the underlying layers on the final disconnect. | |
703 | */ | |
704 | lmv->refcount--; | |
705 | if (lmv->refcount != 0) | |
706 | goto out_local; | |
707 | ||
708 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
2cbdaa45 | 709 | if (!lmv->tgts[i] || !lmv->tgts[i]->ltd_exp) |
d7e09d03 PT |
710 | continue; |
711 | ||
712 | lmv_disconnect_mdc(obd, lmv->tgts[i]); | |
713 | } | |
714 | ||
b5fa70d7 OD |
715 | if (lmv->lmv_tgts_kobj) |
716 | kobject_put(lmv->lmv_tgts_kobj); | |
d7e09d03 PT |
717 | |
718 | out_local: | |
719 | /* | |
720 | * This is the case when no real connection is established by | |
721 | * lmv_check_connect(). | |
722 | */ | |
723 | if (!lmv->connected) | |
724 | class_export_put(exp); | |
725 | rc = class_disconnect(exp); | |
726 | if (lmv->refcount == 0) | |
727 | lmv->connected = 0; | |
0a3bdb00 | 728 | return rc; |
d7e09d03 PT |
729 | } |
730 | ||
0f881d7b OD |
731 | static int lmv_fid2path(struct obd_export *exp, int len, void *karg, |
732 | void __user *uarg) | |
d7e09d03 PT |
733 | { |
734 | struct obd_device *obddev = class_exp2obd(exp); | |
735 | struct lmv_obd *lmv = &obddev->u.lmv; | |
736 | struct getinfo_fid2path *gf; | |
737 | struct lmv_tgt_desc *tgt; | |
738 | struct getinfo_fid2path *remote_gf = NULL; | |
739 | int remote_gf_size = 0; | |
740 | int rc; | |
741 | ||
742 | gf = (struct getinfo_fid2path *)karg; | |
743 | tgt = lmv_find_target(lmv, &gf->gf_fid); | |
744 | if (IS_ERR(tgt)) | |
0a3bdb00 | 745 | return PTR_ERR(tgt); |
d7e09d03 PT |
746 | |
747 | repeat_fid2path: | |
748 | rc = obd_iocontrol(OBD_IOC_FID2PATH, tgt->ltd_exp, len, gf, uarg); | |
749 | if (rc != 0 && rc != -EREMOTE) | |
4d54556f | 750 | goto out_fid2path; |
d7e09d03 PT |
751 | |
752 | /* If remote_gf != NULL, it means just building the | |
7f05d5bb OD |
753 | * path on the remote MDT, copy this path segment to gf |
754 | */ | |
2cbdaa45 | 755 | if (remote_gf) { |
d7e09d03 PT |
756 | struct getinfo_fid2path *ori_gf; |
757 | char *ptr; | |
758 | ||
759 | ori_gf = (struct getinfo_fid2path *)karg; | |
760 | if (strlen(ori_gf->gf_path) + | |
4d54556f JL |
761 | strlen(gf->gf_path) > ori_gf->gf_pathlen) { |
762 | rc = -EOVERFLOW; | |
763 | goto out_fid2path; | |
764 | } | |
d7e09d03 PT |
765 | |
766 | ptr = ori_gf->gf_path; | |
767 | ||
768 | memmove(ptr + strlen(gf->gf_path) + 1, ptr, | |
769 | strlen(ori_gf->gf_path)); | |
770 | ||
771 | strncpy(ptr, gf->gf_path, strlen(gf->gf_path)); | |
772 | ptr += strlen(gf->gf_path); | |
773 | *ptr = '/'; | |
774 | } | |
775 | ||
b0f5aad5 | 776 | CDEBUG(D_INFO, "%s: get path %s "DFID" rec: %llu ln: %u\n", |
d7e09d03 PT |
777 | tgt->ltd_exp->exp_obd->obd_name, |
778 | gf->gf_path, PFID(&gf->gf_fid), gf->gf_recno, | |
779 | gf->gf_linkno); | |
780 | ||
781 | if (rc == 0) | |
4d54556f | 782 | goto out_fid2path; |
d7e09d03 PT |
783 | |
784 | /* sigh, has to go to another MDT to do path building further */ | |
2cbdaa45 | 785 | if (!remote_gf) { |
d7e09d03 | 786 | remote_gf_size = sizeof(*remote_gf) + PATH_MAX; |
8bcf30c3 | 787 | remote_gf = kzalloc(remote_gf_size, GFP_NOFS); |
76e4290c | 788 | if (!remote_gf) { |
4d54556f JL |
789 | rc = -ENOMEM; |
790 | goto out_fid2path; | |
791 | } | |
d7e09d03 PT |
792 | remote_gf->gf_pathlen = PATH_MAX; |
793 | } | |
794 | ||
795 | if (!fid_is_sane(&gf->gf_fid)) { | |
796 | CERROR("%s: invalid FID "DFID": rc = %d\n", | |
797 | tgt->ltd_exp->exp_obd->obd_name, | |
798 | PFID(&gf->gf_fid), -EINVAL); | |
4d54556f JL |
799 | rc = -EINVAL; |
800 | goto out_fid2path; | |
d7e09d03 PT |
801 | } |
802 | ||
803 | tgt = lmv_find_target(lmv, &gf->gf_fid); | |
4d54556f JL |
804 | if (IS_ERR(tgt)) { |
805 | rc = -EINVAL; | |
806 | goto out_fid2path; | |
807 | } | |
d7e09d03 PT |
808 | |
809 | remote_gf->gf_fid = gf->gf_fid; | |
810 | remote_gf->gf_recno = -1; | |
811 | remote_gf->gf_linkno = -1; | |
812 | memset(remote_gf->gf_path, 0, remote_gf->gf_pathlen); | |
813 | gf = remote_gf; | |
814 | goto repeat_fid2path; | |
815 | ||
816 | out_fid2path: | |
13879e5d | 817 | kfree(remote_gf); |
0a3bdb00 | 818 | return rc; |
d7e09d03 PT |
819 | } |
820 | ||
78eb9092 TL |
821 | static int lmv_hsm_req_count(struct lmv_obd *lmv, |
822 | const struct hsm_user_request *hur, | |
823 | const struct lmv_tgt_desc *tgt_mds) | |
824 | { | |
a043a102 | 825 | u32 i, nr = 0; |
78eb9092 TL |
826 | struct lmv_tgt_desc *curr_tgt; |
827 | ||
828 | /* count how many requests must be sent to the given target */ | |
829 | for (i = 0; i < hur->hur_request.hr_itemcount; i++) { | |
830 | curr_tgt = lmv_find_target(lmv, &hur->hur_user_item[i].hui_fid); | |
831 | if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid)) | |
832 | nr++; | |
833 | } | |
834 | return nr; | |
835 | } | |
836 | ||
837 | static void lmv_hsm_req_build(struct lmv_obd *lmv, | |
838 | struct hsm_user_request *hur_in, | |
839 | const struct lmv_tgt_desc *tgt_mds, | |
840 | struct hsm_user_request *hur_out) | |
841 | { | |
842 | int i, nr_out; | |
843 | struct lmv_tgt_desc *curr_tgt; | |
844 | ||
845 | /* build the hsm_user_request for the given target */ | |
846 | hur_out->hur_request = hur_in->hur_request; | |
847 | nr_out = 0; | |
848 | for (i = 0; i < hur_in->hur_request.hr_itemcount; i++) { | |
849 | curr_tgt = lmv_find_target(lmv, | |
f0a87680 | 850 | &hur_in->hur_user_item[i].hui_fid); |
78eb9092 TL |
851 | if (obd_uuid_equals(&curr_tgt->ltd_uuid, &tgt_mds->ltd_uuid)) { |
852 | hur_out->hur_user_item[nr_out] = | |
853 | hur_in->hur_user_item[i]; | |
854 | nr_out++; | |
855 | } | |
856 | } | |
857 | hur_out->hur_request.hr_itemcount = nr_out; | |
858 | memcpy(hur_data(hur_out), hur_data(hur_in), | |
859 | hur_in->hur_request.hr_data_len); | |
860 | } | |
861 | ||
862 | static int lmv_hsm_ct_unregister(struct lmv_obd *lmv, unsigned int cmd, int len, | |
11be8f6c OD |
863 | struct lustre_kernelcomm *lk, |
864 | void __user *uarg) | |
78eb9092 | 865 | { |
406fc913 HD |
866 | int rc = 0; |
867 | __u32 i; | |
78eb9092 TL |
868 | |
869 | /* unregister request (call from llapi_hsm_copytool_fini) */ | |
870 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
0fdd2b8d DE |
871 | struct lmv_tgt_desc *tgt = lmv->tgts[i]; |
872 | ||
873 | if (!tgt || !tgt->ltd_exp) | |
874 | continue; | |
875 | ||
78eb9092 | 876 | /* best effort: try to clean as much as possible |
7f05d5bb OD |
877 | * (continue on error) |
878 | */ | |
78eb9092 TL |
879 | obd_iocontrol(cmd, lmv->tgts[i]->ltd_exp, len, lk, uarg); |
880 | } | |
881 | ||
882 | /* Whatever the result, remove copytool from kuc groups. | |
883 | * Unreached coordinators will get EPIPE on next requests | |
884 | * and will unregister automatically. | |
885 | */ | |
17328956 | 886 | rc = libcfs_kkuc_group_rem(lk->lk_uid, lk->lk_group); |
406fc913 | 887 | |
0a3bdb00 | 888 | return rc; |
78eb9092 TL |
889 | } |
890 | ||
891 | static int lmv_hsm_ct_register(struct lmv_obd *lmv, unsigned int cmd, int len, | |
11be8f6c | 892 | struct lustre_kernelcomm *lk, void __user *uarg) |
78eb9092 | 893 | { |
406fc913 HD |
894 | struct file *filp; |
895 | __u32 i, j; | |
896 | int err, rc = 0; | |
897 | bool any_set = false; | |
17328956 | 898 | struct kkuc_ct_data kcd = { 0 }; |
78eb9092 TL |
899 | |
900 | /* All or nothing: try to register to all MDS. | |
901 | * In case of failure, unregister from previous MDS, | |
7f05d5bb OD |
902 | * except if it because of inactive target. |
903 | */ | |
78eb9092 | 904 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { |
0fdd2b8d DE |
905 | struct lmv_tgt_desc *tgt = lmv->tgts[i]; |
906 | ||
907 | if (!tgt || !tgt->ltd_exp) | |
908 | continue; | |
909 | ||
910 | err = obd_iocontrol(cmd, tgt->ltd_exp, len, lk, uarg); | |
78eb9092 | 911 | if (err) { |
0fdd2b8d | 912 | if (tgt->ltd_active) { |
78eb9092 | 913 | /* permanent error */ |
2d00bd17 | 914 | CERROR("error: iocontrol MDC %s on MDTidx %d cmd %x: err = %d\n", |
0fdd2b8d | 915 | tgt->ltd_uuid.uuid, i, cmd, err); |
78eb9092 TL |
916 | rc = err; |
917 | lk->lk_flags |= LK_FLG_STOP; | |
918 | /* unregister from previous MDS */ | |
0fdd2b8d DE |
919 | for (j = 0; j < i; j++) { |
920 | tgt = lmv->tgts[j]; | |
921 | ||
922 | if (!tgt || !tgt->ltd_exp) | |
923 | continue; | |
924 | obd_iocontrol(cmd, tgt->ltd_exp, len, | |
925 | lk, uarg); | |
926 | } | |
0a3bdb00 | 927 | return rc; |
78eb9092 TL |
928 | } |
929 | /* else: transient error. | |
7f05d5bb OD |
930 | * kuc will register to the missing MDT when it is back |
931 | */ | |
78eb9092 TL |
932 | } else { |
933 | any_set = true; | |
934 | } | |
935 | } | |
936 | ||
937 | if (!any_set) | |
938 | /* no registration done: return error */ | |
0a3bdb00 | 939 | return -ENOTCONN; |
78eb9092 TL |
940 | |
941 | /* at least one registration done, with no failure */ | |
942 | filp = fget(lk->lk_wfd); | |
406fc913 | 943 | if (!filp) |
0a3bdb00 | 944 | return -EBADF; |
406fc913 | 945 | |
17328956 HZ |
946 | kcd.kcd_magic = KKUC_CT_DATA_MAGIC; |
947 | kcd.kcd_uuid = lmv->cluuid; | |
948 | kcd.kcd_archive = lk->lk_data; | |
406fc913 | 949 | |
17328956 HZ |
950 | rc = libcfs_kkuc_group_add(filp, lk->lk_uid, lk->lk_group, |
951 | &kcd, sizeof(kcd)); | |
406fc913 HD |
952 | if (rc) { |
953 | if (filp) | |
954 | fput(filp); | |
406fc913 HD |
955 | } |
956 | ||
0a3bdb00 | 957 | return rc; |
78eb9092 TL |
958 | } |
959 | ||
d7e09d03 | 960 | static int lmv_iocontrol(unsigned int cmd, struct obd_export *exp, |
e09bee34 | 961 | int len, void *karg, void __user *uarg) |
d7e09d03 PT |
962 | { |
963 | struct obd_device *obddev = class_exp2obd(exp); | |
964 | struct lmv_obd *lmv = &obddev->u.lmv; | |
0fdd2b8d | 965 | struct lmv_tgt_desc *tgt = NULL; |
a043a102 | 966 | u32 i = 0; |
d7e09d03 PT |
967 | int rc = 0; |
968 | int set = 0; | |
a043a102 | 969 | u32 count = lmv->desc.ld_tgt_count; |
d7e09d03 PT |
970 | |
971 | if (count == 0) | |
0a3bdb00 | 972 | return -ENOTTY; |
d7e09d03 PT |
973 | |
974 | switch (cmd) { | |
975 | case IOC_OBD_STATFS: { | |
976 | struct obd_ioctl_data *data = karg; | |
977 | struct obd_device *mdc_obd; | |
978 | struct obd_statfs stat_buf = {0}; | |
979 | __u32 index; | |
980 | ||
981 | memcpy(&index, data->ioc_inlbuf2, sizeof(__u32)); | |
dbd18138 | 982 | if (index >= count) |
0a3bdb00 | 983 | return -ENODEV; |
d7e09d03 | 984 | |
0fdd2b8d DE |
985 | tgt = lmv->tgts[index]; |
986 | if (!tgt || !tgt->ltd_active) | |
0a3bdb00 | 987 | return -ENODATA; |
d7e09d03 | 988 | |
0fdd2b8d | 989 | mdc_obd = class_exp2obd(tgt->ltd_exp); |
d7e09d03 | 990 | if (!mdc_obd) |
0a3bdb00 | 991 | return -EINVAL; |
d7e09d03 PT |
992 | |
993 | /* copy UUID */ | |
994 | if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(mdc_obd), | |
f0a87680 OD |
995 | min((int)data->ioc_plen2, |
996 | (int)sizeof(struct obd_uuid)))) | |
0a3bdb00 | 997 | return -EFAULT; |
d7e09d03 | 998 | |
0fdd2b8d | 999 | rc = obd_statfs(NULL, tgt->ltd_exp, &stat_buf, |
d7e09d03 PT |
1000 | cfs_time_shift_64(-OBD_STATFS_CACHE_SECONDS), |
1001 | 0); | |
1002 | if (rc) | |
0a3bdb00 | 1003 | return rc; |
d7e09d03 | 1004 | if (copy_to_user(data->ioc_pbuf1, &stat_buf, |
f0a87680 OD |
1005 | min((int)data->ioc_plen1, |
1006 | (int)sizeof(stat_buf)))) | |
0a3bdb00 | 1007 | return -EFAULT; |
d7e09d03 PT |
1008 | break; |
1009 | } | |
1010 | case OBD_IOC_QUOTACTL: { | |
1011 | struct if_quotactl *qctl = karg; | |
d7e09d03 PT |
1012 | struct obd_quotactl *oqctl; |
1013 | ||
1014 | if (qctl->qc_valid == QC_MDTIDX) { | |
19c55148 | 1015 | if (count <= qctl->qc_idx) |
0a3bdb00 | 1016 | return -EINVAL; |
d7e09d03 PT |
1017 | |
1018 | tgt = lmv->tgts[qctl->qc_idx]; | |
2cbdaa45 | 1019 | if (!tgt || !tgt->ltd_exp) |
0a3bdb00 | 1020 | return -EINVAL; |
d7e09d03 PT |
1021 | } else if (qctl->qc_valid == QC_UUID) { |
1022 | for (i = 0; i < count; i++) { | |
1023 | tgt = lmv->tgts[i]; | |
2cbdaa45 | 1024 | if (!tgt) |
d7e09d03 PT |
1025 | continue; |
1026 | if (!obd_uuid_equals(&tgt->ltd_uuid, | |
1027 | &qctl->obd_uuid)) | |
1028 | continue; | |
1029 | ||
2cbdaa45 | 1030 | if (!tgt->ltd_exp) |
0a3bdb00 | 1031 | return -EINVAL; |
d7e09d03 PT |
1032 | |
1033 | break; | |
1034 | } | |
1035 | } else { | |
0a3bdb00 | 1036 | return -EINVAL; |
d7e09d03 PT |
1037 | } |
1038 | ||
1039 | if (i >= count) | |
0a3bdb00 | 1040 | return -EAGAIN; |
d7e09d03 PT |
1041 | |
1042 | LASSERT(tgt && tgt->ltd_exp); | |
8bcf30c3 | 1043 | oqctl = kzalloc(sizeof(*oqctl), GFP_NOFS); |
d7e09d03 | 1044 | if (!oqctl) |
0a3bdb00 | 1045 | return -ENOMEM; |
d7e09d03 PT |
1046 | |
1047 | QCTL_COPY(oqctl, qctl); | |
1048 | rc = obd_quotactl(tgt->ltd_exp, oqctl); | |
1049 | if (rc == 0) { | |
1050 | QCTL_COPY(qctl, oqctl); | |
1051 | qctl->qc_valid = QC_MDTIDX; | |
1052 | qctl->obd_uuid = tgt->ltd_uuid; | |
1053 | } | |
8bcf30c3 | 1054 | kfree(oqctl); |
d7e09d03 PT |
1055 | break; |
1056 | } | |
1057 | case OBD_IOC_CHANGELOG_SEND: | |
1058 | case OBD_IOC_CHANGELOG_CLEAR: { | |
1059 | struct ioc_changelog *icc = karg; | |
1060 | ||
1061 | if (icc->icc_mdtindex >= count) | |
0a3bdb00 | 1062 | return -ENODEV; |
d7e09d03 | 1063 | |
0fdd2b8d DE |
1064 | tgt = lmv->tgts[icc->icc_mdtindex]; |
1065 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) | |
0a3bdb00 | 1066 | return -ENODEV; |
0fdd2b8d | 1067 | rc = obd_iocontrol(cmd, tgt->ltd_exp, sizeof(*icc), icc, NULL); |
d7e09d03 PT |
1068 | break; |
1069 | } | |
1070 | case LL_IOC_GET_CONNECT_FLAGS: { | |
0fdd2b8d DE |
1071 | tgt = lmv->tgts[0]; |
1072 | ||
1073 | if (!tgt || !tgt->ltd_exp) | |
0a3bdb00 | 1074 | return -ENODATA; |
0fdd2b8d | 1075 | rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg); |
d7e09d03 PT |
1076 | break; |
1077 | } | |
1078 | case OBD_IOC_FID2PATH: { | |
1079 | rc = lmv_fid2path(exp, len, karg, uarg); | |
1080 | break; | |
1081 | } | |
1082 | case LL_IOC_HSM_STATE_GET: | |
1083 | case LL_IOC_HSM_STATE_SET: | |
78eb9092 TL |
1084 | case LL_IOC_HSM_ACTION: { |
1085 | struct md_op_data *op_data = karg; | |
78eb9092 TL |
1086 | |
1087 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
1088 | if (IS_ERR(tgt)) | |
2cbdaa45 | 1089 | return PTR_ERR(tgt); |
78eb9092 | 1090 | |
2cbdaa45 OD |
1091 | if (!tgt->ltd_exp) |
1092 | return -EINVAL; | |
78eb9092 TL |
1093 | |
1094 | rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg); | |
1095 | break; | |
1096 | } | |
1097 | case LL_IOC_HSM_PROGRESS: { | |
1098 | const struct hsm_progress_kernel *hpk = karg; | |
78eb9092 TL |
1099 | |
1100 | tgt = lmv_find_target(lmv, &hpk->hpk_fid); | |
1101 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1102 | return PTR_ERR(tgt); |
78eb9092 TL |
1103 | rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg); |
1104 | break; | |
1105 | } | |
1106 | case LL_IOC_HSM_REQUEST: { | |
1107 | struct hsm_user_request *hur = karg; | |
78eb9092 TL |
1108 | unsigned int reqcount = hur->hur_request.hr_itemcount; |
1109 | ||
1110 | if (reqcount == 0) | |
0a3bdb00 | 1111 | return 0; |
78eb9092 TL |
1112 | |
1113 | /* if the request is about a single fid | |
1114 | * or if there is a single MDS, no need to split | |
7f05d5bb OD |
1115 | * the request. |
1116 | */ | |
78eb9092 TL |
1117 | if (reqcount == 1 || count == 1) { |
1118 | tgt = lmv_find_target(lmv, | |
1119 | &hur->hur_user_item[0].hui_fid); | |
1120 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1121 | return PTR_ERR(tgt); |
78eb9092 TL |
1122 | rc = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg); |
1123 | } else { | |
1124 | /* split fid list to their respective MDS */ | |
1125 | for (i = 0; i < count; i++) { | |
1126 | unsigned int nr, reqlen; | |
1127 | int rc1; | |
1128 | struct hsm_user_request *req; | |
1129 | ||
0fdd2b8d DE |
1130 | tgt = lmv->tgts[i]; |
1131 | if (!tgt || !tgt->ltd_exp) | |
1132 | continue; | |
1133 | ||
1134 | nr = lmv_hsm_req_count(lmv, hur, tgt); | |
78eb9092 TL |
1135 | if (nr == 0) /* nothing for this MDS */ |
1136 | continue; | |
1137 | ||
1138 | /* build a request with fids for this MDS */ | |
1139 | reqlen = offsetof(typeof(*hur), | |
1140 | hur_user_item[nr]) | |
1141 | + hur->hur_request.hr_data_len; | |
8cc3792a | 1142 | req = libcfs_kvzalloc(reqlen, GFP_NOFS); |
2cbdaa45 | 1143 | if (!req) |
0a3bdb00 | 1144 | return -ENOMEM; |
78eb9092 | 1145 | |
0fdd2b8d | 1146 | lmv_hsm_req_build(lmv, hur, tgt, req); |
78eb9092 | 1147 | |
0fdd2b8d DE |
1148 | rc1 = obd_iocontrol(cmd, tgt->ltd_exp, reqlen, |
1149 | req, uarg); | |
78eb9092 TL |
1150 | if (rc1 != 0 && rc == 0) |
1151 | rc = rc1; | |
8cc3792a | 1152 | kvfree(req); |
78eb9092 TL |
1153 | } |
1154 | } | |
1155 | break; | |
1156 | } | |
d7e09d03 PT |
1157 | case LL_IOC_LOV_SWAP_LAYOUTS: { |
1158 | struct md_op_data *op_data = karg; | |
1159 | struct lmv_tgt_desc *tgt1, *tgt2; | |
1160 | ||
1161 | tgt1 = lmv_find_target(lmv, &op_data->op_fid1); | |
1162 | if (IS_ERR(tgt1)) | |
0a3bdb00 | 1163 | return PTR_ERR(tgt1); |
d7e09d03 PT |
1164 | |
1165 | tgt2 = lmv_find_target(lmv, &op_data->op_fid2); | |
1166 | if (IS_ERR(tgt2)) | |
0a3bdb00 | 1167 | return PTR_ERR(tgt2); |
d7e09d03 | 1168 | |
2cbdaa45 | 1169 | if (!tgt1->ltd_exp || !tgt2->ltd_exp) |
0a3bdb00 | 1170 | return -EINVAL; |
d7e09d03 PT |
1171 | |
1172 | /* only files on same MDT can have their layouts swapped */ | |
1173 | if (tgt1->ltd_idx != tgt2->ltd_idx) | |
0a3bdb00 | 1174 | return -EPERM; |
d7e09d03 PT |
1175 | |
1176 | rc = obd_iocontrol(cmd, tgt1->ltd_exp, len, karg, uarg); | |
1177 | break; | |
1178 | } | |
78eb9092 TL |
1179 | case LL_IOC_HSM_CT_START: { |
1180 | struct lustre_kernelcomm *lk = karg; | |
50ffcb7e | 1181 | |
78eb9092 TL |
1182 | if (lk->lk_flags & LK_FLG_STOP) |
1183 | rc = lmv_hsm_ct_unregister(lmv, cmd, len, lk, uarg); | |
1184 | else | |
1185 | rc = lmv_hsm_ct_register(lmv, cmd, len, lk, uarg); | |
1186 | break; | |
1187 | } | |
d7e09d03 PT |
1188 | default: |
1189 | for (i = 0; i < count; i++) { | |
1190 | struct obd_device *mdc_obd; | |
1191 | int err; | |
1192 | ||
0fdd2b8d DE |
1193 | tgt = lmv->tgts[i]; |
1194 | if (!tgt || !tgt->ltd_exp) | |
d7e09d03 PT |
1195 | continue; |
1196 | /* ll_umount_begin() sets force flag but for lmv, not | |
7f05d5bb OD |
1197 | * mdc. Let's pass it through |
1198 | */ | |
0fdd2b8d | 1199 | mdc_obd = class_exp2obd(tgt->ltd_exp); |
d7e09d03 | 1200 | mdc_obd->obd_force = obddev->obd_force; |
0fdd2b8d | 1201 | err = obd_iocontrol(cmd, tgt->ltd_exp, len, karg, uarg); |
d7e09d03 | 1202 | if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) { |
0a3bdb00 | 1203 | return err; |
d7e09d03 | 1204 | } else if (err) { |
0fdd2b8d | 1205 | if (tgt->ltd_active) { |
2d00bd17 | 1206 | CERROR("error: iocontrol MDC %s on MDTidx %d cmd %x: err = %d\n", |
0fdd2b8d | 1207 | tgt->ltd_uuid.uuid, i, cmd, err); |
d7e09d03 PT |
1208 | if (!rc) |
1209 | rc = err; | |
1210 | } | |
da5ecb4d | 1211 | } else { |
d7e09d03 | 1212 | set = 1; |
da5ecb4d | 1213 | } |
d7e09d03 PT |
1214 | } |
1215 | if (!set && !rc) | |
1216 | rc = -EIO; | |
1217 | } | |
0a3bdb00 | 1218 | return rc; |
d7e09d03 PT |
1219 | } |
1220 | ||
d7e09d03 PT |
1221 | /** |
1222 | * This is _inode_ placement policy function (not name). | |
1223 | */ | |
1224 | static int lmv_placement_policy(struct obd_device *obd, | |
114acca8 | 1225 | struct md_op_data *op_data, u32 *mds) |
d7e09d03 PT |
1226 | { |
1227 | struct lmv_obd *lmv = &obd->u.lmv; | |
d7e09d03 | 1228 | |
2cbdaa45 | 1229 | LASSERT(mds); |
d7e09d03 PT |
1230 | |
1231 | if (lmv->desc.ld_tgt_count == 1) { | |
1232 | *mds = 0; | |
0a3bdb00 | 1233 | return 0; |
d7e09d03 PT |
1234 | } |
1235 | ||
1236 | /** | |
1237 | * If stripe_offset is provided during setdirstripe | |
b64767de | 1238 | * (setdirstripe -i xx), xx MDS will be chosen. |
d7e09d03 | 1239 | */ |
2de35386 | 1240 | if (op_data->op_cli_flags & CLI_SET_MEA && op_data->op_data) { |
d7e09d03 PT |
1241 | struct lmv_user_md *lum; |
1242 | ||
2de35386 | 1243 | lum = op_data->op_data; |
5e01c959 JH |
1244 | if (le32_to_cpu(lum->lum_stripe_offset) != (__u32)-1) { |
1245 | *mds = le32_to_cpu(lum->lum_stripe_offset); | |
75ac62fc | 1246 | } else { |
1247 | /* | |
1248 | * -1 means default, which will be in the same MDT with | |
1249 | * the stripe | |
1250 | */ | |
1251 | *mds = op_data->op_mds; | |
5e01c959 | 1252 | lum->lum_stripe_offset = cpu_to_le32(op_data->op_mds); |
75ac62fc | 1253 | } |
2de35386 | 1254 | } else { |
1255 | /* | |
1256 | * Allocate new fid on target according to operation type and | |
1257 | * parent home mds. | |
1258 | */ | |
1259 | *mds = op_data->op_mds; | |
d7e09d03 PT |
1260 | } |
1261 | ||
0a3bdb00 | 1262 | return 0; |
d7e09d03 PT |
1263 | } |
1264 | ||
114acca8 | 1265 | int __lmv_fid_alloc(struct lmv_obd *lmv, struct lu_fid *fid, u32 mds) |
d7e09d03 PT |
1266 | { |
1267 | struct lmv_tgt_desc *tgt; | |
1268 | int rc; | |
d7e09d03 | 1269 | |
711942df | 1270 | tgt = lmv_get_target(lmv, mds, NULL); |
d7e09d03 | 1271 | if (IS_ERR(tgt)) |
0a3bdb00 | 1272 | return PTR_ERR(tgt); |
d7e09d03 PT |
1273 | |
1274 | /* | |
1275 | * New seq alloc and FLD setup should be atomic. Otherwise we may find | |
1276 | * on server that seq in new allocated fid is not yet known. | |
1277 | */ | |
1278 | mutex_lock(&tgt->ltd_fid_mutex); | |
1279 | ||
2cbdaa45 | 1280 | if (tgt->ltd_active == 0 || !tgt->ltd_exp) { |
4d54556f JL |
1281 | rc = -ENODEV; |
1282 | goto out; | |
1283 | } | |
d7e09d03 PT |
1284 | |
1285 | /* | |
1286 | * Asking underlaying tgt layer to allocate new fid. | |
1287 | */ | |
8f18c8a4 | 1288 | rc = obd_fid_alloc(NULL, tgt->ltd_exp, fid, NULL); |
d7e09d03 PT |
1289 | if (rc > 0) { |
1290 | LASSERT(fid_is_sane(fid)); | |
1291 | rc = 0; | |
1292 | } | |
1293 | ||
d7e09d03 PT |
1294 | out: |
1295 | mutex_unlock(&tgt->ltd_fid_mutex); | |
1296 | return rc; | |
1297 | } | |
1298 | ||
8f18c8a4 | 1299 | int lmv_fid_alloc(const struct lu_env *env, struct obd_export *exp, |
1300 | struct lu_fid *fid, struct md_op_data *op_data) | |
d7e09d03 PT |
1301 | { |
1302 | struct obd_device *obd = class_exp2obd(exp); | |
1303 | struct lmv_obd *lmv = &obd->u.lmv; | |
114acca8 | 1304 | u32 mds = 0; |
d7e09d03 | 1305 | int rc; |
d7e09d03 | 1306 | |
2cbdaa45 OD |
1307 | LASSERT(op_data); |
1308 | LASSERT(fid); | |
d7e09d03 PT |
1309 | |
1310 | rc = lmv_placement_policy(obd, op_data, &mds); | |
1311 | if (rc) { | |
2d00bd17 JP |
1312 | CERROR("Can't get target for allocating fid, rc %d\n", |
1313 | rc); | |
0a3bdb00 | 1314 | return rc; |
d7e09d03 PT |
1315 | } |
1316 | ||
1317 | rc = __lmv_fid_alloc(lmv, fid, mds); | |
1318 | if (rc) { | |
1319 | CERROR("Can't alloc new fid, rc %d\n", rc); | |
0a3bdb00 | 1320 | return rc; |
d7e09d03 PT |
1321 | } |
1322 | ||
0a3bdb00 | 1323 | return rc; |
d7e09d03 PT |
1324 | } |
1325 | ||
1326 | static int lmv_setup(struct obd_device *obd, struct lustre_cfg *lcfg) | |
1327 | { | |
1328 | struct lmv_obd *lmv = &obd->u.lmv; | |
9b801302 | 1329 | struct lprocfs_static_vars lvars = { NULL }; |
d7e09d03 PT |
1330 | struct lmv_desc *desc; |
1331 | int rc; | |
d7e09d03 PT |
1332 | |
1333 | if (LUSTRE_CFG_BUFLEN(lcfg, 1) < 1) { | |
1334 | CERROR("LMV setup requires a descriptor\n"); | |
0a3bdb00 | 1335 | return -EINVAL; |
d7e09d03 PT |
1336 | } |
1337 | ||
1338 | desc = (struct lmv_desc *)lustre_cfg_buf(lcfg, 1); | |
1339 | if (sizeof(*desc) > LUSTRE_CFG_BUFLEN(lcfg, 1)) { | |
1340 | CERROR("Lmv descriptor size wrong: %d > %d\n", | |
1341 | (int)sizeof(*desc), LUSTRE_CFG_BUFLEN(lcfg, 1)); | |
0a3bdb00 | 1342 | return -EINVAL; |
d7e09d03 PT |
1343 | } |
1344 | ||
8bcf30c3 | 1345 | lmv->tgts = kcalloc(32, sizeof(*lmv->tgts), GFP_NOFS); |
2cbdaa45 | 1346 | if (!lmv->tgts) |
0a3bdb00 | 1347 | return -ENOMEM; |
d7e09d03 PT |
1348 | lmv->tgts_size = 32; |
1349 | ||
1350 | obd_str2uuid(&lmv->desc.ld_uuid, desc->ld_uuid.uuid); | |
1351 | lmv->desc.ld_tgt_count = 0; | |
1352 | lmv->desc.ld_active_tgt_count = 0; | |
1353 | lmv->max_cookiesize = 0; | |
1354 | lmv->max_def_easize = 0; | |
1355 | lmv->max_easize = 0; | |
1356 | lmv->lmv_placement = PLACEMENT_CHAR_POLICY; | |
1357 | ||
1358 | spin_lock_init(&lmv->lmv_lock); | |
019e9351 | 1359 | mutex_init(&lmv->lmv_init_mutex); |
d7e09d03 PT |
1360 | |
1361 | lprocfs_lmv_init_vars(&lvars); | |
1362 | ||
9b801302 | 1363 | lprocfs_obd_setup(obd, lvars.obd_vars, lvars.sysfs_vars); |
61e87ab0 DE |
1364 | rc = ldebugfs_seq_create(obd->obd_debugfs_entry, "target_obd", |
1365 | 0444, &lmv_proc_target_fops, obd); | |
1366 | if (rc) | |
1367 | CWARN("%s: error adding LMV target_obd file: rc = %d\n", | |
1368 | obd->obd_name, rc); | |
d7e09d03 PT |
1369 | rc = fld_client_init(&lmv->lmv_fld, obd->obd_name, |
1370 | LUSTRE_CLI_FLD_HASH_DHT); | |
1371 | if (rc) { | |
1372 | CERROR("Can't init FLD, err %d\n", rc); | |
4d54556f | 1373 | goto out; |
d7e09d03 PT |
1374 | } |
1375 | ||
0a3bdb00 | 1376 | return 0; |
d7e09d03 PT |
1377 | |
1378 | out: | |
1379 | return rc; | |
1380 | } | |
1381 | ||
1382 | static int lmv_cleanup(struct obd_device *obd) | |
1383 | { | |
1384 | struct lmv_obd *lmv = &obd->u.lmv; | |
d7e09d03 PT |
1385 | |
1386 | fld_client_fini(&lmv->lmv_fld); | |
2cbdaa45 | 1387 | if (lmv->tgts) { |
d7e09d03 | 1388 | int i; |
50ffcb7e | 1389 | |
d7e09d03 | 1390 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { |
2cbdaa45 | 1391 | if (!lmv->tgts[i]) |
d7e09d03 PT |
1392 | continue; |
1393 | lmv_del_target(lmv, i); | |
1394 | } | |
8bcf30c3 | 1395 | kfree(lmv->tgts); |
d7e09d03 PT |
1396 | lmv->tgts_size = 0; |
1397 | } | |
0a3bdb00 | 1398 | return 0; |
d7e09d03 PT |
1399 | } |
1400 | ||
21aef7d9 | 1401 | static int lmv_process_config(struct obd_device *obd, u32 len, void *buf) |
d7e09d03 PT |
1402 | { |
1403 | struct lustre_cfg *lcfg = buf; | |
1404 | struct obd_uuid obd_uuid; | |
1405 | int gen; | |
1406 | __u32 index; | |
1407 | int rc; | |
d7e09d03 PT |
1408 | |
1409 | switch (lcfg->lcfg_command) { | |
1410 | case LCFG_ADD_MDC: | |
1411 | /* modify_mdc_tgts add 0:lustre-clilmv 1:lustre-MDT0000_UUID | |
7f05d5bb OD |
1412 | * 2:0 3:1 4:lustre-MDT0000-mdc_UUID |
1413 | */ | |
4d54556f JL |
1414 | if (LUSTRE_CFG_BUFLEN(lcfg, 1) > sizeof(obd_uuid.uuid)) { |
1415 | rc = -EINVAL; | |
1416 | goto out; | |
1417 | } | |
d7e09d03 PT |
1418 | |
1419 | obd_str2uuid(&obd_uuid, lustre_cfg_buf(lcfg, 1)); | |
1420 | ||
503df2c4 | 1421 | if (sscanf(lustre_cfg_buf(lcfg, 2), "%u", &index) != 1) { |
4d54556f JL |
1422 | rc = -EINVAL; |
1423 | goto out; | |
1424 | } | |
1425 | if (sscanf(lustre_cfg_buf(lcfg, 3), "%d", &gen) != 1) { | |
1426 | rc = -EINVAL; | |
1427 | goto out; | |
1428 | } | |
d7e09d03 | 1429 | rc = lmv_add_target(obd, &obd_uuid, index, gen); |
4d54556f | 1430 | goto out; |
d7e09d03 PT |
1431 | default: |
1432 | CERROR("Unknown command: %d\n", lcfg->lcfg_command); | |
4d54556f JL |
1433 | rc = -EINVAL; |
1434 | goto out; | |
d7e09d03 PT |
1435 | } |
1436 | out: | |
0a3bdb00 | 1437 | return rc; |
d7e09d03 PT |
1438 | } |
1439 | ||
1440 | static int lmv_statfs(const struct lu_env *env, struct obd_export *exp, | |
1441 | struct obd_statfs *osfs, __u64 max_age, __u32 flags) | |
1442 | { | |
1443 | struct obd_device *obd = class_exp2obd(exp); | |
1444 | struct lmv_obd *lmv = &obd->u.lmv; | |
1445 | struct obd_statfs *temp; | |
1446 | int rc = 0; | |
a043a102 | 1447 | u32 i; |
d7e09d03 PT |
1448 | |
1449 | rc = lmv_check_connect(obd); | |
1450 | if (rc) | |
0a3bdb00 | 1451 | return rc; |
d7e09d03 | 1452 | |
8bcf30c3 | 1453 | temp = kzalloc(sizeof(*temp), GFP_NOFS); |
76e4290c | 1454 | if (!temp) |
0a3bdb00 | 1455 | return -ENOMEM; |
d7e09d03 PT |
1456 | |
1457 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
2cbdaa45 | 1458 | if (!lmv->tgts[i] || !lmv->tgts[i]->ltd_exp) |
d7e09d03 PT |
1459 | continue; |
1460 | ||
1461 | rc = obd_statfs(env, lmv->tgts[i]->ltd_exp, temp, | |
1462 | max_age, flags); | |
1463 | if (rc) { | |
1464 | CERROR("can't stat MDS #%d (%s), error %d\n", i, | |
1465 | lmv->tgts[i]->ltd_exp->exp_obd->obd_name, | |
1466 | rc); | |
4d54556f | 1467 | goto out_free_temp; |
d7e09d03 PT |
1468 | } |
1469 | ||
1470 | if (i == 0) { | |
1471 | *osfs = *temp; | |
1472 | /* If the statfs is from mount, it will needs | |
1473 | * retrieve necessary information from MDT0. | |
1474 | * i.e. mount does not need the merged osfs | |
1475 | * from all of MDT. | |
1476 | * And also clients can be mounted as long as | |
7f05d5bb OD |
1477 | * MDT0 is in service |
1478 | */ | |
d7e09d03 | 1479 | if (flags & OBD_STATFS_FOR_MDT0) |
4d54556f | 1480 | goto out_free_temp; |
d7e09d03 PT |
1481 | } else { |
1482 | osfs->os_bavail += temp->os_bavail; | |
1483 | osfs->os_blocks += temp->os_blocks; | |
1484 | osfs->os_ffree += temp->os_ffree; | |
1485 | osfs->os_files += temp->os_files; | |
1486 | } | |
1487 | } | |
1488 | ||
d7e09d03 | 1489 | out_free_temp: |
8bcf30c3 | 1490 | kfree(temp); |
d7e09d03 PT |
1491 | return rc; |
1492 | } | |
1493 | ||
1494 | static int lmv_getstatus(struct obd_export *exp, | |
ef2e0f55 | 1495 | struct lu_fid *fid) |
d7e09d03 PT |
1496 | { |
1497 | struct obd_device *obd = exp->exp_obd; | |
1498 | struct lmv_obd *lmv = &obd->u.lmv; | |
1499 | int rc; | |
d7e09d03 PT |
1500 | |
1501 | rc = lmv_check_connect(obd); | |
1502 | if (rc) | |
0a3bdb00 | 1503 | return rc; |
d7e09d03 | 1504 | |
ef2e0f55 | 1505 | rc = md_getstatus(lmv->tgts[0]->ltd_exp, fid); |
0a3bdb00 | 1506 | return rc; |
d7e09d03 PT |
1507 | } |
1508 | ||
1509 | static int lmv_getxattr(struct obd_export *exp, const struct lu_fid *fid, | |
ef2e0f55 | 1510 | u64 valid, const char *name, |
d7e09d03 PT |
1511 | const char *input, int input_size, int output_size, |
1512 | int flags, struct ptlrpc_request **request) | |
1513 | { | |
1514 | struct obd_device *obd = exp->exp_obd; | |
1515 | struct lmv_obd *lmv = &obd->u.lmv; | |
1516 | struct lmv_tgt_desc *tgt; | |
1517 | int rc; | |
d7e09d03 PT |
1518 | |
1519 | rc = lmv_check_connect(obd); | |
1520 | if (rc) | |
0a3bdb00 | 1521 | return rc; |
d7e09d03 PT |
1522 | |
1523 | tgt = lmv_find_target(lmv, fid); | |
1524 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1525 | return PTR_ERR(tgt); |
d7e09d03 | 1526 | |
ef2e0f55 | 1527 | rc = md_getxattr(tgt->ltd_exp, fid, valid, name, input, |
d7e09d03 PT |
1528 | input_size, output_size, flags, request); |
1529 | ||
0a3bdb00 | 1530 | return rc; |
d7e09d03 PT |
1531 | } |
1532 | ||
1533 | static int lmv_setxattr(struct obd_export *exp, const struct lu_fid *fid, | |
ef2e0f55 | 1534 | u64 valid, const char *name, |
d7e09d03 PT |
1535 | const char *input, int input_size, int output_size, |
1536 | int flags, __u32 suppgid, | |
1537 | struct ptlrpc_request **request) | |
1538 | { | |
1539 | struct obd_device *obd = exp->exp_obd; | |
1540 | struct lmv_obd *lmv = &obd->u.lmv; | |
1541 | struct lmv_tgt_desc *tgt; | |
1542 | int rc; | |
d7e09d03 PT |
1543 | |
1544 | rc = lmv_check_connect(obd); | |
1545 | if (rc) | |
0a3bdb00 | 1546 | return rc; |
d7e09d03 PT |
1547 | |
1548 | tgt = lmv_find_target(lmv, fid); | |
1549 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1550 | return PTR_ERR(tgt); |
d7e09d03 | 1551 | |
ef2e0f55 | 1552 | rc = md_setxattr(tgt->ltd_exp, fid, valid, name, input, |
d7e09d03 PT |
1553 | input_size, output_size, flags, suppgid, |
1554 | request); | |
1555 | ||
0a3bdb00 | 1556 | return rc; |
d7e09d03 PT |
1557 | } |
1558 | ||
1559 | static int lmv_getattr(struct obd_export *exp, struct md_op_data *op_data, | |
1560 | struct ptlrpc_request **request) | |
1561 | { | |
1562 | struct obd_device *obd = exp->exp_obd; | |
1563 | struct lmv_obd *lmv = &obd->u.lmv; | |
1564 | struct lmv_tgt_desc *tgt; | |
1565 | int rc; | |
d7e09d03 PT |
1566 | |
1567 | rc = lmv_check_connect(obd); | |
1568 | if (rc) | |
0a3bdb00 | 1569 | return rc; |
d7e09d03 PT |
1570 | |
1571 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
1572 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1573 | return PTR_ERR(tgt); |
d7e09d03 PT |
1574 | |
1575 | if (op_data->op_flags & MF_GET_MDT_IDX) { | |
1576 | op_data->op_mds = tgt->ltd_idx; | |
0a3bdb00 | 1577 | return 0; |
d7e09d03 PT |
1578 | } |
1579 | ||
1580 | rc = md_getattr(tgt->ltd_exp, op_data, request); | |
1581 | ||
0a3bdb00 | 1582 | return rc; |
d7e09d03 PT |
1583 | } |
1584 | ||
1585 | static int lmv_null_inode(struct obd_export *exp, const struct lu_fid *fid) | |
1586 | { | |
1587 | struct obd_device *obd = exp->exp_obd; | |
1588 | struct lmv_obd *lmv = &obd->u.lmv; | |
a043a102 | 1589 | u32 i; |
d7e09d03 | 1590 | int rc; |
d7e09d03 PT |
1591 | |
1592 | rc = lmv_check_connect(obd); | |
1593 | if (rc) | |
0a3bdb00 | 1594 | return rc; |
d7e09d03 PT |
1595 | |
1596 | CDEBUG(D_INODE, "CBDATA for "DFID"\n", PFID(fid)); | |
1597 | ||
1598 | /* | |
1599 | * With DNE every object can have two locks in different namespaces: | |
1600 | * lookup lock in space of MDT storing direntry and update/open lock in | |
1601 | * space of MDT storing inode. | |
1602 | */ | |
1603 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
2cbdaa45 | 1604 | if (!lmv->tgts[i] || !lmv->tgts[i]->ltd_exp) |
d7e09d03 PT |
1605 | continue; |
1606 | md_null_inode(lmv->tgts[i]->ltd_exp, fid); | |
1607 | } | |
1608 | ||
0a3bdb00 | 1609 | return 0; |
d7e09d03 PT |
1610 | } |
1611 | ||
d7e09d03 PT |
1612 | static int lmv_close(struct obd_export *exp, struct md_op_data *op_data, |
1613 | struct md_open_data *mod, struct ptlrpc_request **request) | |
1614 | { | |
1615 | struct obd_device *obd = exp->exp_obd; | |
1616 | struct lmv_obd *lmv = &obd->u.lmv; | |
1617 | struct lmv_tgt_desc *tgt; | |
1618 | int rc; | |
d7e09d03 PT |
1619 | |
1620 | rc = lmv_check_connect(obd); | |
1621 | if (rc) | |
0a3bdb00 | 1622 | return rc; |
d7e09d03 PT |
1623 | |
1624 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
1625 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1626 | return PTR_ERR(tgt); |
d7e09d03 PT |
1627 | |
1628 | CDEBUG(D_INODE, "CLOSE "DFID"\n", PFID(&op_data->op_fid1)); | |
1629 | rc = md_close(tgt->ltd_exp, op_data, mod, request); | |
0a3bdb00 | 1630 | return rc; |
d7e09d03 PT |
1631 | } |
1632 | ||
2de35386 | 1633 | /** |
1634 | * Choosing the MDT by name or FID in @op_data. | |
1635 | * For non-striped directory, it will locate MDT by fid. | |
1636 | * For striped-directory, it will locate MDT by name. And also | |
1637 | * it will reset op_fid1 with the FID of the chosen stripe. | |
1638 | **/ | |
75ac62fc | 1639 | struct lmv_tgt_desc * |
1640 | lmv_locate_target_for_name(struct lmv_obd *lmv, struct lmv_stripe_md *lsm, | |
1641 | const char *name, int namelen, struct lu_fid *fid, | |
1642 | u32 *mds) | |
1643 | { | |
1644 | const struct lmv_oinfo *oinfo; | |
1645 | struct lmv_tgt_desc *tgt; | |
1646 | ||
1647 | oinfo = lsm_name_to_stripe_info(lsm, name, namelen); | |
79496845 | 1648 | if (IS_ERR(oinfo)) |
1649 | return ERR_CAST(oinfo); | |
1650 | ||
75ac62fc | 1651 | *fid = oinfo->lmo_fid; |
1652 | *mds = oinfo->lmo_mds; | |
711942df | 1653 | tgt = lmv_get_target(lmv, *mds, NULL); |
75ac62fc | 1654 | |
1655 | CDEBUG(D_INFO, "locate on mds %u "DFID"\n", *mds, PFID(fid)); | |
1656 | return tgt; | |
1657 | } | |
1658 | ||
893ab747 | 1659 | /** |
1660 | * Locate mds by fid or name | |
1661 | * | |
1662 | * For striped directory (lsm != NULL), it will locate the stripe | |
1663 | * by name hash (see lsm_name_to_stripe_info()). Note: if the hash_type | |
1664 | * is unknown, it will return -EBADFD, and lmv_intent_lookup might need | |
1665 | * walk through all of stripes to locate the entry. | |
1666 | * | |
1667 | * For normal direcotry, it will locate MDS by FID directly. | |
1668 | * \param[in] lmv LMV device | |
1669 | * \param[in] op_data client MD stack parameters, name, namelen | |
1670 | * mds_num etc. | |
1671 | * \param[in] fid object FID used to locate MDS. | |
1672 | * | |
1673 | * retval pointer to the lmv_tgt_desc if succeed. | |
1674 | * ERR_PTR(errno) if failed. | |
1675 | */ | |
d7e09d03 PT |
1676 | struct lmv_tgt_desc |
1677 | *lmv_locate_mds(struct lmv_obd *lmv, struct md_op_data *op_data, | |
1678 | struct lu_fid *fid) | |
1679 | { | |
2de35386 | 1680 | struct lmv_stripe_md *lsm = op_data->op_mea1; |
d7e09d03 PT |
1681 | struct lmv_tgt_desc *tgt; |
1682 | ||
8f18c8a4 | 1683 | if (!lsm || !op_data->op_namelen) { |
2de35386 | 1684 | tgt = lmv_find_target(lmv, fid); |
1685 | if (IS_ERR(tgt)) | |
1686 | return tgt; | |
1687 | ||
1688 | op_data->op_mds = tgt->ltd_idx; | |
1689 | ||
d7e09d03 | 1690 | return tgt; |
2de35386 | 1691 | } |
d7e09d03 | 1692 | |
75ac62fc | 1693 | return lmv_locate_target_for_name(lmv, lsm, op_data->op_name, |
1694 | op_data->op_namelen, fid, | |
1695 | &op_data->op_mds); | |
d7e09d03 PT |
1696 | } |
1697 | ||
5dc8d7b4 LC |
1698 | static int lmv_create(struct obd_export *exp, struct md_op_data *op_data, |
1699 | const void *data, int datalen, int mode, __u32 uid, | |
1700 | __u32 gid, cfs_cap_t cap_effective, __u64 rdev, | |
1701 | struct ptlrpc_request **request) | |
d7e09d03 PT |
1702 | { |
1703 | struct obd_device *obd = exp->exp_obd; | |
1704 | struct lmv_obd *lmv = &obd->u.lmv; | |
1705 | struct lmv_tgt_desc *tgt; | |
1706 | int rc; | |
d7e09d03 PT |
1707 | |
1708 | rc = lmv_check_connect(obd); | |
1709 | if (rc) | |
0a3bdb00 | 1710 | return rc; |
d7e09d03 PT |
1711 | |
1712 | if (!lmv->desc.ld_active_tgt_count) | |
0a3bdb00 | 1713 | return -EIO; |
d7e09d03 PT |
1714 | |
1715 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); | |
1716 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1717 | return PTR_ERR(tgt); |
d7e09d03 | 1718 | |
2de35386 | 1719 | CDEBUG(D_INODE, "CREATE name '%.*s' on "DFID" -> mds #%x\n", |
1720 | op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1), | |
1721 | op_data->op_mds); | |
1722 | ||
8f18c8a4 | 1723 | rc = lmv_fid_alloc(NULL, exp, &op_data->op_fid2, op_data); |
d7e09d03 | 1724 | if (rc) |
0a3bdb00 | 1725 | return rc; |
d7e09d03 | 1726 | |
2de35386 | 1727 | /* |
1728 | * Send the create request to the MDT where the object | |
1729 | * will be located | |
1730 | */ | |
1731 | tgt = lmv_find_target(lmv, &op_data->op_fid2); | |
1732 | if (IS_ERR(tgt)) | |
1733 | return PTR_ERR(tgt); | |
1734 | ||
1735 | op_data->op_mds = tgt->ltd_idx; | |
1736 | ||
1737 | CDEBUG(D_INODE, "CREATE obj "DFID" -> mds #%x\n", | |
1738 | PFID(&op_data->op_fid1), op_data->op_mds); | |
d7e09d03 PT |
1739 | |
1740 | op_data->op_flags |= MF_MDC_CANCEL_FID1; | |
1741 | rc = md_create(tgt->ltd_exp, op_data, data, datalen, mode, uid, gid, | |
1742 | cap_effective, rdev, request); | |
1743 | ||
1744 | if (rc == 0) { | |
2cbdaa45 | 1745 | if (!*request) |
0a3bdb00 | 1746 | return rc; |
d7e09d03 PT |
1747 | CDEBUG(D_INODE, "Created - "DFID"\n", PFID(&op_data->op_fid2)); |
1748 | } | |
0a3bdb00 | 1749 | return rc; |
d7e09d03 PT |
1750 | } |
1751 | ||
1752 | static int lmv_done_writing(struct obd_export *exp, | |
1753 | struct md_op_data *op_data, | |
1754 | struct md_open_data *mod) | |
1755 | { | |
1756 | struct obd_device *obd = exp->exp_obd; | |
1757 | struct lmv_obd *lmv = &obd->u.lmv; | |
1758 | struct lmv_tgt_desc *tgt; | |
1759 | int rc; | |
d7e09d03 PT |
1760 | |
1761 | rc = lmv_check_connect(obd); | |
1762 | if (rc) | |
0a3bdb00 | 1763 | return rc; |
d7e09d03 PT |
1764 | |
1765 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
1766 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1767 | return PTR_ERR(tgt); |
d7e09d03 PT |
1768 | |
1769 | rc = md_done_writing(tgt->ltd_exp, op_data, mod); | |
0a3bdb00 | 1770 | return rc; |
d7e09d03 PT |
1771 | } |
1772 | ||
d7e09d03 PT |
1773 | static int |
1774 | lmv_enqueue(struct obd_export *exp, struct ldlm_enqueue_info *einfo, | |
70a251f6 | 1775 | const ldlm_policy_data_t *policy, |
d7e09d03 | 1776 | struct lookup_intent *it, struct md_op_data *op_data, |
70a251f6 | 1777 | struct lustre_handle *lockh, __u64 extra_lock_flags) |
d7e09d03 PT |
1778 | { |
1779 | struct obd_device *obd = exp->exp_obd; | |
1780 | struct lmv_obd *lmv = &obd->u.lmv; | |
1781 | struct lmv_tgt_desc *tgt; | |
1782 | int rc; | |
d7e09d03 PT |
1783 | |
1784 | rc = lmv_check_connect(obd); | |
1785 | if (rc) | |
0a3bdb00 | 1786 | return rc; |
d7e09d03 PT |
1787 | |
1788 | CDEBUG(D_INODE, "ENQUEUE '%s' on "DFID"\n", | |
1789 | LL_IT2STR(it), PFID(&op_data->op_fid1)); | |
1790 | ||
1791 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); | |
1792 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1793 | return PTR_ERR(tgt); |
d7e09d03 PT |
1794 | |
1795 | CDEBUG(D_INODE, "ENQUEUE '%s' on "DFID" -> mds #%d\n", | |
1796 | LL_IT2STR(it), PFID(&op_data->op_fid1), tgt->ltd_idx); | |
1797 | ||
70a251f6 JH |
1798 | rc = md_enqueue(tgt->ltd_exp, einfo, policy, it, op_data, lockh, |
1799 | extra_lock_flags); | |
d7e09d03 | 1800 | |
0a3bdb00 | 1801 | return rc; |
d7e09d03 PT |
1802 | } |
1803 | ||
1804 | static int | |
1d8cb70c | 1805 | lmv_getattr_name(struct obd_export *exp, struct md_op_data *op_data, |
9ef3754c | 1806 | struct ptlrpc_request **preq) |
d7e09d03 PT |
1807 | { |
1808 | struct ptlrpc_request *req = NULL; | |
1809 | struct obd_device *obd = exp->exp_obd; | |
1810 | struct lmv_obd *lmv = &obd->u.lmv; | |
1811 | struct lmv_tgt_desc *tgt; | |
1812 | struct mdt_body *body; | |
1813 | int rc; | |
d7e09d03 PT |
1814 | |
1815 | rc = lmv_check_connect(obd); | |
1816 | if (rc) | |
0a3bdb00 | 1817 | return rc; |
d7e09d03 PT |
1818 | |
1819 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); | |
1820 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1821 | return PTR_ERR(tgt); |
d7e09d03 PT |
1822 | |
1823 | CDEBUG(D_INODE, "GETATTR_NAME for %*s on "DFID" -> mds #%d\n", | |
1824 | op_data->op_namelen, op_data->op_name, PFID(&op_data->op_fid1), | |
1825 | tgt->ltd_idx); | |
1826 | ||
9ef3754c | 1827 | rc = md_getattr_name(tgt->ltd_exp, op_data, preq); |
d7e09d03 | 1828 | if (rc != 0) |
0a3bdb00 | 1829 | return rc; |
d7e09d03 | 1830 | |
9ef3754c | 1831 | body = req_capsule_server_get(&(*preq)->rq_pill, &RMF_MDT_BODY); |
2e1b5b8b JH |
1832 | if (body->mbo_valid & OBD_MD_MDS) { |
1833 | struct lu_fid rid = body->mbo_fid1; | |
50ffcb7e | 1834 | |
d7e09d03 PT |
1835 | CDEBUG(D_INODE, "Request attrs for "DFID"\n", |
1836 | PFID(&rid)); | |
1837 | ||
1838 | tgt = lmv_find_target(lmv, &rid); | |
1839 | if (IS_ERR(tgt)) { | |
9ef3754c JH |
1840 | ptlrpc_req_finished(*preq); |
1841 | *preq = NULL; | |
0a3bdb00 | 1842 | return PTR_ERR(tgt); |
d7e09d03 PT |
1843 | } |
1844 | ||
1845 | op_data->op_fid1 = rid; | |
1846 | op_data->op_valid |= OBD_MD_FLCROSSREF; | |
1847 | op_data->op_namelen = 0; | |
1848 | op_data->op_name = NULL; | |
1849 | rc = md_getattr_name(tgt->ltd_exp, op_data, &req); | |
9ef3754c JH |
1850 | ptlrpc_req_finished(*preq); |
1851 | *preq = req; | |
d7e09d03 PT |
1852 | } |
1853 | ||
0a3bdb00 | 1854 | return rc; |
d7e09d03 PT |
1855 | } |
1856 | ||
1857 | #define md_op_data_fid(op_data, fl) \ | |
1858 | (fl == MF_MDC_CANCEL_FID1 ? &op_data->op_fid1 : \ | |
1859 | fl == MF_MDC_CANCEL_FID2 ? &op_data->op_fid2 : \ | |
1860 | fl == MF_MDC_CANCEL_FID3 ? &op_data->op_fid3 : \ | |
1861 | fl == MF_MDC_CANCEL_FID4 ? &op_data->op_fid4 : \ | |
1862 | NULL) | |
1863 | ||
79496845 | 1864 | static int lmv_early_cancel(struct obd_export *exp, struct lmv_tgt_desc *tgt, |
1865 | struct md_op_data *op_data, int op_tgt, | |
1866 | enum ldlm_mode mode, int bits, int flag) | |
d7e09d03 PT |
1867 | { |
1868 | struct lu_fid *fid = md_op_data_fid(op_data, flag); | |
1869 | struct obd_device *obd = exp->exp_obd; | |
1870 | struct lmv_obd *lmv = &obd->u.lmv; | |
b2952d62 | 1871 | ldlm_policy_data_t policy = { {0} }; |
d7e09d03 | 1872 | int rc = 0; |
d7e09d03 PT |
1873 | |
1874 | if (!fid_is_sane(fid)) | |
0a3bdb00 | 1875 | return 0; |
d7e09d03 | 1876 | |
79496845 | 1877 | if (!tgt) { |
1878 | tgt = lmv_find_target(lmv, fid); | |
1879 | if (IS_ERR(tgt)) | |
1880 | return PTR_ERR(tgt); | |
1881 | } | |
d7e09d03 PT |
1882 | |
1883 | if (tgt->ltd_idx != op_tgt) { | |
1884 | CDEBUG(D_INODE, "EARLY_CANCEL on "DFID"\n", PFID(fid)); | |
1885 | policy.l_inodebits.bits = bits; | |
1886 | rc = md_cancel_unused(tgt->ltd_exp, fid, &policy, | |
1887 | mode, LCF_ASYNC, NULL); | |
1888 | } else { | |
1889 | CDEBUG(D_INODE, | |
1890 | "EARLY_CANCEL skip operation target %d on "DFID"\n", | |
1891 | op_tgt, PFID(fid)); | |
1892 | op_data->op_flags |= flag; | |
1893 | rc = 0; | |
1894 | } | |
1895 | ||
0a3bdb00 | 1896 | return rc; |
d7e09d03 PT |
1897 | } |
1898 | ||
1899 | /* | |
1900 | * llite passes fid of an target inode in op_data->op_fid1 and id of directory in | |
1901 | * op_data->op_fid2 | |
1902 | */ | |
1903 | static int lmv_link(struct obd_export *exp, struct md_op_data *op_data, | |
1904 | struct ptlrpc_request **request) | |
1905 | { | |
1906 | struct obd_device *obd = exp->exp_obd; | |
1907 | struct lmv_obd *lmv = &obd->u.lmv; | |
1908 | struct lmv_tgt_desc *tgt; | |
1909 | int rc; | |
d7e09d03 PT |
1910 | |
1911 | rc = lmv_check_connect(obd); | |
1912 | if (rc) | |
0a3bdb00 | 1913 | return rc; |
d7e09d03 PT |
1914 | |
1915 | LASSERT(op_data->op_namelen != 0); | |
1916 | ||
1917 | CDEBUG(D_INODE, "LINK "DFID":%*s to "DFID"\n", | |
1918 | PFID(&op_data->op_fid2), op_data->op_namelen, | |
1919 | op_data->op_name, PFID(&op_data->op_fid1)); | |
1920 | ||
4b1a25f0 PT |
1921 | op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid()); |
1922 | op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid()); | |
d7e09d03 | 1923 | op_data->op_cap = cfs_curproc_cap_pack(); |
2de35386 | 1924 | if (op_data->op_mea2) { |
1925 | struct lmv_stripe_md *lsm = op_data->op_mea2; | |
1926 | const struct lmv_oinfo *oinfo; | |
1927 | ||
1928 | oinfo = lsm_name_to_stripe_info(lsm, op_data->op_name, | |
1929 | op_data->op_namelen); | |
79496845 | 1930 | if (IS_ERR(oinfo)) |
1931 | return PTR_ERR(oinfo); | |
1932 | ||
2de35386 | 1933 | op_data->op_fid2 = oinfo->lmo_fid; |
1934 | } | |
1935 | ||
d7e09d03 PT |
1936 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid2); |
1937 | if (IS_ERR(tgt)) | |
0a3bdb00 | 1938 | return PTR_ERR(tgt); |
d7e09d03 PT |
1939 | |
1940 | /* | |
1941 | * Cancel UPDATE lock on child (fid1). | |
1942 | */ | |
1943 | op_data->op_flags |= MF_MDC_CANCEL_FID2; | |
79496845 | 1944 | rc = lmv_early_cancel(exp, NULL, op_data, tgt->ltd_idx, LCK_EX, |
d7e09d03 PT |
1945 | MDS_INODELOCK_UPDATE, MF_MDC_CANCEL_FID1); |
1946 | if (rc != 0) | |
0a3bdb00 | 1947 | return rc; |
d7e09d03 PT |
1948 | |
1949 | rc = md_link(tgt->ltd_exp, op_data, request); | |
1950 | ||
0a3bdb00 | 1951 | return rc; |
d7e09d03 PT |
1952 | } |
1953 | ||
1954 | static int lmv_rename(struct obd_export *exp, struct md_op_data *op_data, | |
1955 | const char *old, int oldlen, const char *new, int newlen, | |
1956 | struct ptlrpc_request **request) | |
1957 | { | |
1958 | struct obd_device *obd = exp->exp_obd; | |
1959 | struct lmv_obd *lmv = &obd->u.lmv; | |
1960 | struct lmv_tgt_desc *src_tgt; | |
d7e09d03 | 1961 | int rc; |
d7e09d03 PT |
1962 | |
1963 | LASSERT(oldlen != 0); | |
1964 | ||
2de35386 | 1965 | CDEBUG(D_INODE, "RENAME %.*s in "DFID":%d to %.*s in "DFID":%d\n", |
d7e09d03 | 1966 | oldlen, old, PFID(&op_data->op_fid1), |
2de35386 | 1967 | op_data->op_mea1 ? op_data->op_mea1->lsm_md_stripe_count : 0, |
1968 | newlen, new, PFID(&op_data->op_fid2), | |
1969 | op_data->op_mea2 ? op_data->op_mea2->lsm_md_stripe_count : 0); | |
d7e09d03 PT |
1970 | |
1971 | rc = lmv_check_connect(obd); | |
1972 | if (rc) | |
0a3bdb00 | 1973 | return rc; |
d7e09d03 | 1974 | |
4b1a25f0 PT |
1975 | op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid()); |
1976 | op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid()); | |
d7e09d03 | 1977 | op_data->op_cap = cfs_curproc_cap_pack(); |
d7e09d03 | 1978 | |
79496845 | 1979 | if (op_data->op_cli_flags & CLI_MIGRATE) { |
1980 | LASSERTF(fid_is_sane(&op_data->op_fid3), "invalid FID "DFID"\n", | |
1981 | PFID(&op_data->op_fid3)); | |
8f18c8a4 | 1982 | rc = lmv_fid_alloc(NULL, exp, &op_data->op_fid2, op_data); |
79496845 | 1983 | if (rc) |
1984 | return rc; | |
1985 | src_tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid3); | |
2de35386 | 1986 | } else { |
79496845 | 1987 | if (op_data->op_mea1) { |
1988 | struct lmv_stripe_md *lsm = op_data->op_mea1; | |
1989 | ||
1990 | src_tgt = lmv_locate_target_for_name(lmv, lsm, old, | |
1991 | oldlen, | |
1992 | &op_data->op_fid1, | |
1993 | &op_data->op_mds); | |
1994 | if (IS_ERR(src_tgt)) | |
1995 | return PTR_ERR(src_tgt); | |
1996 | } else { | |
1997 | src_tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
1998 | if (IS_ERR(src_tgt)) | |
1999 | return PTR_ERR(src_tgt); | |
2de35386 | 2000 | |
79496845 | 2001 | op_data->op_mds = src_tgt->ltd_idx; |
2002 | } | |
2de35386 | 2003 | |
79496845 | 2004 | if (op_data->op_mea2) { |
2005 | struct lmv_stripe_md *lsm = op_data->op_mea2; | |
2006 | const struct lmv_oinfo *oinfo; | |
2de35386 | 2007 | |
79496845 | 2008 | oinfo = lsm_name_to_stripe_info(lsm, new, newlen); |
2009 | if (IS_ERR(oinfo)) | |
2010 | return PTR_ERR(oinfo); | |
2011 | ||
2012 | op_data->op_fid2 = oinfo->lmo_fid; | |
2013 | } | |
2de35386 | 2014 | } |
79496845 | 2015 | if (IS_ERR(src_tgt)) |
2016 | return PTR_ERR(src_tgt); | |
2de35386 | 2017 | |
d7e09d03 PT |
2018 | /* |
2019 | * LOOKUP lock on src child (fid3) should also be cancelled for | |
2020 | * src_tgt in mdc_rename. | |
2021 | */ | |
2022 | op_data->op_flags |= MF_MDC_CANCEL_FID1 | MF_MDC_CANCEL_FID3; | |
2023 | ||
2024 | /* | |
2025 | * Cancel UPDATE locks on tgt parent (fid2), tgt_tgt is its | |
2026 | * own target. | |
2027 | */ | |
79496845 | 2028 | rc = lmv_early_cancel(exp, NULL, op_data, src_tgt->ltd_idx, |
d7e09d03 PT |
2029 | LCK_EX, MDS_INODELOCK_UPDATE, |
2030 | MF_MDC_CANCEL_FID2); | |
79496845 | 2031 | if (rc) |
2032 | return rc; | |
d7e09d03 | 2033 | /* |
79496845 | 2034 | * Cancel LOOKUP locks on source child (fid3) for parent tgt_tgt. |
d7e09d03 | 2035 | */ |
79496845 | 2036 | if (fid_is_sane(&op_data->op_fid3)) { |
2037 | struct lmv_tgt_desc *tgt; | |
2038 | ||
2039 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
2040 | if (IS_ERR(tgt)) | |
2041 | return PTR_ERR(tgt); | |
2042 | ||
2043 | /* Cancel LOOKUP lock on its parent */ | |
2044 | rc = lmv_early_cancel(exp, tgt, op_data, src_tgt->ltd_idx, | |
d7e09d03 | 2045 | LCK_EX, MDS_INODELOCK_LOOKUP, |
79496845 | 2046 | MF_MDC_CANCEL_FID3); |
2047 | if (rc) | |
2048 | return rc; | |
2049 | ||
2050 | rc = lmv_early_cancel(exp, NULL, op_data, src_tgt->ltd_idx, | |
2051 | LCK_EX, MDS_INODELOCK_FULL, | |
2052 | MF_MDC_CANCEL_FID3); | |
2053 | if (rc) | |
2054 | return rc; | |
d7e09d03 PT |
2055 | } |
2056 | ||
2057 | /* | |
2058 | * Cancel all the locks on tgt child (fid4). | |
2059 | */ | |
79496845 | 2060 | if (fid_is_sane(&op_data->op_fid4)) |
2061 | rc = lmv_early_cancel(exp, NULL, op_data, src_tgt->ltd_idx, | |
d7e09d03 PT |
2062 | LCK_EX, MDS_INODELOCK_FULL, |
2063 | MF_MDC_CANCEL_FID4); | |
2064 | ||
75ac62fc | 2065 | CDEBUG(D_INODE, DFID":m%d to "DFID"\n", PFID(&op_data->op_fid1), |
2066 | op_data->op_mds, PFID(&op_data->op_fid2)); | |
2067 | ||
79496845 | 2068 | rc = md_rename(src_tgt->ltd_exp, op_data, old, oldlen, |
2069 | new, newlen, request); | |
0a3bdb00 | 2070 | return rc; |
d7e09d03 PT |
2071 | } |
2072 | ||
2073 | static int lmv_setattr(struct obd_export *exp, struct md_op_data *op_data, | |
2074 | void *ea, int ealen, void *ea2, int ea2len, | |
2075 | struct ptlrpc_request **request, | |
2076 | struct md_open_data **mod) | |
2077 | { | |
2078 | struct obd_device *obd = exp->exp_obd; | |
2079 | struct lmv_obd *lmv = &obd->u.lmv; | |
2080 | struct lmv_tgt_desc *tgt; | |
a84b7fd5 | 2081 | int rc; |
d7e09d03 PT |
2082 | |
2083 | rc = lmv_check_connect(obd); | |
2084 | if (rc) | |
0a3bdb00 | 2085 | return rc; |
d7e09d03 PT |
2086 | |
2087 | CDEBUG(D_INODE, "SETATTR for "DFID", valid 0x%x\n", | |
2088 | PFID(&op_data->op_fid1), op_data->op_attr.ia_valid); | |
2089 | ||
2090 | op_data->op_flags |= MF_MDC_CANCEL_FID1; | |
2091 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
2092 | if (IS_ERR(tgt)) | |
0a3bdb00 | 2093 | return PTR_ERR(tgt); |
d7e09d03 PT |
2094 | |
2095 | rc = md_setattr(tgt->ltd_exp, op_data, ea, ealen, ea2, | |
2096 | ea2len, request, mod); | |
2097 | ||
0a3bdb00 | 2098 | return rc; |
d7e09d03 PT |
2099 | } |
2100 | ||
2101 | static int lmv_sync(struct obd_export *exp, const struct lu_fid *fid, | |
ef2e0f55 | 2102 | struct ptlrpc_request **request) |
d7e09d03 PT |
2103 | { |
2104 | struct obd_device *obd = exp->exp_obd; | |
2105 | struct lmv_obd *lmv = &obd->u.lmv; | |
2106 | struct lmv_tgt_desc *tgt; | |
2107 | int rc; | |
d7e09d03 PT |
2108 | |
2109 | rc = lmv_check_connect(obd); | |
2110 | if (rc) | |
0a3bdb00 | 2111 | return rc; |
d7e09d03 PT |
2112 | |
2113 | tgt = lmv_find_target(lmv, fid); | |
2114 | if (IS_ERR(tgt)) | |
0a3bdb00 | 2115 | return PTR_ERR(tgt); |
d7e09d03 | 2116 | |
ef2e0f55 | 2117 | rc = md_sync(tgt->ltd_exp, fid, request); |
0a3bdb00 | 2118 | return rc; |
d7e09d03 PT |
2119 | } |
2120 | ||
7ccb7c8f | 2121 | /** |
2122 | * Get current minimum entry from striped directory | |
2123 | * | |
2124 | * This function will search the dir entry, whose hash value is the | |
2125 | * closest(>=) to @hash_offset, from all of sub-stripes, and it is | |
2126 | * only being called for striped directory. | |
2127 | * | |
2128 | * \param[in] exp export of LMV | |
2129 | * \param[in] op_data parameters transferred beween client MD stack | |
2130 | * stripe_information will be included in this | |
2131 | * parameter | |
2132 | * \param[in] cb_op ldlm callback being used in enqueue in | |
2133 | * mdc_read_page | |
2134 | * \param[in] hash_offset the hash value, which is used to locate | |
2135 | * minum(closet) dir entry | |
2136 | * \param[in|out] stripe_offset the caller use this to indicate the stripe | |
2137 | * index of last entry, so to avoid hash conflict | |
2138 | * between stripes. It will also be used to | |
2139 | * return the stripe index of current dir entry. | |
2140 | * \param[in|out] entp the minum entry and it also is being used | |
2141 | * to input the last dir entry to resolve the | |
2142 | * hash conflict | |
2143 | * | |
2144 | * \param[out] ppage the page which holds the minum entry | |
2145 | * | |
2146 | * \retval = 0 get the entry successfully | |
2147 | * negative errno (< 0) does not get the entry | |
2148 | */ | |
2149 | static int lmv_get_min_striped_entry(struct obd_export *exp, | |
2150 | struct md_op_data *op_data, | |
2151 | struct md_callback *cb_op, | |
2152 | __u64 hash_offset, int *stripe_offset, | |
2153 | struct lu_dirent **entp, | |
2154 | struct page **ppage) | |
2155 | { | |
2156 | struct lmv_stripe_md *lsm = op_data->op_mea1; | |
2157 | struct obd_device *obd = exp->exp_obd; | |
2158 | struct lmv_obd *lmv = &obd->u.lmv; | |
2159 | struct lu_dirent *min_ent = NULL; | |
2160 | struct page *min_page = NULL; | |
2161 | struct lmv_tgt_desc *tgt; | |
2162 | int stripe_count; | |
2163 | int min_idx = 0; | |
2164 | int rc = 0; | |
2165 | int i; | |
2166 | ||
2167 | stripe_count = lsm->lsm_md_stripe_count; | |
2168 | for (i = 0; i < stripe_count; i++) { | |
2169 | __u64 stripe_hash = hash_offset; | |
2170 | struct lu_dirent *ent = NULL; | |
2171 | struct page *page = NULL; | |
2172 | struct lu_dirpage *dp; | |
2173 | ||
2174 | tgt = lmv_get_target(lmv, lsm->lsm_md_oinfo[i].lmo_mds, NULL); | |
2175 | if (IS_ERR(tgt)) { | |
2176 | rc = PTR_ERR(tgt); | |
2177 | goto out; | |
2178 | } | |
2179 | ||
2180 | /* | |
2181 | * op_data will be shared by each stripe, so we need | |
2182 | * reset these value for each stripe | |
2183 | */ | |
2184 | op_data->op_fid1 = lsm->lsm_md_oinfo[i].lmo_fid; | |
2185 | op_data->op_fid2 = lsm->lsm_md_oinfo[i].lmo_fid; | |
2186 | op_data->op_data = lsm->lsm_md_oinfo[i].lmo_root; | |
2187 | next: | |
2188 | rc = md_read_page(tgt->ltd_exp, op_data, cb_op, stripe_hash, | |
2189 | &page); | |
2190 | if (rc) | |
2191 | goto out; | |
2192 | ||
2193 | dp = page_address(page); | |
2194 | for (ent = lu_dirent_start(dp); ent; | |
2195 | ent = lu_dirent_next(ent)) { | |
2196 | /* Skip dummy entry */ | |
2197 | if (!le16_to_cpu(ent->lde_namelen)) | |
2198 | continue; | |
2199 | ||
2200 | if (le64_to_cpu(ent->lde_hash) < hash_offset) | |
2201 | continue; | |
2202 | ||
2203 | if (le64_to_cpu(ent->lde_hash) == hash_offset && | |
2204 | (*entp == ent || i < *stripe_offset)) | |
2205 | continue; | |
2206 | ||
2207 | /* skip . and .. for other stripes */ | |
2208 | if (i && (!strncmp(ent->lde_name, ".", | |
2209 | le16_to_cpu(ent->lde_namelen)) || | |
2210 | !strncmp(ent->lde_name, "..", | |
2211 | le16_to_cpu(ent->lde_namelen)))) | |
2212 | continue; | |
2213 | break; | |
2214 | } | |
2215 | ||
2216 | if (!ent) { | |
2217 | stripe_hash = le64_to_cpu(dp->ldp_hash_end); | |
2218 | ||
2219 | kunmap(page); | |
2220 | put_page(page); | |
2221 | page = NULL; | |
2222 | ||
2223 | /* | |
2224 | * reach the end of current stripe, go to next stripe | |
2225 | */ | |
2226 | if (stripe_hash == MDS_DIR_END_OFF) | |
2227 | continue; | |
2228 | else | |
2229 | goto next; | |
2230 | } | |
2231 | ||
2232 | if (min_ent) { | |
2233 | if (le64_to_cpu(min_ent->lde_hash) > | |
2234 | le64_to_cpu(ent->lde_hash)) { | |
2235 | min_ent = ent; | |
2236 | kunmap(min_page); | |
2237 | put_page(min_page); | |
2238 | min_idx = i; | |
2239 | min_page = page; | |
2240 | } else { | |
2241 | kunmap(page); | |
2242 | put_page(page); | |
2243 | page = NULL; | |
2244 | } | |
2245 | } else { | |
2246 | min_ent = ent; | |
2247 | min_page = page; | |
2248 | min_idx = i; | |
2249 | } | |
2250 | } | |
2251 | ||
2252 | out: | |
2253 | if (*ppage) { | |
2254 | kunmap(*ppage); | |
2255 | put_page(*ppage); | |
2256 | } | |
2257 | *stripe_offset = min_idx; | |
2258 | *entp = min_ent; | |
2259 | *ppage = min_page; | |
2260 | return rc; | |
2261 | } | |
2262 | ||
2263 | /** | |
2264 | * Build dir entry page from a striped directory | |
2265 | * | |
2266 | * This function gets one entry by @offset from a striped directory. It will | |
2267 | * read entries from all of stripes, and choose one closest to the required | |
2268 | * offset(&offset). A few notes | |
2269 | * 1. skip . and .. for non-zero stripes, because there can only have one . | |
2270 | * and .. in a directory. | |
2271 | * 2. op_data will be shared by all of stripes, instead of allocating new | |
2272 | * one, so need to restore before reusing. | |
2273 | * 3. release the entry page if that is not being chosen. | |
2274 | * | |
2275 | * \param[in] exp obd export refer to LMV | |
2276 | * \param[in] op_data hold those MD parameters of read_entry | |
2277 | * \param[in] cb_op ldlm callback being used in enqueue in mdc_read_entry | |
2278 | * \param[out] ldp the entry being read | |
2279 | * \param[out] ppage the page holding the entry. Note: because the entry | |
2280 | * will be accessed in upper layer, so we need hold the | |
2281 | * page until the usages of entry is finished, see | |
2282 | * ll_dir_entry_next. | |
2283 | * | |
2284 | * retval =0 if get entry successfully | |
2285 | * <0 cannot get entry | |
2286 | */ | |
2287 | static int lmv_read_striped_page(struct obd_export *exp, | |
2288 | struct md_op_data *op_data, | |
2289 | struct md_callback *cb_op, | |
2290 | __u64 offset, struct page **ppage) | |
2291 | { | |
2292 | struct inode *master_inode = op_data->op_data; | |
2293 | struct lu_fid master_fid = op_data->op_fid1; | |
2294 | struct obd_device *obd = exp->exp_obd; | |
2295 | __u64 hash_offset = offset; | |
2296 | struct page *min_ent_page = NULL; | |
2297 | struct page *ent_page = NULL; | |
2298 | struct lu_dirent *min_ent = NULL; | |
2299 | struct lu_dirent *last_ent; | |
2300 | struct lu_dirent *ent; | |
2301 | struct lu_dirpage *dp; | |
2302 | size_t left_bytes; | |
2303 | int ent_idx = 0; | |
2304 | void *area; | |
2305 | int rc; | |
2306 | ||
2307 | rc = lmv_check_connect(obd); | |
2308 | if (rc) | |
2309 | return rc; | |
2310 | ||
2311 | /* | |
2312 | * Allocate a page and read entries from all of stripes and fill | |
2313 | * the page by hash order | |
2314 | */ | |
2315 | ent_page = alloc_page(GFP_KERNEL); | |
2316 | if (!ent_page) | |
2317 | return -ENOMEM; | |
2318 | ||
2319 | /* Initialize the entry page */ | |
2320 | dp = kmap(ent_page); | |
2321 | memset(dp, 0, sizeof(*dp)); | |
2322 | dp->ldp_hash_start = cpu_to_le64(offset); | |
2323 | dp->ldp_flags |= LDF_COLLIDE; | |
2324 | ||
2325 | area = dp + 1; | |
2326 | left_bytes = PAGE_SIZE - sizeof(*dp); | |
2327 | ent = area; | |
2328 | last_ent = ent; | |
2329 | do { | |
2330 | __u16 ent_size; | |
2331 | ||
2332 | /* Find the minum entry from all sub-stripes */ | |
2333 | rc = lmv_get_min_striped_entry(exp, op_data, cb_op, hash_offset, | |
2334 | &ent_idx, &min_ent, | |
2335 | &min_ent_page); | |
2336 | if (rc) | |
2337 | goto out; | |
2338 | ||
2339 | /* | |
2340 | * If it can not get minum entry, it means it already reaches | |
2341 | * the end of this directory | |
2342 | */ | |
2343 | if (!min_ent) { | |
2344 | last_ent->lde_reclen = 0; | |
2345 | hash_offset = MDS_DIR_END_OFF; | |
2346 | goto out; | |
2347 | } | |
2348 | ||
2349 | ent_size = le16_to_cpu(min_ent->lde_reclen); | |
2350 | ||
2351 | /* | |
2352 | * the last entry lde_reclen is 0, but it might not | |
2353 | * the end of this entry of this temporay entry | |
2354 | */ | |
2355 | if (!ent_size) | |
2356 | ent_size = lu_dirent_calc_size( | |
2357 | le16_to_cpu(min_ent->lde_namelen), | |
2358 | le32_to_cpu(min_ent->lde_attrs)); | |
2359 | if (ent_size > left_bytes) { | |
2360 | last_ent->lde_reclen = cpu_to_le16(0); | |
2361 | hash_offset = le64_to_cpu(min_ent->lde_hash); | |
2362 | goto out; | |
2363 | } | |
2364 | ||
2365 | memcpy(ent, min_ent, ent_size); | |
2366 | ||
2367 | /* | |
2368 | * Replace . with master FID and Replace .. with the parent FID | |
2369 | * of master object | |
2370 | */ | |
2371 | if (!strncmp(ent->lde_name, ".", | |
2372 | le16_to_cpu(ent->lde_namelen)) && | |
2373 | le16_to_cpu(ent->lde_namelen) == 1) | |
2374 | fid_cpu_to_le(&ent->lde_fid, &master_fid); | |
2375 | else if (!strncmp(ent->lde_name, "..", | |
2376 | le16_to_cpu(ent->lde_namelen)) && | |
2377 | le16_to_cpu(ent->lde_namelen) == 2) | |
2378 | fid_cpu_to_le(&ent->lde_fid, &op_data->op_fid3); | |
2379 | ||
2380 | left_bytes -= ent_size; | |
2381 | ent->lde_reclen = cpu_to_le16(ent_size); | |
2382 | last_ent = ent; | |
2383 | ent = (void *)ent + ent_size; | |
2384 | hash_offset = le64_to_cpu(min_ent->lde_hash); | |
2385 | if (hash_offset == MDS_DIR_END_OFF) { | |
2386 | last_ent->lde_reclen = 0; | |
2387 | break; | |
2388 | } | |
2389 | } while (1); | |
2390 | out: | |
2391 | if (min_ent_page) { | |
2392 | kunmap(min_ent_page); | |
2393 | put_page(min_ent_page); | |
2394 | } | |
2395 | ||
2396 | if (unlikely(rc)) { | |
2397 | __free_page(ent_page); | |
2398 | ent_page = NULL; | |
2399 | } else { | |
2400 | if (ent == area) | |
2401 | dp->ldp_flags |= LDF_EMPTY; | |
2402 | dp->ldp_flags = cpu_to_le32(dp->ldp_flags); | |
2403 | dp->ldp_hash_end = cpu_to_le64(hash_offset); | |
2404 | } | |
2405 | ||
2406 | /* | |
2407 | * We do not want to allocate md_op_data during each | |
2408 | * dir entry reading, so op_data will be shared by every stripe, | |
2409 | * then we need to restore it back to original value before | |
2410 | * return to the upper layer | |
2411 | */ | |
2412 | op_data->op_fid1 = master_fid; | |
2413 | op_data->op_fid2 = master_fid; | |
2414 | op_data->op_data = master_inode; | |
2415 | ||
2416 | *ppage = ent_page; | |
2417 | ||
2418 | return rc; | |
2419 | } | |
2420 | ||
2421 | int lmv_read_page(struct obd_export *exp, struct md_op_data *op_data, | |
2422 | struct md_callback *cb_op, __u64 offset, | |
2423 | struct page **ppage) | |
2424 | { | |
2425 | struct lmv_stripe_md *lsm = op_data->op_mea1; | |
2426 | struct obd_device *obd = exp->exp_obd; | |
2427 | struct lmv_obd *lmv = &obd->u.lmv; | |
2428 | struct lmv_tgt_desc *tgt; | |
2429 | int rc; | |
2430 | ||
2431 | rc = lmv_check_connect(obd); | |
2432 | if (rc) | |
2433 | return rc; | |
2434 | ||
2435 | if (unlikely(lsm)) { | |
2436 | rc = lmv_read_striped_page(exp, op_data, cb_op, offset, ppage); | |
2437 | return rc; | |
2438 | } | |
2439 | ||
2440 | tgt = lmv_find_target(lmv, &op_data->op_fid1); | |
2441 | if (IS_ERR(tgt)) | |
2442 | return PTR_ERR(tgt); | |
2443 | ||
2444 | rc = md_read_page(tgt->ltd_exp, op_data, cb_op, offset, ppage); | |
2445 | ||
2446 | return rc; | |
2447 | } | |
2448 | ||
893ab747 | 2449 | /** |
2450 | * Unlink a file/directory | |
2451 | * | |
2452 | * Unlink a file or directory under the parent dir. The unlink request | |
2453 | * usually will be sent to the MDT where the child is located, but if | |
2454 | * the client does not have the child FID then request will be sent to the | |
2455 | * MDT where the parent is located. | |
2456 | * | |
2457 | * If the parent is a striped directory then it also needs to locate which | |
2458 | * stripe the name of the child is located, and replace the parent FID | |
2459 | * (@op->op_fid1) with the stripe FID. Note: if the stripe is unknown, | |
2460 | * it will walk through all of sub-stripes until the child is being | |
2461 | * unlinked finally. | |
2462 | * | |
2463 | * \param[in] exp export refer to LMV | |
2464 | * \param[in] op_data different parameters transferred beween client | |
2465 | * MD stacks, name, namelen, FIDs etc. | |
2466 | * op_fid1 is the parent FID, op_fid2 is the child | |
2467 | * FID. | |
2468 | * \param[out] request point to the request of unlink. | |
2469 | * | |
2470 | * retval 0 if succeed | |
2471 | * negative errno if failed. | |
2472 | */ | |
d7e09d03 PT |
2473 | static int lmv_unlink(struct obd_export *exp, struct md_op_data *op_data, |
2474 | struct ptlrpc_request **request) | |
2475 | { | |
893ab747 | 2476 | struct lmv_stripe_md *lsm = op_data->op_mea1; |
2477 | struct obd_device *obd = exp->exp_obd; | |
d7e09d03 | 2478 | struct lmv_obd *lmv = &obd->u.lmv; |
79496845 | 2479 | struct lmv_tgt_desc *parent_tgt = NULL; |
d7e09d03 PT |
2480 | struct lmv_tgt_desc *tgt = NULL; |
2481 | struct mdt_body *body; | |
893ab747 | 2482 | int stripe_index = 0; |
d7e09d03 | 2483 | int rc; |
d7e09d03 PT |
2484 | |
2485 | rc = lmv_check_connect(obd); | |
2486 | if (rc) | |
0a3bdb00 | 2487 | return rc; |
893ab747 | 2488 | retry_unlink: |
2489 | /* For striped dir, we need to locate the parent as well */ | |
2490 | if (lsm) { | |
2491 | struct lmv_tgt_desc *tmp; | |
75ac62fc | 2492 | |
893ab747 | 2493 | LASSERT(op_data->op_name && op_data->op_namelen); |
2494 | ||
2495 | tmp = lmv_locate_target_for_name(lmv, lsm, | |
2496 | op_data->op_name, | |
2497 | op_data->op_namelen, | |
2498 | &op_data->op_fid1, | |
2499 | &op_data->op_mds); | |
2500 | ||
2501 | /* | |
2502 | * return -EBADFD means unknown hash type, might | |
2503 | * need try all sub-stripe here | |
2504 | */ | |
2505 | if (IS_ERR(tmp) && PTR_ERR(tmp) != -EBADFD) | |
2506 | return PTR_ERR(tmp); | |
2507 | ||
2508 | /* | |
2509 | * Note: both migrating dir and unknown hash dir need to | |
2510 | * try all of sub-stripes, so we need start search the | |
2511 | * name from stripe 0, but migrating dir is already handled | |
2512 | * inside lmv_locate_target_for_name(), so we only check | |
2513 | * unknown hash type directory here | |
2514 | */ | |
2515 | if (!lmv_is_known_hash_type(lsm)) { | |
2516 | struct lmv_oinfo *oinfo; | |
2517 | ||
2518 | oinfo = &lsm->lsm_md_oinfo[stripe_index]; | |
2519 | ||
2520 | op_data->op_fid1 = oinfo->lmo_fid; | |
2521 | op_data->op_mds = oinfo->lmo_mds; | |
75ac62fc | 2522 | } |
75ac62fc | 2523 | } |
d7e09d03 | 2524 | |
893ab747 | 2525 | try_next_stripe: |
2526 | /* Send unlink requests to the MDT where the child is located */ | |
2527 | if (likely(!fid_is_zero(&op_data->op_fid2))) | |
2528 | tgt = lmv_find_target(lmv, &op_data->op_fid2); | |
2529 | else if (lsm) | |
2530 | tgt = lmv_get_target(lmv, op_data->op_mds, NULL); | |
2531 | else | |
2532 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); | |
2533 | ||
2534 | if (IS_ERR(tgt)) | |
2535 | return PTR_ERR(tgt); | |
2536 | ||
4b1a25f0 PT |
2537 | op_data->op_fsuid = from_kuid(&init_user_ns, current_fsuid()); |
2538 | op_data->op_fsgid = from_kgid(&init_user_ns, current_fsgid()); | |
d7e09d03 PT |
2539 | op_data->op_cap = cfs_curproc_cap_pack(); |
2540 | ||
2541 | /* | |
2542 | * If child's fid is given, cancel unused locks for it if it is from | |
2543 | * another export than parent. | |
2544 | * | |
2545 | * LOOKUP lock for child (fid3) should also be cancelled on parent | |
2546 | * tgt_tgt in mdc_unlink(). | |
2547 | */ | |
2548 | op_data->op_flags |= MF_MDC_CANCEL_FID1 | MF_MDC_CANCEL_FID3; | |
2549 | ||
2550 | /* | |
2551 | * Cancel FULL locks on child (fid3). | |
2552 | */ | |
79496845 | 2553 | parent_tgt = lmv_find_target(lmv, &op_data->op_fid1); |
2554 | if (IS_ERR(parent_tgt)) | |
2555 | return PTR_ERR(parent_tgt); | |
2556 | ||
2557 | if (parent_tgt != tgt) { | |
2558 | rc = lmv_early_cancel(exp, parent_tgt, op_data, tgt->ltd_idx, | |
2559 | LCK_EX, MDS_INODELOCK_LOOKUP, | |
2560 | MF_MDC_CANCEL_FID3); | |
2561 | } | |
d7e09d03 | 2562 | |
79496845 | 2563 | rc = lmv_early_cancel(exp, NULL, op_data, tgt->ltd_idx, LCK_EX, |
2564 | MDS_INODELOCK_FULL, MF_MDC_CANCEL_FID3); | |
d7e09d03 | 2565 | if (rc != 0) |
0a3bdb00 | 2566 | return rc; |
d7e09d03 PT |
2567 | |
2568 | CDEBUG(D_INODE, "unlink with fid="DFID"/"DFID" -> mds #%d\n", | |
2569 | PFID(&op_data->op_fid1), PFID(&op_data->op_fid2), tgt->ltd_idx); | |
2570 | ||
2571 | rc = md_unlink(tgt->ltd_exp, op_data, request); | |
893ab747 | 2572 | if (rc != 0 && rc != -EREMOTE && rc != -ENOENT) |
0a3bdb00 | 2573 | return rc; |
d7e09d03 | 2574 | |
893ab747 | 2575 | /* Try next stripe if it is needed. */ |
2576 | if (rc == -ENOENT && lsm && lmv_need_try_all_stripes(lsm)) { | |
2577 | struct lmv_oinfo *oinfo; | |
2578 | ||
2579 | stripe_index++; | |
2580 | if (stripe_index >= lsm->lsm_md_stripe_count) | |
2581 | return rc; | |
2582 | ||
2583 | oinfo = &lsm->lsm_md_oinfo[stripe_index]; | |
2584 | ||
2585 | op_data->op_fid1 = oinfo->lmo_fid; | |
2586 | op_data->op_mds = oinfo->lmo_mds; | |
2587 | ||
2588 | ptlrpc_req_finished(*request); | |
2589 | *request = NULL; | |
2590 | ||
2591 | goto try_next_stripe; | |
2592 | } | |
2593 | ||
d7e09d03 | 2594 | body = req_capsule_server_get(&(*request)->rq_pill, &RMF_MDT_BODY); |
2cbdaa45 | 2595 | if (!body) |
0a3bdb00 | 2596 | return -EPROTO; |
d7e09d03 PT |
2597 | |
2598 | /* Not cross-ref case, just get out of here. */ | |
2e1b5b8b | 2599 | if (likely(!(body->mbo_valid & OBD_MD_MDS))) |
0a3bdb00 | 2600 | return 0; |
d7e09d03 PT |
2601 | |
2602 | CDEBUG(D_INODE, "%s: try unlink to another MDT for "DFID"\n", | |
2e1b5b8b | 2603 | exp->exp_obd->obd_name, PFID(&body->mbo_fid1)); |
d7e09d03 PT |
2604 | |
2605 | /* This is a remote object, try remote MDT, Note: it may | |
2606 | * try more than 1 time here, Considering following case | |
2607 | * /mnt/lustre is root on MDT0, remote1 is on MDT1 | |
2608 | * 1. Initially A does not know where remote1 is, it send | |
2609 | * unlink RPC to MDT0, MDT0 return -EREMOTE, it will | |
2610 | * resend unlink RPC to MDT1 (retry 1st time). | |
2611 | * | |
2612 | * 2. During the unlink RPC in flight, | |
2613 | * client B mv /mnt/lustre/remote1 /mnt/lustre/remote2 | |
2614 | * and create new remote1, but on MDT0 | |
2615 | * | |
2616 | * 3. MDT1 get unlink RPC(from A), then do remote lock on | |
2617 | * /mnt/lustre, then lookup get fid of remote1, and find | |
2618 | * it is remote dir again, and replay -EREMOTE again. | |
2619 | * | |
2620 | * 4. Then A will resend unlink RPC to MDT0. (retry 2nd times). | |
2621 | * | |
2622 | * In theory, it might try unlimited time here, but it should | |
7f05d5bb OD |
2623 | * be very rare case. |
2624 | */ | |
2e1b5b8b | 2625 | op_data->op_fid2 = body->mbo_fid1; |
d7e09d03 PT |
2626 | ptlrpc_req_finished(*request); |
2627 | *request = NULL; | |
2628 | ||
893ab747 | 2629 | goto retry_unlink; |
d7e09d03 PT |
2630 | } |
2631 | ||
2632 | static int lmv_precleanup(struct obd_device *obd, enum obd_cleanup_stage stage) | |
2633 | { | |
2634 | struct lmv_obd *lmv = &obd->u.lmv; | |
d7e09d03 PT |
2635 | |
2636 | switch (stage) { | |
2637 | case OBD_CLEANUP_EARLY: | |
2638 | /* XXX: here should be calling obd_precleanup() down to | |
7f05d5bb OD |
2639 | * stack. |
2640 | */ | |
d7e09d03 PT |
2641 | break; |
2642 | case OBD_CLEANUP_EXPORTS: | |
82765049 | 2643 | fld_client_debugfs_fini(&lmv->lmv_fld); |
d7e09d03 PT |
2644 | lprocfs_obd_cleanup(obd); |
2645 | break; | |
2646 | default: | |
2647 | break; | |
2648 | } | |
5ed57d6d | 2649 | return 0; |
d7e09d03 PT |
2650 | } |
2651 | ||
2652 | static int lmv_get_info(const struct lu_env *env, struct obd_export *exp, | |
2653 | __u32 keylen, void *key, __u32 *vallen, void *val, | |
2654 | struct lov_stripe_md *lsm) | |
2655 | { | |
2656 | struct obd_device *obd; | |
2657 | struct lmv_obd *lmv; | |
2658 | int rc = 0; | |
d7e09d03 PT |
2659 | |
2660 | obd = class_exp2obd(exp); | |
2cbdaa45 | 2661 | if (!obd) { |
55f5a824 | 2662 | CDEBUG(D_IOCTL, "Invalid client cookie %#llx\n", |
d7e09d03 | 2663 | exp->exp_handle.h_cookie); |
0a3bdb00 | 2664 | return -EINVAL; |
d7e09d03 PT |
2665 | } |
2666 | ||
2667 | lmv = &obd->u.lmv; | |
2668 | if (keylen >= strlen("remote_flag") && !strcmp(key, "remote_flag")) { | |
d7e09d03 PT |
2669 | int i; |
2670 | ||
2671 | rc = lmv_check_connect(obd); | |
2672 | if (rc) | |
0a3bdb00 | 2673 | return rc; |
d7e09d03 PT |
2674 | |
2675 | LASSERT(*vallen == sizeof(__u32)); | |
2676 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
0fdd2b8d DE |
2677 | struct lmv_tgt_desc *tgt = lmv->tgts[i]; |
2678 | ||
d7e09d03 PT |
2679 | /* |
2680 | * All tgts should be connected when this gets called. | |
2681 | */ | |
2cbdaa45 | 2682 | if (!tgt || !tgt->ltd_exp) |
d7e09d03 PT |
2683 | continue; |
2684 | ||
2685 | if (!obd_get_info(env, tgt->ltd_exp, keylen, key, | |
2686 | vallen, val, NULL)) | |
0a3bdb00 | 2687 | return 0; |
d7e09d03 | 2688 | } |
0a3bdb00 | 2689 | return -EINVAL; |
44779340 BB |
2690 | } else if (KEY_IS(KEY_MAX_EASIZE) || |
2691 | KEY_IS(KEY_DEFAULT_EASIZE) || | |
44779340 | 2692 | KEY_IS(KEY_CONN_DATA)) { |
d7e09d03 PT |
2693 | rc = lmv_check_connect(obd); |
2694 | if (rc) | |
0a3bdb00 | 2695 | return rc; |
d7e09d03 PT |
2696 | |
2697 | /* | |
2698 | * Forwarding this request to first MDS, it should know LOV | |
2699 | * desc. | |
2700 | */ | |
2701 | rc = obd_get_info(env, lmv->tgts[0]->ltd_exp, keylen, key, | |
2702 | vallen, val, NULL); | |
2703 | if (!rc && KEY_IS(KEY_CONN_DATA)) | |
2704 | exp->exp_connect_data = *(struct obd_connect_data *)val; | |
0a3bdb00 | 2705 | return rc; |
d7e09d03 PT |
2706 | } else if (KEY_IS(KEY_TGT_COUNT)) { |
2707 | *((int *)val) = lmv->desc.ld_tgt_count; | |
0a3bdb00 | 2708 | return 0; |
d7e09d03 PT |
2709 | } |
2710 | ||
2711 | CDEBUG(D_IOCTL, "Invalid key\n"); | |
0a3bdb00 | 2712 | return -EINVAL; |
d7e09d03 PT |
2713 | } |
2714 | ||
5dc8d7b4 LC |
2715 | static int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp, |
2716 | u32 keylen, void *key, u32 vallen, | |
2717 | void *val, struct ptlrpc_request_set *set) | |
d7e09d03 PT |
2718 | { |
2719 | struct lmv_tgt_desc *tgt; | |
2720 | struct obd_device *obd; | |
2721 | struct lmv_obd *lmv; | |
2722 | int rc = 0; | |
d7e09d03 PT |
2723 | |
2724 | obd = class_exp2obd(exp); | |
2cbdaa45 | 2725 | if (!obd) { |
55f5a824 | 2726 | CDEBUG(D_IOCTL, "Invalid client cookie %#llx\n", |
d7e09d03 | 2727 | exp->exp_handle.h_cookie); |
0a3bdb00 | 2728 | return -EINVAL; |
d7e09d03 PT |
2729 | } |
2730 | lmv = &obd->u.lmv; | |
2731 | ||
2732 | if (KEY_IS(KEY_READ_ONLY) || KEY_IS(KEY_FLUSH_CTX)) { | |
2733 | int i, err = 0; | |
2734 | ||
2735 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
2736 | tgt = lmv->tgts[i]; | |
2737 | ||
2cbdaa45 | 2738 | if (!tgt || !tgt->ltd_exp) |
d7e09d03 PT |
2739 | continue; |
2740 | ||
2741 | err = obd_set_info_async(env, tgt->ltd_exp, | |
2742 | keylen, key, vallen, val, set); | |
2743 | if (err && rc == 0) | |
2744 | rc = err; | |
2745 | } | |
2746 | ||
0a3bdb00 | 2747 | return rc; |
d7e09d03 PT |
2748 | } |
2749 | ||
0a3bdb00 | 2750 | return -EINVAL; |
d7e09d03 PT |
2751 | } |
2752 | ||
fad3a392 | 2753 | static int lmv_pack_md_v1(const struct lmv_stripe_md *lsm, |
2754 | struct lmv_mds_md_v1 *lmm1) | |
d7e09d03 | 2755 | { |
fad3a392 | 2756 | int cplen; |
2757 | int i; | |
2758 | ||
2759 | lmm1->lmv_magic = cpu_to_le32(lsm->lsm_md_magic); | |
2760 | lmm1->lmv_stripe_count = cpu_to_le32(lsm->lsm_md_stripe_count); | |
2761 | lmm1->lmv_master_mdt_index = cpu_to_le32(lsm->lsm_md_master_mdt_index); | |
2762 | lmm1->lmv_hash_type = cpu_to_le32(lsm->lsm_md_hash_type); | |
2763 | cplen = strlcpy(lmm1->lmv_pool_name, lsm->lsm_md_pool_name, | |
2764 | sizeof(lmm1->lmv_pool_name)); | |
2765 | if (cplen >= sizeof(lmm1->lmv_pool_name)) | |
2766 | return -E2BIG; | |
2767 | ||
2768 | for (i = 0; i < lsm->lsm_md_stripe_count; i++) | |
2769 | fid_cpu_to_le(&lmm1->lmv_stripe_fids[i], | |
2770 | &lsm->lsm_md_oinfo[i].lmo_fid); | |
2771 | return 0; | |
2772 | } | |
2773 | ||
2774 | int lmv_pack_md(union lmv_mds_md **lmmp, const struct lmv_stripe_md *lsm, | |
2775 | int stripe_count) | |
2776 | { | |
2777 | int lmm_size = 0, rc = 0; | |
2778 | bool allocated = false; | |
d7e09d03 | 2779 | |
fad3a392 | 2780 | LASSERT(lmmp); |
d7e09d03 | 2781 | |
fad3a392 | 2782 | /* Free lmm */ |
d7e09d03 | 2783 | if (*lmmp && !lsm) { |
fad3a392 | 2784 | int stripe_cnt; |
2785 | ||
2786 | stripe_cnt = lmv_mds_md_stripe_count_get(*lmmp); | |
2787 | lmm_size = lmv_mds_md_size(stripe_cnt, | |
2788 | le32_to_cpu((*lmmp)->lmv_magic)); | |
2789 | if (!lmm_size) | |
2790 | return -EINVAL; | |
8cc3792a | 2791 | kvfree(*lmmp); |
d7e09d03 | 2792 | *lmmp = NULL; |
0a3bdb00 | 2793 | return 0; |
d7e09d03 PT |
2794 | } |
2795 | ||
fad3a392 | 2796 | /* Alloc lmm */ |
2797 | if (!*lmmp && !lsm) { | |
2798 | lmm_size = lmv_mds_md_size(stripe_count, LMV_MAGIC); | |
2799 | LASSERT(lmm_size > 0); | |
2800 | *lmmp = libcfs_kvzalloc(lmm_size, GFP_NOFS); | |
2801 | if (!*lmmp) | |
2802 | return -ENOMEM; | |
2803 | lmv_mds_md_stripe_count_set(*lmmp, stripe_count); | |
2804 | (*lmmp)->lmv_magic = cpu_to_le32(LMV_MAGIC); | |
2805 | return lmm_size; | |
2806 | } | |
2807 | ||
2808 | /* pack lmm */ | |
2809 | LASSERT(lsm); | |
2810 | lmm_size = lmv_mds_md_size(lsm->lsm_md_stripe_count, | |
2811 | lsm->lsm_md_magic); | |
2cbdaa45 | 2812 | if (!*lmmp) { |
fad3a392 | 2813 | *lmmp = libcfs_kvzalloc(lmm_size, GFP_NOFS); |
2cbdaa45 | 2814 | if (!*lmmp) |
0a3bdb00 | 2815 | return -ENOMEM; |
fad3a392 | 2816 | allocated = true; |
d7e09d03 PT |
2817 | } |
2818 | ||
fad3a392 | 2819 | switch (lsm->lsm_md_magic) { |
2820 | case LMV_MAGIC_V1: | |
2821 | rc = lmv_pack_md_v1(lsm, &(*lmmp)->lmv_md_v1); | |
2822 | break; | |
2823 | default: | |
2824 | rc = -EINVAL; | |
2825 | break; | |
2826 | } | |
d7e09d03 | 2827 | |
fad3a392 | 2828 | if (rc && allocated) { |
2829 | kvfree(*lmmp); | |
2830 | *lmmp = NULL; | |
2831 | } | |
d7e09d03 | 2832 | |
fad3a392 | 2833 | return lmm_size; |
2834 | } | |
2835 | EXPORT_SYMBOL(lmv_pack_md); | |
d7e09d03 | 2836 | |
fad3a392 | 2837 | static int lmv_unpack_md_v1(struct obd_export *exp, struct lmv_stripe_md *lsm, |
2838 | const struct lmv_mds_md_v1 *lmm1) | |
2839 | { | |
2840 | struct lmv_obd *lmv = &exp->exp_obd->u.lmv; | |
2841 | int stripe_count; | |
2842 | int rc = 0; | |
2843 | int cplen; | |
2844 | int i; | |
d7e09d03 | 2845 | |
fad3a392 | 2846 | lsm->lsm_md_magic = le32_to_cpu(lmm1->lmv_magic); |
2847 | lsm->lsm_md_stripe_count = le32_to_cpu(lmm1->lmv_stripe_count); | |
2848 | lsm->lsm_md_master_mdt_index = le32_to_cpu(lmm1->lmv_master_mdt_index); | |
893ab747 | 2849 | if (OBD_FAIL_CHECK(OBD_FAIL_UNKNOWN_LMV_STRIPE)) |
2850 | lsm->lsm_md_hash_type = LMV_HASH_TYPE_UNKNOWN; | |
2851 | else | |
2852 | lsm->lsm_md_hash_type = le32_to_cpu(lmm1->lmv_hash_type); | |
fad3a392 | 2853 | lsm->lsm_md_layout_version = le32_to_cpu(lmm1->lmv_layout_version); |
2854 | cplen = strlcpy(lsm->lsm_md_pool_name, lmm1->lmv_pool_name, | |
2855 | sizeof(lsm->lsm_md_pool_name)); | |
2856 | ||
2857 | if (cplen >= sizeof(lsm->lsm_md_pool_name)) | |
2858 | return -E2BIG; | |
2859 | ||
2860 | CDEBUG(D_INFO, "unpack lsm count %d, master %d hash_type %d layout_version %d\n", | |
2861 | lsm->lsm_md_stripe_count, lsm->lsm_md_master_mdt_index, | |
2862 | lsm->lsm_md_hash_type, lsm->lsm_md_layout_version); | |
2863 | ||
2864 | stripe_count = le32_to_cpu(lmm1->lmv_stripe_count); | |
2865 | for (i = 0; i < le32_to_cpu(stripe_count); i++) { | |
2866 | fid_le_to_cpu(&lsm->lsm_md_oinfo[i].lmo_fid, | |
2867 | &lmm1->lmv_stripe_fids[i]); | |
2868 | rc = lmv_fld_lookup(lmv, &lsm->lsm_md_oinfo[i].lmo_fid, | |
2869 | &lsm->lsm_md_oinfo[i].lmo_mds); | |
2870 | if (rc) | |
2871 | return rc; | |
2872 | CDEBUG(D_INFO, "unpack fid #%d "DFID"\n", i, | |
2873 | PFID(&lsm->lsm_md_oinfo[i].lmo_fid)); | |
d7e09d03 PT |
2874 | } |
2875 | ||
fad3a392 | 2876 | return rc; |
d7e09d03 PT |
2877 | } |
2878 | ||
fad3a392 | 2879 | int lmv_unpack_md(struct obd_export *exp, struct lmv_stripe_md **lsmp, |
2880 | const union lmv_mds_md *lmm, int stripe_count) | |
d7e09d03 | 2881 | { |
fad3a392 | 2882 | struct lmv_stripe_md *lsm; |
2883 | bool allocated = false; | |
2884 | int lsm_size, rc; | |
2885 | ||
2886 | LASSERT(lsmp); | |
2887 | ||
2888 | lsm = *lsmp; | |
2889 | /* Free memmd */ | |
2890 | if (lsm && !lmm) { | |
2891 | int i; | |
d7e09d03 | 2892 | |
fad3a392 | 2893 | for (i = 1; i < lsm->lsm_md_stripe_count; i++) { |
8f18c8a4 | 2894 | /* |
2895 | * For migrating inode, the master stripe and master | |
2896 | * object will be the same, so do not need iput, see | |
2897 | * ll_update_lsm_md | |
2898 | */ | |
2899 | if (!(lsm->lsm_md_hash_type & LMV_HASH_FLAG_MIGRATION && | |
2900 | !i) && lsm->lsm_md_oinfo[i].lmo_root) | |
fad3a392 | 2901 | iput(lsm->lsm_md_oinfo[i].lmo_root); |
2902 | } | |
d7e09d03 | 2903 | |
fad3a392 | 2904 | kvfree(lsm); |
d7e09d03 | 2905 | *lsmp = NULL; |
0a3bdb00 | 2906 | return 0; |
d7e09d03 PT |
2907 | } |
2908 | ||
fad3a392 | 2909 | /* Alloc memmd */ |
2910 | if (!lsm && !lmm) { | |
2911 | lsm_size = lmv_stripe_md_size(stripe_count); | |
2912 | lsm = libcfs_kvzalloc(lsm_size, GFP_NOFS); | |
2913 | if (!lsm) | |
2914 | return -ENOMEM; | |
2915 | lsm->lsm_md_stripe_count = stripe_count; | |
2916 | *lsmp = lsm; | |
2917 | return 0; | |
2918 | } | |
d7e09d03 | 2919 | |
8f18c8a4 | 2920 | if (le32_to_cpu(lmm->lmv_magic) == LMV_MAGIC_STRIPE) |
2921 | return -EPERM; | |
2922 | ||
fad3a392 | 2923 | /* Unpack memmd */ |
79496845 | 2924 | if (le32_to_cpu(lmm->lmv_magic) != LMV_MAGIC_V1 && |
79496845 | 2925 | le32_to_cpu(lmm->lmv_magic) != LMV_USER_MAGIC) { |
2926 | CERROR("%s: invalid lmv magic %x: rc = %d\n", | |
2927 | exp->exp_obd->obd_name, le32_to_cpu(lmm->lmv_magic), | |
2928 | -EIO); | |
2929 | return -EIO; | |
fad3a392 | 2930 | } |
d7e09d03 | 2931 | |
8f18c8a4 | 2932 | if (le32_to_cpu(lmm->lmv_magic) == LMV_MAGIC_V1) |
79496845 | 2933 | lsm_size = lmv_stripe_md_size(lmv_mds_md_stripe_count_get(lmm)); |
2934 | else | |
2935 | /** | |
2936 | * Unpack default dirstripe(lmv_user_md) to lmv_stripe_md, | |
2937 | * stripecount should be 0 then. | |
2938 | */ | |
2939 | lsm_size = lmv_stripe_md_size(0); | |
2940 | ||
fad3a392 | 2941 | if (!lsm) { |
2942 | lsm = libcfs_kvzalloc(lsm_size, GFP_NOFS); | |
2943 | if (!lsm) | |
2944 | return -ENOMEM; | |
2945 | allocated = true; | |
2946 | *lsmp = lsm; | |
2947 | } | |
d7e09d03 | 2948 | |
fad3a392 | 2949 | switch (le32_to_cpu(lmm->lmv_magic)) { |
2950 | case LMV_MAGIC_V1: | |
2951 | rc = lmv_unpack_md_v1(exp, lsm, &lmm->lmv_md_v1); | |
2952 | break; | |
2953 | default: | |
2954 | CERROR("%s: unrecognized magic %x\n", exp->exp_obd->obd_name, | |
2955 | le32_to_cpu(lmm->lmv_magic)); | |
2956 | rc = -EINVAL; | |
2957 | break; | |
d7e09d03 PT |
2958 | } |
2959 | ||
fad3a392 | 2960 | if (rc && allocated) { |
2961 | kvfree(lsm); | |
2962 | *lsmp = NULL; | |
2963 | lsm_size = rc; | |
2964 | } | |
2965 | return lsm_size; | |
2966 | } | |
2de35386 | 2967 | EXPORT_SYMBOL(lmv_unpack_md); |
d7e09d03 | 2968 | |
fad3a392 | 2969 | int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp, |
2970 | struct lov_mds_md *lmm, int disk_len) | |
2971 | { | |
2972 | return lmv_unpack_md(exp, (struct lmv_stripe_md **)lsmp, | |
2973 | (union lmv_mds_md *)lmm, disk_len); | |
2974 | } | |
2975 | ||
2976 | int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp, | |
2977 | struct lov_stripe_md *lsm) | |
2978 | { | |
2979 | const struct lmv_stripe_md *lmv = (struct lmv_stripe_md *)lsm; | |
2980 | struct obd_device *obd = exp->exp_obd; | |
2981 | struct lmv_obd *lmv_obd = &obd->u.lmv; | |
2982 | int stripe_count; | |
2983 | ||
2984 | if (!lmmp) { | |
2985 | if (lsm) | |
2986 | stripe_count = lmv->lsm_md_stripe_count; | |
2987 | else | |
2988 | stripe_count = lmv_obd->desc.ld_tgt_count; | |
2989 | ||
2990 | return lmv_mds_md_size(stripe_count, LMV_MAGIC_V1); | |
d7e09d03 | 2991 | } |
fad3a392 | 2992 | |
2993 | return lmv_pack_md((union lmv_mds_md **)lmmp, lmv, 0); | |
d7e09d03 PT |
2994 | } |
2995 | ||
2996 | static int lmv_cancel_unused(struct obd_export *exp, const struct lu_fid *fid, | |
52ee0d20 | 2997 | ldlm_policy_data_t *policy, enum ldlm_mode mode, |
f833ee42 | 2998 | enum ldlm_cancel_flags flags, void *opaque) |
d7e09d03 PT |
2999 | { |
3000 | struct obd_device *obd = exp->exp_obd; | |
3001 | struct lmv_obd *lmv = &obd->u.lmv; | |
3002 | int rc = 0; | |
3003 | int err; | |
a043a102 | 3004 | u32 i; |
d7e09d03 | 3005 | |
2cbdaa45 | 3006 | LASSERT(fid); |
d7e09d03 PT |
3007 | |
3008 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
0fdd2b8d DE |
3009 | struct lmv_tgt_desc *tgt = lmv->tgts[i]; |
3010 | ||
3011 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) | |
d7e09d03 PT |
3012 | continue; |
3013 | ||
0fdd2b8d DE |
3014 | err = md_cancel_unused(tgt->ltd_exp, fid, policy, mode, flags, |
3015 | opaque); | |
d7e09d03 PT |
3016 | if (!rc) |
3017 | rc = err; | |
3018 | } | |
0a3bdb00 | 3019 | return rc; |
d7e09d03 PT |
3020 | } |
3021 | ||
bc30c172 JH |
3022 | static int lmv_set_lock_data(struct obd_export *exp, |
3023 | const struct lustre_handle *lockh, | |
3024 | void *data, __u64 *bits) | |
d7e09d03 PT |
3025 | { |
3026 | struct lmv_obd *lmv = &exp->exp_obd->u.lmv; | |
0fdd2b8d | 3027 | struct lmv_tgt_desc *tgt = lmv->tgts[0]; |
d7e09d03 | 3028 | int rc; |
d7e09d03 | 3029 | |
0fdd2b8d DE |
3030 | if (!tgt || !tgt->ltd_exp) |
3031 | return -EINVAL; | |
3032 | ||
3033 | rc = md_set_lock_data(tgt->ltd_exp, lockh, data, bits); | |
0a3bdb00 | 3034 | return rc; |
d7e09d03 PT |
3035 | } |
3036 | ||
52ee0d20 OD |
3037 | static enum ldlm_mode lmv_lock_match(struct obd_export *exp, __u64 flags, |
3038 | const struct lu_fid *fid, | |
3039 | enum ldlm_type type, | |
3040 | ldlm_policy_data_t *policy, | |
3041 | enum ldlm_mode mode, | |
3042 | struct lustre_handle *lockh) | |
d7e09d03 PT |
3043 | { |
3044 | struct obd_device *obd = exp->exp_obd; | |
3045 | struct lmv_obd *lmv = &obd->u.lmv; | |
52ee0d20 | 3046 | enum ldlm_mode rc; |
711942df | 3047 | int tgt; |
a043a102 | 3048 | u32 i; |
d7e09d03 PT |
3049 | |
3050 | CDEBUG(D_INODE, "Lock match for "DFID"\n", PFID(fid)); | |
3051 | ||
3052 | /* | |
711942df | 3053 | * With DNE every object can have two locks in different namespaces: |
3054 | * lookup lock in space of MDT storing direntry and update/open lock in | |
3055 | * space of MDT storing inode. Try the MDT that the FID maps to first, | |
3056 | * since this can be easily found, and only try others if that fails. | |
d7e09d03 | 3057 | */ |
711942df | 3058 | for (i = 0, tgt = lmv_find_target_index(lmv, fid); |
3059 | i < lmv->desc.ld_tgt_count; | |
3060 | i++, tgt = (tgt + 1) % lmv->desc.ld_tgt_count) { | |
3061 | if (tgt < 0) { | |
3062 | CDEBUG(D_HA, "%s: "DFID" is inaccessible: rc = %d\n", | |
3063 | obd->obd_name, PFID(fid), tgt); | |
3064 | tgt = 0; | |
3065 | } | |
0fdd2b8d | 3066 | |
711942df | 3067 | if (!lmv->tgts[tgt] || !lmv->tgts[tgt]->ltd_exp || |
3068 | !lmv->tgts[tgt]->ltd_active) | |
d7e09d03 PT |
3069 | continue; |
3070 | ||
711942df | 3071 | rc = md_lock_match(lmv->tgts[tgt]->ltd_exp, flags, fid, |
3072 | type, policy, mode, lockh); | |
d7e09d03 | 3073 | if (rc) |
0a3bdb00 | 3074 | return rc; |
d7e09d03 PT |
3075 | } |
3076 | ||
0a3bdb00 | 3077 | return 0; |
d7e09d03 PT |
3078 | } |
3079 | ||
5dc8d7b4 LC |
3080 | static int lmv_get_lustre_md(struct obd_export *exp, |
3081 | struct ptlrpc_request *req, | |
3082 | struct obd_export *dt_exp, | |
3083 | struct obd_export *md_exp, | |
3084 | struct lustre_md *md) | |
d7e09d03 PT |
3085 | { |
3086 | struct lmv_obd *lmv = &exp->exp_obd->u.lmv; | |
0fdd2b8d | 3087 | struct lmv_tgt_desc *tgt = lmv->tgts[0]; |
d7e09d03 | 3088 | |
0fdd2b8d DE |
3089 | if (!tgt || !tgt->ltd_exp) |
3090 | return -EINVAL; | |
3091 | return md_get_lustre_md(tgt->ltd_exp, req, dt_exp, md_exp, md); | |
d7e09d03 PT |
3092 | } |
3093 | ||
5dc8d7b4 | 3094 | static int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md) |
d7e09d03 PT |
3095 | { |
3096 | struct obd_device *obd = exp->exp_obd; | |
3097 | struct lmv_obd *lmv = &obd->u.lmv; | |
0fdd2b8d | 3098 | struct lmv_tgt_desc *tgt = lmv->tgts[0]; |
d7e09d03 | 3099 | |
75ac62fc | 3100 | if (md->lmv) { |
5ce536b3 | 3101 | lmv_free_memmd(md->lmv); |
75ac62fc | 3102 | md->lmv = NULL; |
3103 | } | |
0fdd2b8d DE |
3104 | if (!tgt || !tgt->ltd_exp) |
3105 | return -EINVAL; | |
3106 | return md_free_lustre_md(tgt->ltd_exp, md); | |
d7e09d03 PT |
3107 | } |
3108 | ||
5dc8d7b4 LC |
3109 | static int lmv_set_open_replay_data(struct obd_export *exp, |
3110 | struct obd_client_handle *och, | |
3111 | struct lookup_intent *it) | |
d7e09d03 PT |
3112 | { |
3113 | struct obd_device *obd = exp->exp_obd; | |
3114 | struct lmv_obd *lmv = &obd->u.lmv; | |
3115 | struct lmv_tgt_desc *tgt; | |
d7e09d03 PT |
3116 | |
3117 | tgt = lmv_find_target(lmv, &och->och_fid); | |
3118 | if (IS_ERR(tgt)) | |
0a3bdb00 | 3119 | return PTR_ERR(tgt); |
d7e09d03 | 3120 | |
63d42578 | 3121 | return md_set_open_replay_data(tgt->ltd_exp, och, it); |
d7e09d03 PT |
3122 | } |
3123 | ||
5dc8d7b4 LC |
3124 | static int lmv_clear_open_replay_data(struct obd_export *exp, |
3125 | struct obd_client_handle *och) | |
d7e09d03 PT |
3126 | { |
3127 | struct obd_device *obd = exp->exp_obd; | |
3128 | struct lmv_obd *lmv = &obd->u.lmv; | |
3129 | struct lmv_tgt_desc *tgt; | |
d7e09d03 PT |
3130 | |
3131 | tgt = lmv_find_target(lmv, &och->och_fid); | |
3132 | if (IS_ERR(tgt)) | |
0a3bdb00 | 3133 | return PTR_ERR(tgt); |
d7e09d03 | 3134 | |
0a3bdb00 | 3135 | return md_clear_open_replay_data(tgt->ltd_exp, och); |
d7e09d03 PT |
3136 | } |
3137 | ||
5dc8d7b4 LC |
3138 | static int lmv_intent_getattr_async(struct obd_export *exp, |
3139 | struct md_enqueue_info *minfo, | |
3140 | struct ldlm_enqueue_info *einfo) | |
d7e09d03 PT |
3141 | { |
3142 | struct md_op_data *op_data = &minfo->mi_data; | |
3143 | struct obd_device *obd = exp->exp_obd; | |
3144 | struct lmv_obd *lmv = &obd->u.lmv; | |
3145 | struct lmv_tgt_desc *tgt = NULL; | |
3146 | int rc; | |
d7e09d03 PT |
3147 | |
3148 | rc = lmv_check_connect(obd); | |
3149 | if (rc) | |
0a3bdb00 | 3150 | return rc; |
d7e09d03 | 3151 | |
2de35386 | 3152 | tgt = lmv_locate_mds(lmv, op_data, &op_data->op_fid1); |
d7e09d03 | 3153 | if (IS_ERR(tgt)) |
0a3bdb00 | 3154 | return PTR_ERR(tgt); |
d7e09d03 PT |
3155 | |
3156 | rc = md_intent_getattr_async(tgt->ltd_exp, minfo, einfo); | |
0a3bdb00 | 3157 | return rc; |
d7e09d03 PT |
3158 | } |
3159 | ||
5dc8d7b4 LC |
3160 | static int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it, |
3161 | struct lu_fid *fid, __u64 *bits) | |
d7e09d03 PT |
3162 | { |
3163 | struct obd_device *obd = exp->exp_obd; | |
3164 | struct lmv_obd *lmv = &obd->u.lmv; | |
3165 | struct lmv_tgt_desc *tgt; | |
3166 | int rc; | |
d7e09d03 PT |
3167 | |
3168 | rc = lmv_check_connect(obd); | |
3169 | if (rc) | |
0a3bdb00 | 3170 | return rc; |
d7e09d03 PT |
3171 | |
3172 | tgt = lmv_find_target(lmv, fid); | |
3173 | if (IS_ERR(tgt)) | |
0a3bdb00 | 3174 | return PTR_ERR(tgt); |
d7e09d03 PT |
3175 | |
3176 | rc = md_revalidate_lock(tgt->ltd_exp, it, fid, bits); | |
0a3bdb00 | 3177 | return rc; |
d7e09d03 PT |
3178 | } |
3179 | ||
a609c393 | 3180 | int lmv_get_fid_from_lsm(struct obd_export *exp, |
3181 | const struct lmv_stripe_md *lsm, | |
3182 | const char *name, int namelen, struct lu_fid *fid) | |
3183 | { | |
3184 | const struct lmv_oinfo *oinfo; | |
3185 | ||
3186 | LASSERT(lsm); | |
3187 | oinfo = lsm_name_to_stripe_info(lsm, name, namelen); | |
3188 | if (IS_ERR(oinfo)) | |
3189 | return PTR_ERR(oinfo); | |
3190 | ||
3191 | *fid = oinfo->lmo_fid; | |
3192 | ||
3193 | return 0; | |
3194 | } | |
3195 | ||
d7e09d03 PT |
3196 | /** |
3197 | * For lmv, only need to send request to master MDT, and the master MDT will | |
3198 | * process with other slave MDTs. The only exception is Q_GETOQUOTA for which | |
3199 | * we directly fetch data from the slave MDTs. | |
3200 | */ | |
5dc8d7b4 LC |
3201 | static int lmv_quotactl(struct obd_device *unused, struct obd_export *exp, |
3202 | struct obd_quotactl *oqctl) | |
d7e09d03 PT |
3203 | { |
3204 | struct obd_device *obd = class_exp2obd(exp); | |
3205 | struct lmv_obd *lmv = &obd->u.lmv; | |
3206 | struct lmv_tgt_desc *tgt = lmv->tgts[0]; | |
a043a102 | 3207 | int rc = 0; |
77447a86 | 3208 | __u64 curspace = 0, curinodes = 0; |
a043a102 | 3209 | u32 i; |
d7e09d03 | 3210 | |
0fdd2b8d DE |
3211 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active || |
3212 | !lmv->desc.ld_tgt_count) { | |
d7e09d03 | 3213 | CERROR("master lmv inactive\n"); |
0a3bdb00 | 3214 | return -EIO; |
d7e09d03 PT |
3215 | } |
3216 | ||
3217 | if (oqctl->qc_cmd != Q_GETOQUOTA) { | |
3218 | rc = obd_quotactl(tgt->ltd_exp, oqctl); | |
0a3bdb00 | 3219 | return rc; |
d7e09d03 PT |
3220 | } |
3221 | ||
d7e09d03 PT |
3222 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { |
3223 | int err; | |
50ffcb7e | 3224 | |
d7e09d03 PT |
3225 | tgt = lmv->tgts[i]; |
3226 | ||
0fdd2b8d | 3227 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) |
d7e09d03 | 3228 | continue; |
d7e09d03 PT |
3229 | |
3230 | err = obd_quotactl(tgt->ltd_exp, oqctl); | |
3231 | if (err) { | |
3232 | CERROR("getquota on mdt %d failed. %d\n", i, err); | |
3233 | if (!rc) | |
3234 | rc = err; | |
3235 | } else { | |
3236 | curspace += oqctl->qc_dqblk.dqb_curspace; | |
3237 | curinodes += oqctl->qc_dqblk.dqb_curinodes; | |
3238 | } | |
3239 | } | |
3240 | oqctl->qc_dqblk.dqb_curspace = curspace; | |
3241 | oqctl->qc_dqblk.dqb_curinodes = curinodes; | |
3242 | ||
0a3bdb00 | 3243 | return rc; |
d7e09d03 PT |
3244 | } |
3245 | ||
5dc8d7b4 LC |
3246 | static int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp, |
3247 | struct obd_quotactl *oqctl) | |
d7e09d03 PT |
3248 | { |
3249 | struct obd_device *obd = class_exp2obd(exp); | |
3250 | struct lmv_obd *lmv = &obd->u.lmv; | |
3251 | struct lmv_tgt_desc *tgt; | |
a043a102 DE |
3252 | int rc = 0; |
3253 | u32 i; | |
d7e09d03 PT |
3254 | |
3255 | for (i = 0; i < lmv->desc.ld_tgt_count; i++) { | |
3256 | int err; | |
50ffcb7e | 3257 | |
d7e09d03 | 3258 | tgt = lmv->tgts[i]; |
2cbdaa45 | 3259 | if (!tgt || !tgt->ltd_exp || !tgt->ltd_active) { |
d7e09d03 | 3260 | CERROR("lmv idx %d inactive\n", i); |
0a3bdb00 | 3261 | return -EIO; |
d7e09d03 PT |
3262 | } |
3263 | ||
3264 | err = obd_quotacheck(tgt->ltd_exp, oqctl); | |
3265 | if (err && !rc) | |
3266 | rc = err; | |
3267 | } | |
3268 | ||
0a3bdb00 | 3269 | return rc; |
d7e09d03 PT |
3270 | } |
3271 | ||
2de35386 | 3272 | int lmv_update_lsm_md(struct obd_export *exp, struct lmv_stripe_md *lsm, |
3273 | struct mdt_body *body, ldlm_blocking_callback cb_blocking) | |
3274 | { | |
2de35386 | 3275 | return lmv_revalidate_slaves(exp, body, lsm, cb_blocking, 0); |
3276 | } | |
3277 | ||
3278 | int lmv_merge_attr(struct obd_export *exp, const struct lmv_stripe_md *lsm, | |
3279 | struct cl_attr *attr) | |
3280 | { | |
3281 | int i; | |
3282 | ||
3283 | for (i = 0; i < lsm->lsm_md_stripe_count; i++) { | |
3284 | struct inode *inode = lsm->lsm_md_oinfo[i].lmo_root; | |
3285 | ||
3286 | CDEBUG(D_INFO, ""DFID" size %llu, nlink %u, atime %lu ctime %lu, mtime %lu.\n", | |
3287 | PFID(&lsm->lsm_md_oinfo[i].lmo_fid), | |
3288 | i_size_read(inode), inode->i_nlink, | |
3289 | LTIME_S(inode->i_atime), LTIME_S(inode->i_ctime), | |
3290 | LTIME_S(inode->i_mtime)); | |
3291 | ||
3292 | /* for slave stripe, it needs to subtract nlink for . and .. */ | |
3293 | if (i) | |
3294 | attr->cat_nlink += inode->i_nlink - 2; | |
3295 | else | |
3296 | attr->cat_nlink = inode->i_nlink; | |
3297 | ||
3298 | attr->cat_size += i_size_read(inode); | |
3299 | ||
3300 | if (attr->cat_atime < LTIME_S(inode->i_atime)) | |
3301 | attr->cat_atime = LTIME_S(inode->i_atime); | |
3302 | ||
3303 | if (attr->cat_ctime < LTIME_S(inode->i_ctime)) | |
3304 | attr->cat_ctime = LTIME_S(inode->i_ctime); | |
3305 | ||
3306 | if (attr->cat_mtime < LTIME_S(inode->i_mtime)) | |
3307 | attr->cat_mtime = LTIME_S(inode->i_mtime); | |
3308 | } | |
3309 | return 0; | |
3310 | } | |
3311 | ||
5dc8d7b4 | 3312 | static struct obd_ops lmv_obd_ops = { |
a13b1f32 DC |
3313 | .owner = THIS_MODULE, |
3314 | .setup = lmv_setup, | |
3315 | .cleanup = lmv_cleanup, | |
3316 | .precleanup = lmv_precleanup, | |
3317 | .process_config = lmv_process_config, | |
3318 | .connect = lmv_connect, | |
3319 | .disconnect = lmv_disconnect, | |
3320 | .statfs = lmv_statfs, | |
3321 | .get_info = lmv_get_info, | |
3322 | .set_info_async = lmv_set_info_async, | |
3323 | .packmd = lmv_packmd, | |
3324 | .unpackmd = lmv_unpackmd, | |
3325 | .notify = lmv_notify, | |
3326 | .get_uuid = lmv_get_uuid, | |
3327 | .iocontrol = lmv_iocontrol, | |
3328 | .quotacheck = lmv_quotacheck, | |
3329 | .quotactl = lmv_quotactl | |
d7e09d03 PT |
3330 | }; |
3331 | ||
5dc8d7b4 | 3332 | static struct md_ops lmv_md_ops = { |
df18a80a DC |
3333 | .getstatus = lmv_getstatus, |
3334 | .null_inode = lmv_null_inode, | |
df18a80a DC |
3335 | .close = lmv_close, |
3336 | .create = lmv_create, | |
3337 | .done_writing = lmv_done_writing, | |
3338 | .enqueue = lmv_enqueue, | |
3339 | .getattr = lmv_getattr, | |
3340 | .getxattr = lmv_getxattr, | |
3341 | .getattr_name = lmv_getattr_name, | |
3342 | .intent_lock = lmv_intent_lock, | |
3343 | .link = lmv_link, | |
3344 | .rename = lmv_rename, | |
3345 | .setattr = lmv_setattr, | |
3346 | .setxattr = lmv_setxattr, | |
3347 | .sync = lmv_sync, | |
7ccb7c8f | 3348 | .read_page = lmv_read_page, |
df18a80a DC |
3349 | .unlink = lmv_unlink, |
3350 | .init_ea_size = lmv_init_ea_size, | |
3351 | .cancel_unused = lmv_cancel_unused, | |
3352 | .set_lock_data = lmv_set_lock_data, | |
3353 | .lock_match = lmv_lock_match, | |
3354 | .get_lustre_md = lmv_get_lustre_md, | |
3355 | .free_lustre_md = lmv_free_lustre_md, | |
2de35386 | 3356 | .update_lsm_md = lmv_update_lsm_md, |
3357 | .merge_attr = lmv_merge_attr, | |
df18a80a DC |
3358 | .set_open_replay_data = lmv_set_open_replay_data, |
3359 | .clear_open_replay_data = lmv_clear_open_replay_data, | |
df18a80a | 3360 | .intent_getattr_async = lmv_intent_getattr_async, |
a609c393 | 3361 | .revalidate_lock = lmv_revalidate_lock, |
3362 | .get_fid_from_lsm = lmv_get_fid_from_lsm, | |
d7e09d03 PT |
3363 | }; |
3364 | ||
5dc8d7b4 | 3365 | static int __init lmv_init(void) |
d7e09d03 PT |
3366 | { |
3367 | struct lprocfs_static_vars lvars; | |
3368 | int rc; | |
3369 | ||
3370 | lprocfs_lmv_init_vars(&lvars); | |
3371 | ||
3372 | rc = class_register_type(&lmv_obd_ops, &lmv_md_ops, | |
2962b440 | 3373 | LUSTRE_LMV_NAME, NULL); |
d7e09d03 PT |
3374 | return rc; |
3375 | } | |
3376 | ||
3377 | static void lmv_exit(void) | |
3378 | { | |
3379 | class_unregister_type(LUSTRE_LMV_NAME); | |
3380 | } | |
3381 | ||
a0455471 | 3382 | MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>"); |
57878e17 | 3383 | MODULE_DESCRIPTION("Lustre Logical Metadata Volume"); |
5b0e50b9 | 3384 | MODULE_VERSION(LUSTRE_VERSION_STRING); |
d7e09d03 PT |
3385 | MODULE_LICENSE("GPL"); |
3386 | ||
3387 | module_init(lmv_init); | |
3388 | module_exit(lmv_exit); |