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); | |
71 | if (req->rq_oi.oi_md) | |
72 | OBD_FREE_LARGE(req->rq_oi.oi_md, req->rq_buflen); | |
25e42899 | 73 | kfree(req->rq_oi.oi_osfs); |
840c94d5 | 74 | kfree(req); |
d7e09d03 | 75 | } |
840c94d5 | 76 | kfree(set); |
d7e09d03 PT |
77 | } |
78 | ||
79 | int lov_set_finished(struct lov_request_set *set, int idempotent) | |
80 | { | |
81 | int completes = atomic_read(&set->set_completes); | |
82 | ||
83 | CDEBUG(D_INFO, "check set %d/%d\n", completes, set->set_count); | |
84 | ||
85 | if (completes == set->set_count) { | |
86 | if (idempotent) | |
87 | return 1; | |
88 | if (atomic_inc_return(&set->set_finish_checked) == 1) | |
89 | return 1; | |
90 | } | |
91 | return 0; | |
92 | } | |
93 | ||
94 | void lov_update_set(struct lov_request_set *set, | |
95 | struct lov_request *req, int rc) | |
96 | { | |
97 | req->rq_complete = 1; | |
98 | req->rq_rc = rc; | |
99 | ||
100 | atomic_inc(&set->set_completes); | |
101 | if (rc == 0) | |
102 | atomic_inc(&set->set_success); | |
103 | ||
104 | wake_up(&set->set_waitq); | |
105 | } | |
106 | ||
107 | int lov_update_common_set(struct lov_request_set *set, | |
108 | struct lov_request *req, int rc) | |
109 | { | |
110 | struct lov_obd *lov = &set->set_exp->exp_obd->u.lov; | |
d7e09d03 PT |
111 | |
112 | lov_update_set(set, req, rc); | |
113 | ||
114 | /* grace error on inactive ost */ | |
115 | if (rc && !(lov->lov_tgts[req->rq_idx] && | |
116 | lov->lov_tgts[req->rq_idx]->ltd_active)) | |
117 | rc = 0; | |
118 | ||
119 | /* FIXME in raid1 regime, should return 0 */ | |
0a3bdb00 | 120 | return rc; |
d7e09d03 PT |
121 | } |
122 | ||
123 | void lov_set_add_req(struct lov_request *req, struct lov_request_set *set) | |
124 | { | |
125 | list_add_tail(&req->rq_link, &set->set_list); | |
126 | set->set_count++; | |
127 | req->rq_rqset = set; | |
128 | } | |
129 | ||
130 | static int lov_check_set(struct lov_obd *lov, int idx) | |
131 | { | |
bd9cb12f RL |
132 | int rc; |
133 | struct lov_tgt_desc *tgt; | |
d7e09d03 | 134 | |
5c816ad7 | 135 | mutex_lock(&lov->lov_lock); |
bd9cb12f RL |
136 | tgt = lov->lov_tgts[idx]; |
137 | rc = !tgt || tgt->ltd_active || | |
138 | (tgt->ltd_exp && | |
139 | class_exp2cliimp(tgt->ltd_exp)->imp_connect_tried); | |
d7e09d03 | 140 | mutex_unlock(&lov->lov_lock); |
5c816ad7 | 141 | |
d7e09d03 PT |
142 | return rc; |
143 | } | |
144 | ||
145 | /* Check if the OSC connection exists and is active. | |
146 | * If the OSC has not yet had a chance to connect to the OST the first time, | |
147 | * wait once for it to connect instead of returning an error. | |
148 | */ | |
149 | int lov_check_and_wait_active(struct lov_obd *lov, int ost_idx) | |
150 | { | |
151 | wait_queue_head_t waitq; | |
152 | struct l_wait_info lwi; | |
153 | struct lov_tgt_desc *tgt; | |
154 | int rc = 0; | |
155 | ||
156 | mutex_lock(&lov->lov_lock); | |
157 | ||
158 | tgt = lov->lov_tgts[ost_idx]; | |
159 | ||
18751668 JL |
160 | if (unlikely(tgt == NULL)) { |
161 | rc = 0; | |
162 | goto out; | |
163 | } | |
d7e09d03 | 164 | |
18751668 JL |
165 | if (likely(tgt->ltd_active)) { |
166 | rc = 1; | |
167 | goto out; | |
168 | } | |
d7e09d03 | 169 | |
18751668 JL |
170 | if (tgt->ltd_exp && class_exp2cliimp(tgt->ltd_exp)->imp_connect_tried) { |
171 | rc = 0; | |
172 | goto out; | |
173 | } | |
d7e09d03 PT |
174 | |
175 | mutex_unlock(&lov->lov_lock); | |
176 | ||
177 | init_waitqueue_head(&waitq); | |
178 | lwi = LWI_TIMEOUT_INTERVAL(cfs_time_seconds(obd_timeout), | |
179 | cfs_time_seconds(1), NULL, NULL); | |
180 | ||
181 | rc = l_wait_event(waitq, lov_check_set(lov, ost_idx), &lwi); | |
182 | if (tgt != NULL && tgt->ltd_active) | |
183 | return 1; | |
184 | ||
185 | return 0; | |
186 | ||
187 | out: | |
188 | mutex_unlock(&lov->lov_lock); | |
189 | return rc; | |
190 | } | |
191 | ||
d7e09d03 PT |
192 | static int common_attr_done(struct lov_request_set *set) |
193 | { | |
194 | struct list_head *pos; | |
195 | struct lov_request *req; | |
196 | struct obdo *tmp_oa; | |
197 | int rc = 0, attrset = 0; | |
d7e09d03 PT |
198 | |
199 | LASSERT(set->set_oi != NULL); | |
200 | ||
201 | if (set->set_oi->oi_oa == NULL) | |
0a3bdb00 | 202 | return 0; |
d7e09d03 PT |
203 | |
204 | if (!atomic_read(&set->set_success)) | |
0a3bdb00 | 205 | return -EIO; |
d7e09d03 PT |
206 | |
207 | OBDO_ALLOC(tmp_oa); | |
18751668 JL |
208 | if (tmp_oa == NULL) { |
209 | rc = -ENOMEM; | |
210 | goto out; | |
211 | } | |
d7e09d03 | 212 | |
66e7a94a | 213 | list_for_each(pos, &set->set_list) { |
d7e09d03 PT |
214 | req = list_entry(pos, struct lov_request, rq_link); |
215 | ||
216 | if (!req->rq_complete || req->rq_rc) | |
217 | continue; | |
218 | if (req->rq_oi.oi_oa->o_valid == 0) /* inactive stripe */ | |
219 | continue; | |
220 | lov_merge_attrs(tmp_oa, req->rq_oi.oi_oa, | |
221 | req->rq_oi.oi_oa->o_valid, | |
222 | set->set_oi->oi_md, req->rq_stripe, &attrset); | |
223 | } | |
224 | if (!attrset) { | |
225 | CERROR("No stripes had valid attrs\n"); | |
226 | rc = -EIO; | |
227 | } | |
228 | if ((set->set_oi->oi_oa->o_valid & OBD_MD_FLEPOCH) && | |
229 | (set->set_oi->oi_md->lsm_stripe_count != attrset)) { | |
230 | /* When we take attributes of some epoch, we require all the | |
231 | * ost to be active. */ | |
232 | CERROR("Not all the stripes had valid attrs\n"); | |
18751668 JL |
233 | rc = -EIO; |
234 | goto out; | |
d7e09d03 PT |
235 | } |
236 | ||
237 | tmp_oa->o_oi = set->set_oi->oi_oa->o_oi; | |
238 | memcpy(set->set_oi->oi_oa, tmp_oa, sizeof(*set->set_oi->oi_oa)); | |
239 | out: | |
240 | if (tmp_oa) | |
241 | OBDO_FREE(tmp_oa); | |
0a3bdb00 | 242 | return rc; |
d7e09d03 PT |
243 | |
244 | } | |
245 | ||
d7e09d03 PT |
246 | int lov_fini_getattr_set(struct lov_request_set *set) |
247 | { | |
248 | int rc = 0; | |
d7e09d03 PT |
249 | |
250 | if (set == NULL) | |
0a3bdb00 | 251 | return 0; |
d7e09d03 PT |
252 | LASSERT(set->set_exp); |
253 | if (atomic_read(&set->set_completes)) | |
254 | rc = common_attr_done(set); | |
255 | ||
256 | lov_put_reqset(set); | |
257 | ||
0a3bdb00 | 258 | return rc; |
d7e09d03 PT |
259 | } |
260 | ||
1208bcd8 | 261 | /* The callback for osc_getattr_async that finalizes a request info when a |
d7e09d03 PT |
262 | * response is received. */ |
263 | static int cb_getattr_update(void *cookie, int rc) | |
264 | { | |
265 | struct obd_info *oinfo = cookie; | |
266 | struct lov_request *lovreq; | |
5c816ad7 | 267 | |
d7e09d03 PT |
268 | lovreq = container_of(oinfo, struct lov_request, rq_oi); |
269 | return lov_update_common_set(lovreq->rq_rqset, lovreq, rc); | |
270 | } | |
271 | ||
272 | int lov_prep_getattr_set(struct obd_export *exp, struct obd_info *oinfo, | |
273 | struct lov_request_set **reqset) | |
274 | { | |
275 | struct lov_request_set *set; | |
276 | struct lov_obd *lov = &exp->exp_obd->u.lov; | |
277 | int rc = 0, i; | |
d7e09d03 | 278 | |
840c94d5 | 279 | set = kzalloc(sizeof(*set), GFP_NOFS); |
d7e09d03 | 280 | if (set == NULL) |
0a3bdb00 | 281 | return -ENOMEM; |
d7e09d03 PT |
282 | lov_init_set(set); |
283 | ||
284 | set->set_exp = exp; | |
285 | set->set_oi = oinfo; | |
286 | ||
287 | for (i = 0; i < oinfo->oi_md->lsm_stripe_count; i++) { | |
288 | struct lov_oinfo *loi; | |
289 | struct lov_request *req; | |
290 | ||
291 | loi = oinfo->oi_md->lsm_oinfo[i]; | |
397632e4 YS |
292 | if (lov_oinfo_is_dummy(loi)) |
293 | continue; | |
294 | ||
d7e09d03 PT |
295 | if (!lov_check_and_wait_active(lov, loi->loi_ost_idx)) { |
296 | CDEBUG(D_HA, "lov idx %d inactive\n", loi->loi_ost_idx); | |
18751668 | 297 | if (oinfo->oi_oa->o_valid & OBD_MD_FLEPOCH) { |
d7e09d03 | 298 | /* SOM requires all the OSTs to be active. */ |
18751668 JL |
299 | rc = -EIO; |
300 | goto out_set; | |
301 | } | |
d7e09d03 PT |
302 | continue; |
303 | } | |
304 | ||
840c94d5 | 305 | req = kzalloc(sizeof(*req), GFP_NOFS); |
18751668 JL |
306 | if (req == NULL) { |
307 | rc = -ENOMEM; | |
308 | goto out_set; | |
309 | } | |
d7e09d03 PT |
310 | |
311 | req->rq_stripe = i; | |
312 | req->rq_idx = loi->loi_ost_idx; | |
313 | ||
314 | OBDO_ALLOC(req->rq_oi.oi_oa); | |
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; | |
324 | req->rq_oi.oi_capa = oinfo->oi_capa; | |
325 | ||
326 | lov_set_add_req(req, set); | |
327 | } | |
18751668 JL |
328 | if (!set->set_count) { |
329 | rc = -EIO; | |
330 | goto out_set; | |
331 | } | |
d7e09d03 | 332 | *reqset = set; |
0a3bdb00 | 333 | return rc; |
d7e09d03 PT |
334 | out_set: |
335 | lov_fini_getattr_set(set); | |
0a3bdb00 | 336 | return rc; |
d7e09d03 PT |
337 | } |
338 | ||
339 | int lov_fini_destroy_set(struct lov_request_set *set) | |
340 | { | |
d7e09d03 | 341 | if (set == NULL) |
0a3bdb00 | 342 | return 0; |
d7e09d03 PT |
343 | LASSERT(set->set_exp); |
344 | if (atomic_read(&set->set_completes)) { | |
345 | /* FIXME update qos data here */ | |
346 | } | |
347 | ||
348 | lov_put_reqset(set); | |
349 | ||
0a3bdb00 | 350 | return 0; |
d7e09d03 PT |
351 | } |
352 | ||
353 | int lov_prep_destroy_set(struct obd_export *exp, struct obd_info *oinfo, | |
354 | struct obdo *src_oa, struct lov_stripe_md *lsm, | |
355 | struct obd_trans_info *oti, | |
356 | struct lov_request_set **reqset) | |
357 | { | |
358 | struct lov_request_set *set; | |
359 | struct lov_obd *lov = &exp->exp_obd->u.lov; | |
360 | int rc = 0, i; | |
d7e09d03 | 361 | |
840c94d5 | 362 | set = kzalloc(sizeof(*set), GFP_NOFS); |
d7e09d03 | 363 | if (set == NULL) |
0a3bdb00 | 364 | return -ENOMEM; |
d7e09d03 PT |
365 | lov_init_set(set); |
366 | ||
367 | set->set_exp = exp; | |
368 | set->set_oi = oinfo; | |
369 | set->set_oi->oi_md = lsm; | |
370 | set->set_oi->oi_oa = src_oa; | |
371 | set->set_oti = oti; | |
372 | if (oti != NULL && src_oa->o_valid & OBD_MD_FLCOOKIE) | |
373 | set->set_cookies = oti->oti_logcookies; | |
374 | ||
375 | for (i = 0; i < lsm->lsm_stripe_count; i++) { | |
376 | struct lov_oinfo *loi; | |
377 | struct lov_request *req; | |
378 | ||
379 | loi = lsm->lsm_oinfo[i]; | |
397632e4 YS |
380 | if (lov_oinfo_is_dummy(loi)) |
381 | continue; | |
382 | ||
d7e09d03 PT |
383 | if (!lov_check_and_wait_active(lov, loi->loi_ost_idx)) { |
384 | CDEBUG(D_HA, "lov idx %d inactive\n", loi->loi_ost_idx); | |
385 | continue; | |
386 | } | |
387 | ||
840c94d5 | 388 | req = kzalloc(sizeof(*req), GFP_NOFS); |
18751668 JL |
389 | if (req == NULL) { |
390 | rc = -ENOMEM; | |
391 | goto out_set; | |
392 | } | |
d7e09d03 PT |
393 | |
394 | req->rq_stripe = i; | |
395 | req->rq_idx = loi->loi_ost_idx; | |
396 | ||
397 | OBDO_ALLOC(req->rq_oi.oi_oa); | |
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); |
d7e09d03 | 482 | if (set == NULL) |
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); |
18751668 JL |
505 | if (req == NULL) { |
506 | rc = -ENOMEM; | |
507 | goto out_set; | |
508 | } | |
d7e09d03 PT |
509 | req->rq_stripe = i; |
510 | req->rq_idx = loi->loi_ost_idx; | |
511 | ||
512 | OBDO_ALLOC(req->rq_oi.oi_oa); | |
513 | if (req->rq_oi.oi_oa == NULL) { | |
840c94d5 | 514 | kfree(req); |
18751668 JL |
515 | rc = -ENOMEM; |
516 | goto out_set; | |
d7e09d03 PT |
517 | } |
518 | memcpy(req->rq_oi.oi_oa, oinfo->oi_oa, | |
519 | sizeof(*req->rq_oi.oi_oa)); | |
520 | req->rq_oi.oi_oa->o_oi = loi->loi_oi; | |
521 | req->rq_oi.oi_oa->o_stripe_idx = i; | |
522 | req->rq_oi.oi_cb_up = cb_setattr_update; | |
523 | req->rq_oi.oi_capa = oinfo->oi_capa; | |
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 | ||
595 | void lov_update_statfs(struct obd_statfs *osfs, struct obd_statfs *lov_sfs, | |
596 | int success) | |
597 | { | |
598 | int shift = 0, quit = 0; | |
599 | __u64 tmp; | |
600 | ||
601 | if (success == 0) { | |
602 | memcpy(osfs, lov_sfs, sizeof(*lov_sfs)); | |
603 | } else { | |
604 | if (osfs->os_bsize != lov_sfs->os_bsize) { | |
605 | /* assume all block sizes are always powers of 2 */ | |
606 | /* get the bits difference */ | |
607 | tmp = osfs->os_bsize | lov_sfs->os_bsize; | |
608 | for (shift = 0; shift <= 64; ++shift) { | |
609 | if (tmp & 1) { | |
610 | if (quit) | |
611 | break; | |
612 | else | |
613 | quit = 1; | |
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); |
d7e09d03 | 710 | if (set == NULL) |
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); |
18751668 JL |
736 | if (req == NULL) { |
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); | |
d7e09d03 | 743 | if (req->rq_oi.oi_osfs == NULL) { |
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 | } |