Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | * | |
1dc563a6 | 30 | * Copyright (c) 2011, 2015, Intel Corporation. |
d7e09d03 PT |
31 | */ |
32 | /* | |
33 | * This file is part of Lustre, http://www.lustre.org/ | |
34 | * Lustre is a trademark of Sun Microsystems, Inc. | |
35 | */ | |
36 | ||
37 | #define DEBUG_SUBSYSTEM S_LOV | |
38 | ||
9fdaf8c0 | 39 | #include "../../include/linux/libcfs/libcfs.h" |
d7e09d03 | 40 | |
0cf0f7a7 | 41 | #include "../include/obd_class.h" |
0cf0f7a7 | 42 | #include "../include/lustre/lustre_idl.h" |
d7e09d03 PT |
43 | #include "lov_internal.h" |
44 | ||
45 | static void lov_init_set(struct lov_request_set *set) | |
46 | { | |
47 | set->set_count = 0; | |
48 | atomic_set(&set->set_completes, 0); | |
49 | atomic_set(&set->set_success, 0); | |
50 | atomic_set(&set->set_finish_checked, 0); | |
87355c1b | 51 | set->set_cookies = NULL; |
d7e09d03 PT |
52 | INIT_LIST_HEAD(&set->set_list); |
53 | atomic_set(&set->set_refcount, 1); | |
54 | init_waitqueue_head(&set->set_waitq); | |
55 | spin_lock_init(&set->set_lock); | |
56 | } | |
57 | ||
58 | void lov_finish_set(struct lov_request_set *set) | |
59 | { | |
60 | struct list_head *pos, *n; | |
d7e09d03 PT |
61 | |
62 | LASSERT(set); | |
63 | list_for_each_safe(pos, n, &set->set_list) { | |
64 | struct lov_request *req = list_entry(pos, | |
65 | struct lov_request, | |
66 | rq_link); | |
67 | list_del_init(&req->rq_link); | |
68 | ||
69 | if (req->rq_oi.oi_oa) | |
2ba262fb | 70 | kmem_cache_free(obdo_cachep, req->rq_oi.oi_oa); |
25e42899 | 71 | kfree(req->rq_oi.oi_osfs); |
840c94d5 | 72 | kfree(req); |
d7e09d03 | 73 | } |
840c94d5 | 74 | kfree(set); |
d7e09d03 PT |
75 | } |
76 | ||
2408e54d | 77 | static int lov_set_finished(struct lov_request_set *set, int idempotent) |
d7e09d03 PT |
78 | { |
79 | int completes = atomic_read(&set->set_completes); | |
80 | ||
81 | CDEBUG(D_INFO, "check set %d/%d\n", completes, set->set_count); | |
82 | ||
83 | if (completes == set->set_count) { | |
84 | if (idempotent) | |
85 | return 1; | |
86 | if (atomic_inc_return(&set->set_finish_checked) == 1) | |
87 | return 1; | |
88 | } | |
89 | return 0; | |
90 | } | |
91 | ||
2408e54d SB |
92 | static void lov_update_set(struct lov_request_set *set, |
93 | struct lov_request *req, int rc) | |
d7e09d03 PT |
94 | { |
95 | req->rq_complete = 1; | |
96 | req->rq_rc = rc; | |
97 | ||
98 | atomic_inc(&set->set_completes); | |
99 | if (rc == 0) | |
100 | atomic_inc(&set->set_success); | |
101 | ||
102 | wake_up(&set->set_waitq); | |
103 | } | |
104 | ||
105 | int lov_update_common_set(struct lov_request_set *set, | |
106 | struct lov_request *req, int rc) | |
107 | { | |
108 | struct lov_obd *lov = &set->set_exp->exp_obd->u.lov; | |
d7e09d03 PT |
109 | |
110 | lov_update_set(set, req, rc); | |
111 | ||
112 | /* grace error on inactive ost */ | |
113 | if (rc && !(lov->lov_tgts[req->rq_idx] && | |
114 | lov->lov_tgts[req->rq_idx]->ltd_active)) | |
115 | rc = 0; | |
116 | ||
117 | /* FIXME in raid1 regime, should return 0 */ | |
0a3bdb00 | 118 | return rc; |
d7e09d03 PT |
119 | } |
120 | ||
2408e54d SB |
121 | static void lov_set_add_req(struct lov_request *req, |
122 | struct lov_request_set *set) | |
d7e09d03 PT |
123 | { |
124 | list_add_tail(&req->rq_link, &set->set_list); | |
125 | set->set_count++; | |
126 | req->rq_rqset = set; | |
127 | } | |
128 | ||
129 | static int lov_check_set(struct lov_obd *lov, int idx) | |
130 | { | |
bd9cb12f RL |
131 | int rc; |
132 | struct lov_tgt_desc *tgt; | |
d7e09d03 | 133 | |
5c816ad7 | 134 | mutex_lock(&lov->lov_lock); |
bd9cb12f RL |
135 | tgt = lov->lov_tgts[idx]; |
136 | rc = !tgt || tgt->ltd_active || | |
137 | (tgt->ltd_exp && | |
138 | class_exp2cliimp(tgt->ltd_exp)->imp_connect_tried); | |
d7e09d03 | 139 | mutex_unlock(&lov->lov_lock); |
5c816ad7 | 140 | |
d7e09d03 PT |
141 | return rc; |
142 | } | |
143 | ||
144 | /* Check if the OSC connection exists and is active. | |
145 | * If the OSC has not yet had a chance to connect to the OST the first time, | |
146 | * wait once for it to connect instead of returning an error. | |
147 | */ | |
2408e54d | 148 | static int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx) |
d7e09d03 PT |
149 | { |
150 | wait_queue_head_t waitq; | |
151 | struct l_wait_info lwi; | |
152 | struct lov_tgt_desc *tgt; | |
153 | int rc = 0; | |
154 | ||
155 | mutex_lock(&lov->lov_lock); | |
156 | ||
157 | tgt = lov->lov_tgts[ost_idx]; | |
158 | ||
18751668 JL |
159 | if (unlikely(tgt == NULL)) { |
160 | rc = 0; | |
161 | goto out; | |
162 | } | |
d7e09d03 | 163 | |
18751668 JL |
164 | if (likely(tgt->ltd_active)) { |
165 | rc = 1; | |
166 | goto out; | |
167 | } | |
d7e09d03 | 168 | |
18751668 JL |
169 | if (tgt->ltd_exp && class_exp2cliimp(tgt->ltd_exp)->imp_connect_tried) { |
170 | rc = 0; | |
171 | goto out; | |
172 | } | |
d7e09d03 PT |
173 | |
174 | mutex_unlock(&lov->lov_lock); | |
175 | ||
176 | init_waitqueue_head(&waitq); | |
177 | lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(obd_timeout), | |
178 | cfs_time_seconds(1), NULL, NULL); | |
179 | ||
180 | rc = l_wait_event(waitq, lov_check_set(lov, ost_idx), &lwi); | |
181 | if (tgt != NULL && tgt->ltd_active) | |
182 | return 1; | |
183 | ||
184 | return 0; | |
185 | ||
186 | out: | |
187 | mutex_unlock(&lov->lov_lock); | |
188 | return rc; | |
189 | } | |
190 | ||
d7e09d03 PT |
191 | static int common_attr_done(struct lov_request_set *set) |
192 | { | |
193 | struct list_head *pos; | |
194 | struct lov_request *req; | |
195 | struct obdo *tmp_oa; | |
196 | int rc = 0, attrset = 0; | |
d7e09d03 PT |
197 | |
198 | LASSERT(set->set_oi != NULL); | |
199 | ||
200 | if (set->set_oi->oi_oa == NULL) | |
0a3bdb00 | 201 | return 0; |
d7e09d03 PT |
202 | |
203 | if (!atomic_read(&set->set_success)) | |
0a3bdb00 | 204 | return -EIO; |
d7e09d03 | 205 | |
131637b8 | 206 | tmp_oa = kmem_cache_alloc(obdo_cachep, GFP_NOFS | __GFP_ZERO); |
18751668 JL |
207 | if (tmp_oa == NULL) { |
208 | rc = -ENOMEM; | |
209 | goto out; | |
210 | } | |
d7e09d03 | 211 | |
66e7a94a | 212 | list_for_each(pos, &set->set_list) { |
d7e09d03 PT |
213 | req = list_entry(pos, struct lov_request, rq_link); |
214 | ||
215 | if (!req->rq_complete || req->rq_rc) | |
216 | continue; | |
217 | if (req->rq_oi.oi_oa->o_valid == 0) /* inactive stripe */ | |
218 | continue; | |
219 | lov_merge_attrs(tmp_oa, req->rq_oi.oi_oa, | |
220 | req->rq_oi.oi_oa->o_valid, | |
221 | set->set_oi->oi_md, req->rq_stripe, &attrset); | |
222 | } | |
223 | if (!attrset) { | |
224 | CERROR("No stripes had valid attrs\n"); | |
225 | rc = -EIO; | |
226 | } | |
227 | if ((set->set_oi->oi_oa->o_valid & OBD_MD_FLEPOCH) && | |
228 | (set->set_oi->oi_md->lsm_stripe_count != attrset)) { | |
229 | /* When we take attributes of some epoch, we require all the | |
230 | * ost to be active. */ | |
231 | CERROR("Not all the stripes had valid attrs\n"); | |
18751668 JL |
232 | rc = -EIO; |
233 | goto out; | |
d7e09d03 PT |
234 | } |
235 | ||
236 | tmp_oa->o_oi = set->set_oi->oi_oa->o_oi; | |
237 | memcpy(set->set_oi->oi_oa, tmp_oa, sizeof(*set->set_oi->oi_oa)); | |
238 | out: | |
239 | if (tmp_oa) | |
2ba262fb | 240 | kmem_cache_free(obdo_cachep, tmp_oa); |
0a3bdb00 | 241 | return rc; |
d7e09d03 PT |
242 | |
243 | } | |
244 | ||
d7e09d03 PT |
245 | int lov_fini_getattr_set(struct lov_request_set *set) |
246 | { | |
247 | int rc = 0; | |
d7e09d03 PT |
248 | |
249 | if (set == NULL) | |
0a3bdb00 | 250 | return 0; |
d7e09d03 PT |
251 | LASSERT(set->set_exp); |
252 | if (atomic_read(&set->set_completes)) | |
253 | rc = common_attr_done(set); | |
254 | ||
255 | lov_put_reqset(set); | |
256 | ||
0a3bdb00 | 257 | return rc; |
d7e09d03 PT |
258 | } |
259 | ||
1208bcd8 | 260 | /* The callback for osc_getattr_async that finalizes a request info when a |
d7e09d03 PT |
261 | * response is received. */ |
262 | static int cb_getattr_update(void *cookie, int rc) | |
263 | { | |
264 | struct obd_info *oinfo = cookie; | |
265 | struct lov_request *lovreq; | |
5c816ad7 | 266 | |
d7e09d03 PT |
267 | lovreq = container_of(oinfo, struct lov_request, rq_oi); |
268 | return lov_update_common_set(lovreq->rq_rqset, lovreq, rc); | |
269 | } | |
270 | ||
271 | int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo, | |
272 | struct lov_request_set **reqset) | |
273 | { | |
274 | struct lov_request_set *set; | |
275 | struct lov_obd *lov = &exp->exp_obd->u.lov; | |
276 | int rc = 0, i; | |
d7e09d03 | 277 | |
840c94d5 | 278 | set = kzalloc(sizeof(*set), GFP_NOFS); |
36a86fe6 | 279 | if (!set) |
0a3bdb00 | 280 | return -ENOMEM; |
d7e09d03 PT |
281 | lov_init_set(set); |
282 | ||
283 | set->set_exp = exp; | |
284 | set->set_oi = oinfo; | |
285 | ||
286 | for (i = 0; i < oinfo->oi_md->lsm_stripe_count; i++) { | |
287 | struct lov_oinfo *loi; | |
288 | struct lov_request *req; | |
289 | ||
290 | loi = oinfo->oi_md->lsm_oinfo[i]; | |
397632e4 YS |
291 | if (lov_oinfo_is_dummy(loi)) |
292 | continue; | |
293 | ||
d7e09d03 PT |
294 | if (!lov_check_and_wait_active(lov, loi->loi_ost_idx)) { |
295 | CDEBUG(D_HA, "lov idx %d inactive\n", loi->loi_ost_idx); | |
18751668 | 296 | if (oinfo->oi_oa->o_valid & OBD_MD_FLEPOCH) { |
d7e09d03 | 297 | /* SOM requires all the OSTs to be active. */ |
18751668 JL |
298 | rc = -EIO; |
299 | goto out_set; | |
300 | } | |
d7e09d03 PT |
301 | continue; |
302 | } | |
303 | ||
840c94d5 | 304 | req = kzalloc(sizeof(*req), GFP_NOFS); |
36a86fe6 | 305 | if (!req) { |
18751668 JL |
306 | rc = -ENOMEM; |
307 | goto out_set; | |
308 | } | |
d7e09d03 PT |
309 | |
310 | req->rq_stripe = i; | |
311 | req->rq_idx = loi->loi_ost_idx; | |
312 | ||
131637b8 MR |
313 | req->rq_oi.oi_oa = kmem_cache_alloc(obdo_cachep, |
314 | GFP_NOFS | __GFP_ZERO); | |
d7e09d03 | 315 | if (req->rq_oi.oi_oa == NULL) { |
840c94d5 | 316 | kfree(req); |
18751668 JL |
317 | rc = -ENOMEM; |
318 | goto out_set; | |
d7e09d03 PT |
319 | } |
320 | memcpy(req->rq_oi.oi_oa, oinfo->oi_oa, | |
321 | sizeof(*req->rq_oi.oi_oa)); | |
322 | req->rq_oi.oi_oa->o_oi = loi->loi_oi; | |
323 | req->rq_oi.oi_cb_up = cb_getattr_update; | |
d7e09d03 PT |
324 | |
325 | lov_set_add_req(req, set); | |
326 | } | |
18751668 JL |
327 | if (!set->set_count) { |
328 | rc = -EIO; | |
329 | goto out_set; | |
330 | } | |
d7e09d03 | 331 | *reqset = set; |
0a3bdb00 | 332 | return rc; |
d7e09d03 PT |
333 | out_set: |
334 | lov_fini_getattr_set(set); | |
0a3bdb00 | 335 | return rc; |
d7e09d03 PT |
336 | } |
337 | ||
338 | int lov_fini_destroy_set(struct lov_request_set *set) | |
339 | { | |
d7e09d03 | 340 | if (set == NULL) |
0a3bdb00 | 341 | return 0; |
d7e09d03 PT |
342 | LASSERT(set->set_exp); |
343 | if (atomic_read(&set->set_completes)) { | |
344 | /* FIXME update qos data here */ | |
345 | } | |
346 | ||
347 | lov_put_reqset(set); | |
348 | ||
0a3bdb00 | 349 | return 0; |
d7e09d03 PT |
350 | } |
351 | ||
352 | int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo, | |
353 | struct obdo *src_oa, struct lov_stripe_md *lsm, | |
354 | struct obd_trans_info *oti, | |
355 | struct lov_request_set **reqset) | |
356 | { | |
357 | struct lov_request_set *set; | |
358 | struct lov_obd *lov = &exp->exp_obd->u.lov; | |
359 | int rc = 0, i; | |
d7e09d03 | 360 | |
840c94d5 | 361 | set = kzalloc(sizeof(*set), GFP_NOFS); |
36a86fe6 | 362 | if (!set) |
0a3bdb00 | 363 | return -ENOMEM; |
d7e09d03 PT |
364 | lov_init_set(set); |
365 | ||
366 | set->set_exp = exp; | |
367 | set->set_oi = oinfo; | |
368 | set->set_oi->oi_md = lsm; | |
369 | set->set_oi->oi_oa = src_oa; | |
370 | set->set_oti = oti; | |
371 | if (oti != NULL && src_oa->o_valid & OBD_MD_FLCOOKIE) | |
372 | set->set_cookies = oti->oti_logcookies; | |
373 | ||
374 | for (i = 0; i < lsm->lsm_stripe_count; i++) { | |
375 | struct lov_oinfo *loi; | |
376 | struct lov_request *req; | |
377 | ||
378 | loi = lsm->lsm_oinfo[i]; | |
397632e4 YS |
379 | if (lov_oinfo_is_dummy(loi)) |
380 | continue; | |
381 | ||
d7e09d03 PT |
382 | if (!lov_check_and_wait_active(lov, loi->loi_ost_idx)) { |
383 | CDEBUG(D_HA, "lov idx %d inactive\n", loi->loi_ost_idx); | |
384 | continue; | |
385 | } | |
386 | ||
840c94d5 | 387 | req = kzalloc(sizeof(*req), GFP_NOFS); |
36a86fe6 | 388 | if (!req) { |
18751668 JL |
389 | rc = -ENOMEM; |
390 | goto out_set; | |
391 | } | |
d7e09d03 PT |
392 | |
393 | req->rq_stripe = i; | |
394 | req->rq_idx = loi->loi_ost_idx; | |
395 | ||
131637b8 MR |
396 | req->rq_oi.oi_oa = kmem_cache_alloc(obdo_cachep, |
397 | GFP_NOFS | __GFP_ZERO); | |
d7e09d03 | 398 | if (req->rq_oi.oi_oa == NULL) { |
840c94d5 | 399 | kfree(req); |
18751668 JL |
400 | rc = -ENOMEM; |
401 | goto out_set; | |
d7e09d03 PT |
402 | } |
403 | memcpy(req->rq_oi.oi_oa, src_oa, sizeof(*req->rq_oi.oi_oa)); | |
404 | req->rq_oi.oi_oa->o_oi = loi->loi_oi; | |
405 | lov_set_add_req(req, set); | |
406 | } | |
18751668 JL |
407 | if (!set->set_count) { |
408 | rc = -EIO; | |
409 | goto out_set; | |
410 | } | |
d7e09d03 | 411 | *reqset = set; |
0a3bdb00 | 412 | return rc; |
d7e09d03 PT |
413 | out_set: |
414 | lov_fini_destroy_set(set); | |
0a3bdb00 | 415 | return rc; |
d7e09d03 PT |
416 | } |
417 | ||
418 | int lov_fini_setattr_set(struct lov_request_set *set) | |
419 | { | |
420 | int rc = 0; | |
d7e09d03 PT |
421 | |
422 | if (set == NULL) | |
0a3bdb00 | 423 | return 0; |
d7e09d03 PT |
424 | LASSERT(set->set_exp); |
425 | if (atomic_read(&set->set_completes)) { | |
426 | rc = common_attr_done(set); | |
427 | /* FIXME update qos data here */ | |
428 | } | |
429 | ||
430 | lov_put_reqset(set); | |
0a3bdb00 | 431 | return rc; |
d7e09d03 PT |
432 | } |
433 | ||
434 | int lov_update_setattr_set(struct lov_request_set *set, | |
435 | struct lov_request *req, int rc) | |
436 | { | |
437 | struct lov_obd *lov = &req->rq_rqset->set_exp->exp_obd->u.lov; | |
438 | struct lov_stripe_md *lsm = req->rq_rqset->set_oi->oi_md; | |
d7e09d03 PT |
439 | |
440 | lov_update_set(set, req, rc); | |
441 | ||
442 | /* grace error on inactive ost */ | |
443 | if (rc && !(lov->lov_tgts[req->rq_idx] && | |
444 | lov->lov_tgts[req->rq_idx]->ltd_active)) | |
445 | rc = 0; | |
446 | ||
447 | if (rc == 0) { | |
448 | if (req->rq_oi.oi_oa->o_valid & OBD_MD_FLCTIME) | |
449 | lsm->lsm_oinfo[req->rq_stripe]->loi_lvb.lvb_ctime = | |
450 | req->rq_oi.oi_oa->o_ctime; | |
451 | if (req->rq_oi.oi_oa->o_valid & OBD_MD_FLMTIME) | |
452 | lsm->lsm_oinfo[req->rq_stripe]->loi_lvb.lvb_mtime = | |
453 | req->rq_oi.oi_oa->o_mtime; | |
454 | if (req->rq_oi.oi_oa->o_valid & OBD_MD_FLATIME) | |
455 | lsm->lsm_oinfo[req->rq_stripe]->loi_lvb.lvb_atime = | |
456 | req->rq_oi.oi_oa->o_atime; | |
457 | } | |
458 | ||
0a3bdb00 | 459 | return rc; |
d7e09d03 PT |
460 | } |
461 | ||
1208bcd8 | 462 | /* The callback for osc_setattr_async that finalizes a request info when a |
d7e09d03 PT |
463 | * response is received. */ |
464 | static int cb_setattr_update(void *cookie, int rc) | |
465 | { | |
466 | struct obd_info *oinfo = cookie; | |
467 | struct lov_request *lovreq; | |
5c816ad7 | 468 | |
d7e09d03 PT |
469 | lovreq = container_of(oinfo, struct lov_request, rq_oi); |
470 | return lov_update_setattr_set(lovreq->rq_rqset, lovreq, rc); | |
471 | } | |
472 | ||
473 | int lov_prep_setattr_set(struct obd_export *exp, struct obd_info *oinfo, | |
474 | struct obd_trans_info *oti, | |
475 | struct lov_request_set **reqset) | |
476 | { | |
477 | struct lov_request_set *set; | |
478 | struct lov_obd *lov = &exp->exp_obd->u.lov; | |
479 | int rc = 0, i; | |
d7e09d03 | 480 | |
840c94d5 | 481 | set = kzalloc(sizeof(*set), GFP_NOFS); |
36a86fe6 | 482 | if (!set) |
0a3bdb00 | 483 | return -ENOMEM; |
d7e09d03 PT |
484 | lov_init_set(set); |
485 | ||
486 | set->set_exp = exp; | |
487 | set->set_oti = oti; | |
488 | set->set_oi = oinfo; | |
489 | if (oti != NULL && oinfo->oi_oa->o_valid & OBD_MD_FLCOOKIE) | |
490 | set->set_cookies = oti->oti_logcookies; | |
491 | ||
492 | for (i = 0; i < oinfo->oi_md->lsm_stripe_count; i++) { | |
493 | struct lov_oinfo *loi = oinfo->oi_md->lsm_oinfo[i]; | |
494 | struct lov_request *req; | |
495 | ||
397632e4 YS |
496 | if (lov_oinfo_is_dummy(loi)) |
497 | continue; | |
498 | ||
d7e09d03 PT |
499 | if (!lov_check_and_wait_active(lov, loi->loi_ost_idx)) { |
500 | CDEBUG(D_HA, "lov idx %d inactive\n", loi->loi_ost_idx); | |
501 | continue; | |
502 | } | |
503 | ||
840c94d5 | 504 | req = kzalloc(sizeof(*req), GFP_NOFS); |
36a86fe6 | 505 | if (!req) { |
18751668 JL |
506 | rc = -ENOMEM; |
507 | goto out_set; | |
508 | } | |
d7e09d03 PT |
509 | req->rq_stripe = i; |
510 | req->rq_idx = loi->loi_ost_idx; | |
511 | ||
131637b8 MR |
512 | req->rq_oi.oi_oa = kmem_cache_alloc(obdo_cachep, |
513 | GFP_NOFS | __GFP_ZERO); | |
d7e09d03 | 514 | if (req->rq_oi.oi_oa == NULL) { |
840c94d5 | 515 | kfree(req); |
18751668 JL |
516 | rc = -ENOMEM; |
517 | goto out_set; | |
d7e09d03 PT |
518 | } |
519 | memcpy(req->rq_oi.oi_oa, oinfo->oi_oa, | |
520 | sizeof(*req->rq_oi.oi_oa)); | |
521 | req->rq_oi.oi_oa->o_oi = loi->loi_oi; | |
522 | req->rq_oi.oi_oa->o_stripe_idx = i; | |
523 | req->rq_oi.oi_cb_up = cb_setattr_update; | |
d7e09d03 PT |
524 | |
525 | if (oinfo->oi_oa->o_valid & OBD_MD_FLSIZE) { | |
526 | int off = lov_stripe_offset(oinfo->oi_md, | |
527 | oinfo->oi_oa->o_size, i, | |
528 | &req->rq_oi.oi_oa->o_size); | |
529 | ||
530 | if (off < 0 && req->rq_oi.oi_oa->o_size) | |
531 | req->rq_oi.oi_oa->o_size--; | |
532 | ||
b0f5aad5 | 533 | CDEBUG(D_INODE, "stripe %d has size %llu/%llu\n", |
d7e09d03 PT |
534 | i, req->rq_oi.oi_oa->o_size, |
535 | oinfo->oi_oa->o_size); | |
536 | } | |
537 | lov_set_add_req(req, set); | |
538 | } | |
18751668 JL |
539 | if (!set->set_count) { |
540 | rc = -EIO; | |
541 | goto out_set; | |
542 | } | |
d7e09d03 | 543 | *reqset = set; |
0a3bdb00 | 544 | return rc; |
d7e09d03 PT |
545 | out_set: |
546 | lov_fini_setattr_set(set); | |
0a3bdb00 | 547 | return rc; |
d7e09d03 PT |
548 | } |
549 | ||
d7e09d03 PT |
550 | #define LOV_U64_MAX ((__u64)~0ULL) |
551 | #define LOV_SUM_MAX(tot, add) \ | |
552 | do { \ | |
553 | if ((tot) + (add) < (tot)) \ | |
554 | (tot) = LOV_U64_MAX; \ | |
555 | else \ | |
556 | (tot) += (add); \ | |
5f3a68f9 | 557 | } while (0) |
d7e09d03 | 558 | |
1d8cb70c GD |
559 | int lov_fini_statfs(struct obd_device *obd, struct obd_statfs *osfs, |
560 | int success) | |
d7e09d03 | 561 | { |
d7e09d03 PT |
562 | if (success) { |
563 | __u32 expected_stripes = lov_get_stripecnt(&obd->u.lov, | |
564 | LOV_MAGIC, 0); | |
565 | if (osfs->os_files != LOV_U64_MAX) | |
566 | lov_do_div64(osfs->os_files, expected_stripes); | |
567 | if (osfs->os_ffree != LOV_U64_MAX) | |
568 | lov_do_div64(osfs->os_ffree, expected_stripes); | |
569 | ||
570 | spin_lock(&obd->obd_osfs_lock); | |
571 | memcpy(&obd->obd_osfs, osfs, sizeof(*osfs)); | |
572 | obd->obd_osfs_age = cfs_time_current_64(); | |
573 | spin_unlock(&obd->obd_osfs_lock); | |
0a3bdb00 | 574 | return 0; |
d7e09d03 PT |
575 | } |
576 | ||
0a3bdb00 | 577 | return -EIO; |
d7e09d03 PT |
578 | } |
579 | ||
580 | int lov_fini_statfs_set(struct lov_request_set *set) | |
581 | { | |
582 | int rc = 0; | |
d7e09d03 PT |
583 | |
584 | if (set == NULL) | |
0a3bdb00 | 585 | return 0; |
d7e09d03 PT |
586 | |
587 | if (atomic_read(&set->set_completes)) { | |
588 | rc = lov_fini_statfs(set->set_obd, set->set_oi->oi_osfs, | |
589 | atomic_read(&set->set_success)); | |
590 | } | |
591 | lov_put_reqset(set); | |
0a3bdb00 | 592 | return rc; |
d7e09d03 PT |
593 | } |
594 | ||
2408e54d SB |
595 | static void lov_update_statfs(struct obd_statfs *osfs, |
596 | struct obd_statfs *lov_sfs, | |
597 | int success) | |
d7e09d03 PT |
598 | { |
599 | int shift = 0, quit = 0; | |
600 | __u64 tmp; | |
601 | ||
602 | if (success == 0) { | |
603 | memcpy(osfs, lov_sfs, sizeof(*lov_sfs)); | |
604 | } else { | |
605 | if (osfs->os_bsize != lov_sfs->os_bsize) { | |
606 | /* assume all block sizes are always powers of 2 */ | |
607 | /* get the bits difference */ | |
608 | tmp = osfs->os_bsize | lov_sfs->os_bsize; | |
609 | for (shift = 0; shift <= 64; ++shift) { | |
610 | if (tmp & 1) { | |
611 | if (quit) | |
612 | break; | |
71e8dd9a | 613 | quit = 1; |
d7e09d03 PT |
614 | shift = 0; |
615 | } | |
616 | tmp >>= 1; | |
617 | } | |
618 | } | |
619 | ||
620 | if (osfs->os_bsize < lov_sfs->os_bsize) { | |
621 | osfs->os_bsize = lov_sfs->os_bsize; | |
622 | ||
623 | osfs->os_bfree >>= shift; | |
624 | osfs->os_bavail >>= shift; | |
625 | osfs->os_blocks >>= shift; | |
626 | } else if (shift != 0) { | |
627 | lov_sfs->os_bfree >>= shift; | |
628 | lov_sfs->os_bavail >>= shift; | |
629 | lov_sfs->os_blocks >>= shift; | |
630 | } | |
631 | osfs->os_bfree += lov_sfs->os_bfree; | |
632 | osfs->os_bavail += lov_sfs->os_bavail; | |
633 | osfs->os_blocks += lov_sfs->os_blocks; | |
634 | /* XXX not sure about this one - depends on policy. | |
635 | * - could be minimum if we always stripe on all OBDs | |
636 | * (but that would be wrong for any other policy, | |
637 | * if one of the OBDs has no more objects left) | |
638 | * - could be sum if we stripe whole objects | |
639 | * - could be average, just to give a nice number | |
640 | * | |
641 | * To give a "reasonable" (if not wholly accurate) | |
642 | * number, we divide the total number of free objects | |
643 | * by expected stripe count (watch out for overflow). | |
644 | */ | |
645 | LOV_SUM_MAX(osfs->os_files, lov_sfs->os_files); | |
646 | LOV_SUM_MAX(osfs->os_ffree, lov_sfs->os_ffree); | |
647 | } | |
648 | } | |
649 | ||
1208bcd8 | 650 | /* The callback for osc_statfs_async that finalizes a request info when a |
d7e09d03 PT |
651 | * response is received. */ |
652 | static int cb_statfs_update(void *cookie, int rc) | |
653 | { | |
654 | struct obd_info *oinfo = cookie; | |
655 | struct lov_request *lovreq; | |
656 | struct lov_request_set *set; | |
657 | struct obd_statfs *osfs, *lov_sfs; | |
658 | struct lov_obd *lov; | |
659 | struct lov_tgt_desc *tgt; | |
660 | struct obd_device *lovobd, *tgtobd; | |
661 | int success; | |
d7e09d03 PT |
662 | |
663 | lovreq = container_of(oinfo, struct lov_request, rq_oi); | |
664 | set = lovreq->rq_rqset; | |
665 | lovobd = set->set_obd; | |
666 | lov = &lovobd->u.lov; | |
667 | osfs = set->set_oi->oi_osfs; | |
668 | lov_sfs = oinfo->oi_osfs; | |
669 | success = atomic_read(&set->set_success); | |
670 | /* XXX: the same is done in lov_update_common_set, however | |
671 | lovset->set_exp is not initialized. */ | |
672 | lov_update_set(set, lovreq, rc); | |
673 | if (rc) | |
18751668 | 674 | goto out; |
d7e09d03 PT |
675 | |
676 | obd_getref(lovobd); | |
677 | tgt = lov->lov_tgts[lovreq->rq_idx]; | |
678 | if (!tgt || !tgt->ltd_active) | |
18751668 | 679 | goto out_update; |
d7e09d03 PT |
680 | |
681 | tgtobd = class_exp2obd(tgt->ltd_exp); | |
682 | spin_lock(&tgtobd->obd_osfs_lock); | |
683 | memcpy(&tgtobd->obd_osfs, lov_sfs, sizeof(*lov_sfs)); | |
684 | if ((oinfo->oi_flags & OBD_STATFS_FROM_CACHE) == 0) | |
685 | tgtobd->obd_osfs_age = cfs_time_current_64(); | |
686 | spin_unlock(&tgtobd->obd_osfs_lock); | |
687 | ||
688 | out_update: | |
689 | lov_update_statfs(osfs, lov_sfs, success); | |
690 | obd_putref(lovobd); | |
691 | ||
692 | out: | |
693 | if (set->set_oi->oi_flags & OBD_STATFS_PTLRPCD && | |
694 | lov_set_finished(set, 0)) { | |
695 | lov_statfs_interpret(NULL, set, set->set_count != | |
696 | atomic_read(&set->set_success)); | |
697 | } | |
698 | ||
0a3bdb00 | 699 | return 0; |
d7e09d03 PT |
700 | } |
701 | ||
702 | int lov_prep_statfs_set(struct obd_device *obd, struct obd_info *oinfo, | |
703 | struct lov_request_set **reqset) | |
704 | { | |
705 | struct lov_request_set *set; | |
706 | struct lov_obd *lov = &obd->u.lov; | |
707 | int rc = 0, i; | |
d7e09d03 | 708 | |
840c94d5 | 709 | set = kzalloc(sizeof(*set), GFP_NOFS); |
36a86fe6 | 710 | if (!set) |
0a3bdb00 | 711 | return -ENOMEM; |
d7e09d03 PT |
712 | lov_init_set(set); |
713 | ||
714 | set->set_obd = obd; | |
715 | set->set_oi = oinfo; | |
716 | ||
717 | /* We only get block data from the OBD */ | |
718 | for (i = 0; i < lov->desc.ld_tgt_count; i++) { | |
719 | struct lov_request *req; | |
720 | ||
721 | if (lov->lov_tgts[i] == NULL || | |
722 | (!lov_check_and_wait_active(lov, i) && | |
723 | (oinfo->oi_flags & OBD_STATFS_NODELAY))) { | |
724 | CDEBUG(D_HA, "lov idx %d inactive\n", i); | |
725 | continue; | |
726 | } | |
727 | ||
1208bcd8 | 728 | /* skip targets that have been explicitly disabled by the |
d7e09d03 PT |
729 | * administrator */ |
730 | if (!lov->lov_tgts[i]->ltd_exp) { | |
731 | CDEBUG(D_HA, "lov idx %d administratively disabled\n", i); | |
732 | continue; | |
733 | } | |
734 | ||
840c94d5 | 735 | req = kzalloc(sizeof(*req), GFP_NOFS); |
36a86fe6 | 736 | if (!req) { |
18751668 JL |
737 | rc = -ENOMEM; |
738 | goto out_set; | |
739 | } | |
d7e09d03 | 740 | |
840c94d5 JL |
741 | req->rq_oi.oi_osfs = kzalloc(sizeof(*req->rq_oi.oi_osfs), |
742 | GFP_NOFS); | |
36a86fe6 | 743 | if (!req->rq_oi.oi_osfs) { |
840c94d5 | 744 | kfree(req); |
18751668 JL |
745 | rc = -ENOMEM; |
746 | goto out_set; | |
d7e09d03 PT |
747 | } |
748 | ||
749 | req->rq_idx = i; | |
750 | req->rq_oi.oi_cb_up = cb_statfs_update; | |
751 | req->rq_oi.oi_flags = oinfo->oi_flags; | |
752 | ||
753 | lov_set_add_req(req, set); | |
754 | } | |
18751668 JL |
755 | if (!set->set_count) { |
756 | rc = -EIO; | |
757 | goto out_set; | |
758 | } | |
d7e09d03 | 759 | *reqset = set; |
0a3bdb00 | 760 | return rc; |
d7e09d03 PT |
761 | out_set: |
762 | lov_fini_statfs_set(set); | |
0a3bdb00 | 763 | return rc; |
d7e09d03 | 764 | } |