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