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) 2008, 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 | * Implementation of cl_io for OSC layer. | |
33 | * | |
34 | * Author: Nikita Danilov <nikita.danilov@sun.com> | |
35 | * Author: Jinshan Xiong <jinshan.xiong@whamcloud.com> | |
36 | */ | |
37 | ||
38 | #define DEBUG_SUBSYSTEM S_OSC | |
39 | ||
40 | #include "osc_cl_internal.h" | |
41 | ||
42 | /** \addtogroup osc | |
43 | * @{ | |
44 | */ | |
45 | ||
46 | /***************************************************************************** | |
47 | * | |
48 | * Type conversions. | |
49 | * | |
50 | */ | |
51 | ||
52 | static struct osc_req *cl2osc_req(const struct cl_req_slice *slice) | |
53 | { | |
54 | LINVRNT(slice->crs_dev->cd_lu_dev.ld_type == &osc_device_type); | |
55 | return container_of0(slice, struct osc_req, or_cl); | |
56 | } | |
57 | ||
58 | static struct osc_io *cl2osc_io(const struct lu_env *env, | |
59 | const struct cl_io_slice *slice) | |
60 | { | |
61 | struct osc_io *oio = container_of0(slice, struct osc_io, oi_cl); | |
1144b19f | 62 | |
d7e09d03 PT |
63 | LINVRNT(oio == osc_env_io(env)); |
64 | return oio; | |
65 | } | |
66 | ||
7addf402 JX |
67 | static struct osc_page *osc_cl_page_osc(struct cl_page *page, |
68 | struct osc_object *osc) | |
d7e09d03 PT |
69 | { |
70 | const struct cl_page_slice *slice; | |
71 | ||
7addf402 JX |
72 | if (osc) |
73 | slice = cl_object_page_slice(&osc->oo_cl, page); | |
74 | else | |
75 | slice = cl_page_at(page, &osc_device_type); | |
7f1ae4c0 | 76 | LASSERT(slice); |
d7e09d03 PT |
77 | |
78 | return cl2osc_page(slice); | |
79 | } | |
80 | ||
d7e09d03 PT |
81 | /***************************************************************************** |
82 | * | |
83 | * io operations. | |
84 | * | |
85 | */ | |
86 | ||
87 | static void osc_io_fini(const struct lu_env *env, const struct cl_io_slice *io) | |
88 | { | |
89 | } | |
90 | ||
91 | /** | |
92 | * An implementation of cl_io_operations::cio_io_submit() method for osc | |
93 | * layer. Iterates over pages in the in-queue, prepares each for io by calling | |
94 | * cl_page_prep() and then either submits them through osc_io_submit_page() | |
95 | * or, if page is already submitted, changes osc flags through | |
96 | * osc_set_async_flags(). | |
97 | */ | |
98 | static int osc_io_submit(const struct lu_env *env, | |
99 | const struct cl_io_slice *ios, | |
100 | enum cl_req_type crt, struct cl_2queue *queue) | |
101 | { | |
29ac6840 CH |
102 | struct cl_page *page; |
103 | struct cl_page *tmp; | |
104 | struct client_obd *cli = NULL; | |
105 | struct osc_object *osc = NULL; /* to keep gcc happy */ | |
106 | struct osc_page *opg; | |
107 | struct cl_io *io; | |
218c394a | 108 | LIST_HEAD(list); |
d7e09d03 | 109 | |
29ac6840 CH |
110 | struct cl_page_list *qin = &queue->c2_qin; |
111 | struct cl_page_list *qout = &queue->c2_qout; | |
d7e09d03 PT |
112 | int queued = 0; |
113 | int result = 0; | |
114 | int cmd; | |
115 | int brw_flags; | |
116 | int max_pages; | |
117 | ||
118 | LASSERT(qin->pl_nr > 0); | |
119 | ||
120 | CDEBUG(D_CACHE, "%d %d\n", qin->pl_nr, crt); | |
121 | ||
122 | osc = cl2osc(ios->cis_obj); | |
123 | cli = osc_cli(osc); | |
124 | max_pages = cli->cl_max_pages_per_rpc; | |
125 | ||
126 | cmd = crt == CRT_WRITE ? OBD_BRW_WRITE : OBD_BRW_READ; | |
127 | brw_flags = osc_io_srvlock(cl2osc_io(env, ios)) ? OBD_BRW_SRVLOCK : 0; | |
128 | ||
129 | /* | |
130 | * NOTE: here @page is a top-level page. This is done to avoid | |
131 | * creation of sub-page-list. | |
132 | */ | |
133 | cl_page_list_for_each_safe(page, tmp, qin) { | |
134 | struct osc_async_page *oap; | |
135 | ||
136 | /* Top level IO. */ | |
137 | io = page->cp_owner; | |
7f1ae4c0 | 138 | LASSERT(io); |
d7e09d03 | 139 | |
7addf402 | 140 | opg = osc_cl_page_osc(page, osc); |
d7e09d03 PT |
141 | oap = &opg->ops_oap; |
142 | LASSERT(osc == oap->oap_obj); | |
143 | ||
144 | if (!list_empty(&oap->oap_pending_item) || | |
145 | !list_empty(&oap->oap_rpc_item)) { | |
146 | CDEBUG(D_CACHE, "Busy oap %p page %p for submit.\n", | |
147 | oap, opg); | |
148 | result = -EBUSY; | |
149 | break; | |
150 | } | |
151 | ||
152 | result = cl_page_prep(env, io, page, crt); | |
153 | if (result != 0) { | |
154 | LASSERT(result < 0); | |
155 | if (result != -EALREADY) | |
156 | break; | |
157 | /* | |
158 | * Handle -EALREADY error: for read case, the page is | |
159 | * already in UPTODATE state; for write, the page | |
160 | * is not dirty. | |
161 | */ | |
162 | result = 0; | |
163 | continue; | |
164 | } | |
165 | ||
82281bc0 | 166 | spin_lock(&oap->oap_lock); |
cd94f231 | 167 | oap->oap_async_flags = ASYNC_URGENT | ASYNC_READY; |
d7e09d03 | 168 | oap->oap_async_flags |= ASYNC_COUNT_STABLE; |
82281bc0 | 169 | spin_unlock(&oap->oap_lock); |
d7e09d03 PT |
170 | |
171 | osc_page_submit(env, opg, crt, brw_flags); | |
172 | list_add_tail(&oap->oap_pending_item, &list); | |
96c53363 JX |
173 | |
174 | if (page->cp_sync_io) | |
175 | cl_page_list_move(qout, qin, page); | |
176 | else /* async IO */ | |
177 | cl_page_list_del(env, qin, page); | |
178 | ||
d7e09d03 PT |
179 | if (++queued == max_pages) { |
180 | queued = 0; | |
181 | result = osc_queue_sync_pages(env, osc, &list, cmd, | |
182 | brw_flags); | |
183 | if (result < 0) | |
184 | break; | |
185 | } | |
186 | } | |
187 | ||
188 | if (queued > 0) | |
189 | result = osc_queue_sync_pages(env, osc, &list, cmd, brw_flags); | |
190 | ||
191 | CDEBUG(D_INFO, "%d/%d %d\n", qin->pl_nr, qout->pl_nr, result); | |
192 | return qout->pl_nr > 0 ? 0 : result; | |
193 | } | |
194 | ||
77605e41 JX |
195 | /** |
196 | * This is called when a page is accessed within file in a way that creates | |
197 | * new page, if one were missing (i.e., if there were a hole at that place in | |
198 | * the file, or accessed page is beyond the current file size). | |
199 | * | |
200 | * Expand stripe KMS if necessary. | |
201 | */ | |
d7e09d03 PT |
202 | static void osc_page_touch_at(const struct lu_env *env, |
203 | struct cl_object *obj, pgoff_t idx, unsigned to) | |
204 | { | |
29ac6840 CH |
205 | struct lov_oinfo *loi = cl2osc(obj)->oo_oinfo; |
206 | struct cl_attr *attr = &osc_env_info(env)->oti_attr; | |
d7e09d03 PT |
207 | int valid; |
208 | __u64 kms; | |
209 | ||
210 | /* offset within stripe */ | |
211 | kms = cl_offset(obj, idx) + to; | |
212 | ||
213 | cl_object_attr_lock(obj); | |
214 | /* | |
215 | * XXX old code used | |
216 | * | |
217 | * ll_inode_size_lock(inode, 0); lov_stripe_lock(lsm); | |
218 | * | |
219 | * here | |
220 | */ | |
b0f5aad5 | 221 | CDEBUG(D_INODE, "stripe KMS %sincreasing %llu->%llu %llu\n", |
d7e09d03 PT |
222 | kms > loi->loi_kms ? "" : "not ", loi->loi_kms, kms, |
223 | loi->loi_lvb.lvb_size); | |
224 | ||
04a6284f NC |
225 | attr->cat_ctime = LTIME_S(CURRENT_TIME); |
226 | attr->cat_mtime = attr->cat_ctime; | |
77605e41 | 227 | valid = CAT_MTIME | CAT_CTIME; |
d7e09d03 PT |
228 | if (kms > loi->loi_kms) { |
229 | attr->cat_kms = kms; | |
230 | valid |= CAT_KMS; | |
231 | } | |
232 | if (kms > loi->loi_lvb.lvb_size) { | |
233 | attr->cat_size = kms; | |
234 | valid |= CAT_SIZE; | |
235 | } | |
236 | cl_object_attr_set(env, obj, attr, valid); | |
237 | cl_object_attr_unlock(obj); | |
238 | } | |
239 | ||
77605e41 JX |
240 | static int osc_io_commit_async(const struct lu_env *env, |
241 | const struct cl_io_slice *ios, | |
242 | struct cl_page_list *qin, int from, int to, | |
243 | cl_commit_cbt cb) | |
d7e09d03 | 244 | { |
77605e41 | 245 | struct cl_io *io = ios->cis_io; |
29ac6840 | 246 | struct osc_io *oio = cl2osc_io(env, ios); |
77605e41 JX |
247 | struct osc_object *osc = cl2osc(ios->cis_obj); |
248 | struct cl_page *page; | |
249 | struct cl_page *last_page; | |
250 | struct osc_page *opg; | |
d7e09d03 | 251 | int result = 0; |
d7e09d03 | 252 | |
77605e41 JX |
253 | LASSERT(qin->pl_nr > 0); |
254 | ||
255 | /* Handle partial page cases */ | |
256 | last_page = cl_page_list_last(qin); | |
257 | if (oio->oi_lockless) { | |
258 | page = cl_page_list_first(qin); | |
259 | if (page == last_page) { | |
260 | cl_page_clip(env, page, from, to); | |
261 | } else { | |
262 | if (from != 0) | |
263 | cl_page_clip(env, page, from, PAGE_SIZE); | |
264 | if (to != PAGE_SIZE) | |
265 | cl_page_clip(env, last_page, 0, to); | |
266 | } | |
267 | } | |
268 | ||
77605e41 JX |
269 | while (qin->pl_nr > 0) { |
270 | struct osc_async_page *oap; | |
d7e09d03 | 271 | |
77605e41 | 272 | page = cl_page_list_first(qin); |
7addf402 | 273 | opg = osc_cl_page_osc(page, osc); |
77605e41 | 274 | oap = &opg->ops_oap; |
d7e09d03 | 275 | |
77605e41 JX |
276 | if (!list_empty(&oap->oap_rpc_item)) { |
277 | CDEBUG(D_CACHE, "Busy oap %p page %p for submit.\n", | |
278 | oap, opg); | |
279 | result = -EBUSY; | |
280 | break; | |
281 | } | |
d7e09d03 | 282 | |
77605e41 JX |
283 | /* The page may be already in dirty cache. */ |
284 | if (list_empty(&oap->oap_pending_item)) { | |
285 | result = osc_page_cache_add(env, &opg->ops_cl, io); | |
286 | if (result != 0) | |
287 | break; | |
288 | } | |
d7e09d03 | 289 | |
7addf402 | 290 | osc_page_touch_at(env, osc2cl(osc), osc_index(opg), |
77605e41 | 291 | page == last_page ? to : PAGE_SIZE); |
d7e09d03 | 292 | |
77605e41 | 293 | cl_page_list_del(env, qin, page); |
d7e09d03 | 294 | |
77605e41 JX |
295 | (*cb)(env, io, page); |
296 | /* Can't access page any more. Page can be in transfer and | |
297 | * complete at any time. | |
298 | */ | |
299 | } | |
300 | ||
301 | /* for sync write, kernel will wait for this page to be flushed before | |
302 | * osc_io_end() is called, so release it earlier. | |
303 | * for mkwrite(), it's known there is no further pages. | |
304 | */ | |
305 | if (cl_io_is_sync_write(io) && oio->oi_active) { | |
306 | osc_extent_release(env, oio->oi_active); | |
307 | oio->oi_active = NULL; | |
308 | } | |
309 | ||
310 | CDEBUG(D_INFO, "%d %d\n", qin->pl_nr, result); | |
311 | return result; | |
d7e09d03 PT |
312 | } |
313 | ||
5196e42c JX |
314 | static int osc_io_rw_iter_init(const struct lu_env *env, |
315 | const struct cl_io_slice *ios) | |
316 | { | |
317 | struct cl_io *io = ios->cis_io; | |
318 | struct osc_io *oio = osc_env_io(env); | |
319 | struct osc_object *osc = cl2osc(ios->cis_obj); | |
320 | struct client_obd *cli = osc_cli(osc); | |
321 | unsigned long c; | |
322 | unsigned int npages; | |
323 | unsigned int max_pages; | |
324 | ||
325 | if (cl_io_is_append(io)) | |
326 | return 0; | |
327 | ||
5f479924 | 328 | npages = io->u.ci_rw.crw_count >> PAGE_SHIFT; |
5196e42c JX |
329 | if (io->u.ci_rw.crw_pos & ~PAGE_MASK) |
330 | ++npages; | |
331 | ||
332 | max_pages = cli->cl_max_pages_per_rpc * cli->cl_max_rpcs_in_flight; | |
333 | if (npages > max_pages) | |
334 | npages = max_pages; | |
335 | ||
336 | c = atomic_read(cli->cl_lru_left); | |
337 | if (c < npages && osc_lru_reclaim(cli) > 0) | |
338 | c = atomic_read(cli->cl_lru_left); | |
339 | while (c >= npages) { | |
340 | if (c == atomic_cmpxchg(cli->cl_lru_left, c, c - npages)) { | |
341 | oio->oi_lru_reserved = npages; | |
342 | break; | |
343 | } | |
344 | c = atomic_read(cli->cl_lru_left); | |
345 | } | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | static void osc_io_rw_iter_fini(const struct lu_env *env, | |
351 | const struct cl_io_slice *ios) | |
352 | { | |
353 | struct osc_io *oio = osc_env_io(env); | |
354 | struct osc_object *osc = cl2osc(ios->cis_obj); | |
355 | struct client_obd *cli = osc_cli(osc); | |
356 | ||
357 | if (oio->oi_lru_reserved > 0) { | |
358 | atomic_add(oio->oi_lru_reserved, cli->cl_lru_left); | |
359 | oio->oi_lru_reserved = 0; | |
360 | } | |
06563b56 | 361 | oio->oi_write_osclock = NULL; |
5196e42c JX |
362 | } |
363 | ||
d7e09d03 PT |
364 | static int osc_io_fault_start(const struct lu_env *env, |
365 | const struct cl_io_slice *ios) | |
366 | { | |
29ac6840 | 367 | struct cl_io *io; |
d7e09d03 PT |
368 | struct cl_fault_io *fio; |
369 | ||
29ac6840 | 370 | io = ios->cis_io; |
d7e09d03 PT |
371 | fio = &io->u.ci_fault; |
372 | CDEBUG(D_INFO, "%lu %d %d\n", | |
373 | fio->ft_index, fio->ft_writable, fio->ft_nob); | |
374 | /* | |
375 | * If mapping is writeable, adjust kms to cover this page, | |
376 | * but do not extend kms beyond actual file size. | |
377 | * See bug 10919. | |
378 | */ | |
379 | if (fio->ft_writable) | |
380 | osc_page_touch_at(env, ios->cis_obj, | |
381 | fio->ft_index, fio->ft_nob); | |
0a3bdb00 | 382 | return 0; |
d7e09d03 PT |
383 | } |
384 | ||
385 | static int osc_async_upcall(void *a, int rc) | |
386 | { | |
387 | struct osc_async_cbargs *args = a; | |
388 | ||
389 | args->opc_rc = rc; | |
390 | complete(&args->opc_sync); | |
391 | return 0; | |
392 | } | |
393 | ||
394 | /** | |
395 | * Checks that there are no pages being written in the extent being truncated. | |
396 | */ | |
397 | static int trunc_check_cb(const struct lu_env *env, struct cl_io *io, | |
d9d47901 | 398 | struct osc_page *ops, void *cbdata) |
d7e09d03 | 399 | { |
d9d47901 | 400 | struct cl_page *page = ops->ops_cl.cpl_page; |
d7e09d03 PT |
401 | struct osc_async_page *oap; |
402 | __u64 start = *(__u64 *)cbdata; | |
403 | ||
d7e09d03 | 404 | oap = &ops->ops_oap; |
d7e09d03 PT |
405 | if (oap->oap_cmd & OBD_BRW_WRITE && |
406 | !list_empty(&oap->oap_pending_item)) | |
b0f5aad5 | 407 | CL_PAGE_DEBUG(D_ERROR, env, page, "exists %llu/%s.\n", |
79910d7d | 408 | start, current->comm); |
d7e09d03 | 409 | |
7addf402 JX |
410 | if (PageLocked(page->cp_vmpage)) |
411 | CDEBUG(D_CACHE, "page %p index %lu locked for %d.\n", | |
412 | ops, osc_index(ops), oap->oap_cmd & OBD_BRW_RWMASK); | |
d7e09d03 PT |
413 | |
414 | return CLP_GANG_OKAY; | |
415 | } | |
416 | ||
417 | static void osc_trunc_check(const struct lu_env *env, struct cl_io *io, | |
418 | struct osc_io *oio, __u64 size) | |
419 | { | |
420 | struct cl_object *clob; | |
29ac6840 | 421 | int partial; |
d7e09d03 PT |
422 | pgoff_t start; |
423 | ||
29ac6840 CH |
424 | clob = oio->oi_cl.cis_obj; |
425 | start = cl_index(clob, size); | |
d7e09d03 PT |
426 | partial = cl_offset(clob, start) < size; |
427 | ||
428 | /* | |
429 | * Complain if there are pages in the truncated region. | |
430 | */ | |
d9d47901 JX |
431 | osc_page_gang_lookup(env, io, cl2osc(clob), |
432 | start + partial, CL_PAGE_EOF, | |
433 | trunc_check_cb, (void *)&size); | |
d7e09d03 PT |
434 | } |
435 | ||
436 | static int osc_io_setattr_start(const struct lu_env *env, | |
437 | const struct cl_io_slice *slice) | |
438 | { | |
29ac6840 CH |
439 | struct cl_io *io = slice->cis_io; |
440 | struct osc_io *oio = cl2osc_io(env, slice); | |
441 | struct cl_object *obj = slice->cis_obj; | |
442 | struct lov_oinfo *loi = cl2osc(obj)->oo_oinfo; | |
443 | struct cl_attr *attr = &osc_env_info(env)->oti_attr; | |
444 | struct obdo *oa = &oio->oi_oa; | |
d7e09d03 | 445 | struct osc_async_cbargs *cbargs = &oio->oi_cbarg; |
29ac6840 CH |
446 | __u64 size = io->u.ci_setattr.sa_attr.lvb_size; |
447 | unsigned int ia_valid = io->u.ci_setattr.sa_valid; | |
448 | int result = 0; | |
45efd655 | 449 | struct obd_info oinfo = { }; |
d7e09d03 PT |
450 | |
451 | /* truncate cache dirty pages first */ | |
452 | if (cl_io_is_trunc(io)) | |
453 | result = osc_cache_truncate_start(env, oio, cl2osc(obj), size); | |
454 | ||
455 | if (result == 0 && oio->oi_lockless == 0) { | |
456 | cl_object_attr_lock(obj); | |
457 | result = cl_object_attr_get(env, obj, attr); | |
458 | if (result == 0) { | |
459 | struct ost_lvb *lvb = &io->u.ci_setattr.sa_attr; | |
460 | unsigned int cl_valid = 0; | |
461 | ||
462 | if (ia_valid & ATTR_SIZE) { | |
04a6284f NC |
463 | attr->cat_size = size; |
464 | attr->cat_kms = size; | |
b6ee3824 | 465 | cl_valid = CAT_SIZE | CAT_KMS; |
d7e09d03 PT |
466 | } |
467 | if (ia_valid & ATTR_MTIME_SET) { | |
468 | attr->cat_mtime = lvb->lvb_mtime; | |
469 | cl_valid |= CAT_MTIME; | |
470 | } | |
471 | if (ia_valid & ATTR_ATIME_SET) { | |
472 | attr->cat_atime = lvb->lvb_atime; | |
473 | cl_valid |= CAT_ATIME; | |
474 | } | |
475 | if (ia_valid & ATTR_CTIME_SET) { | |
476 | attr->cat_ctime = lvb->lvb_ctime; | |
477 | cl_valid |= CAT_CTIME; | |
478 | } | |
479 | result = cl_object_attr_set(env, obj, attr, cl_valid); | |
480 | } | |
481 | cl_object_attr_unlock(obj); | |
482 | } | |
483 | memset(oa, 0, sizeof(*oa)); | |
484 | if (result == 0) { | |
485 | oa->o_oi = loi->loi_oi; | |
486 | oa->o_mtime = attr->cat_mtime; | |
487 | oa->o_atime = attr->cat_atime; | |
488 | oa->o_ctime = attr->cat_ctime; | |
489 | oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP | OBD_MD_FLATIME | | |
490 | OBD_MD_FLCTIME | OBD_MD_FLMTIME; | |
491 | if (ia_valid & ATTR_SIZE) { | |
492 | oa->o_size = size; | |
493 | oa->o_blocks = OBD_OBJECT_EOF; | |
494 | oa->o_valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS; | |
495 | ||
496 | if (oio->oi_lockless) { | |
497 | oa->o_flags = OBD_FL_SRVLOCK; | |
498 | oa->o_valid |= OBD_MD_FLFLAGS; | |
499 | } | |
500 | } else { | |
501 | LASSERT(oio->oi_lockless == 0); | |
502 | } | |
503 | ||
504 | oinfo.oi_oa = oa; | |
d7e09d03 PT |
505 | init_completion(&cbargs->opc_sync); |
506 | ||
507 | if (ia_valid & ATTR_SIZE) | |
508 | result = osc_punch_base(osc_export(cl2osc(obj)), | |
509 | &oinfo, osc_async_upcall, | |
510 | cbargs, PTLRPCD_SET); | |
511 | else | |
512 | result = osc_setattr_async_base(osc_export(cl2osc(obj)), | |
513 | &oinfo, NULL, | |
514 | osc_async_upcall, | |
515 | cbargs, PTLRPCD_SET); | |
516 | cbargs->opc_rpc_sent = result == 0; | |
517 | } | |
518 | return result; | |
519 | } | |
520 | ||
521 | static void osc_io_setattr_end(const struct lu_env *env, | |
522 | const struct cl_io_slice *slice) | |
523 | { | |
29ac6840 CH |
524 | struct cl_io *io = slice->cis_io; |
525 | struct osc_io *oio = cl2osc_io(env, slice); | |
d7e09d03 PT |
526 | struct cl_object *obj = slice->cis_obj; |
527 | struct osc_async_cbargs *cbargs = &oio->oi_cbarg; | |
528 | int result = 0; | |
529 | ||
530 | if (cbargs->opc_rpc_sent) { | |
531 | wait_for_completion(&cbargs->opc_sync); | |
04a6284f NC |
532 | result = cbargs->opc_rc; |
533 | io->ci_result = cbargs->opc_rc; | |
d7e09d03 PT |
534 | } |
535 | if (result == 0) { | |
536 | if (oio->oi_lockless) { | |
537 | /* lockless truncate */ | |
538 | struct osc_device *osd = lu2osc_dev(obj->co_lu.lo_dev); | |
539 | ||
540 | LASSERT(cl_io_is_trunc(io)); | |
541 | /* XXX: Need a lock. */ | |
542 | osd->od_stats.os_lockless_truncates++; | |
543 | } | |
544 | } | |
545 | ||
546 | if (cl_io_is_trunc(io)) { | |
547 | __u64 size = io->u.ci_setattr.sa_attr.lvb_size; | |
1144b19f | 548 | |
d7e09d03 | 549 | osc_trunc_check(env, io, oio, size); |
7f1ae4c0 | 550 | if (oio->oi_trunc) { |
d7e09d03 PT |
551 | osc_cache_truncate_end(env, oio, cl2osc(obj)); |
552 | oio->oi_trunc = NULL; | |
553 | } | |
554 | } | |
555 | } | |
556 | ||
557 | static int osc_io_read_start(const struct lu_env *env, | |
558 | const struct cl_io_slice *slice) | |
559 | { | |
29ac6840 CH |
560 | struct cl_object *obj = slice->cis_obj; |
561 | struct cl_attr *attr = &osc_env_info(env)->oti_attr; | |
ec9bca9c | 562 | int rc = 0; |
d7e09d03 | 563 | |
beaa2647 | 564 | if (!slice->cis_io->ci_noatime) { |
d7e09d03 | 565 | cl_object_attr_lock(obj); |
46c360f9 | 566 | attr->cat_atime = ktime_get_real_seconds(); |
ec9bca9c | 567 | rc = cl_object_attr_set(env, obj, attr, CAT_ATIME); |
d7e09d03 PT |
568 | cl_object_attr_unlock(obj); |
569 | } | |
ec9bca9c | 570 | return rc; |
d7e09d03 PT |
571 | } |
572 | ||
573 | static int osc_io_write_start(const struct lu_env *env, | |
574 | const struct cl_io_slice *slice) | |
575 | { | |
29ac6840 CH |
576 | struct cl_object *obj = slice->cis_obj; |
577 | struct cl_attr *attr = &osc_env_info(env)->oti_attr; | |
beaa2647 | 578 | int rc = 0; |
d7e09d03 | 579 | |
beaa2647 SP |
580 | OBD_FAIL_TIMEOUT(OBD_FAIL_OSC_DELAY_SETTIME, 1); |
581 | cl_object_attr_lock(obj); | |
04a6284f NC |
582 | attr->cat_ctime = ktime_get_real_seconds(); |
583 | attr->cat_mtime = attr->cat_ctime; | |
beaa2647 SP |
584 | rc = cl_object_attr_set(env, obj, attr, CAT_MTIME | CAT_CTIME); |
585 | cl_object_attr_unlock(obj); | |
586 | ||
587 | return rc; | |
d7e09d03 PT |
588 | } |
589 | ||
590 | static int osc_fsync_ost(const struct lu_env *env, struct osc_object *obj, | |
591 | struct cl_fsync_io *fio) | |
592 | { | |
29ac6840 CH |
593 | struct osc_io *oio = osc_env_io(env); |
594 | struct obdo *oa = &oio->oi_oa; | |
595 | struct obd_info *oinfo = &oio->oi_info; | |
596 | struct lov_oinfo *loi = obj->oo_oinfo; | |
d7e09d03 PT |
597 | struct osc_async_cbargs *cbargs = &oio->oi_cbarg; |
598 | int rc = 0; | |
d7e09d03 PT |
599 | |
600 | memset(oa, 0, sizeof(*oa)); | |
601 | oa->o_oi = loi->loi_oi; | |
602 | oa->o_valid = OBD_MD_FLID | OBD_MD_FLGROUP; | |
603 | ||
604 | /* reload size abd blocks for start and end of sync range */ | |
605 | oa->o_size = fio->fi_start; | |
606 | oa->o_blocks = fio->fi_end; | |
607 | oa->o_valid |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS; | |
608 | ||
609 | obdo_set_parent_fid(oa, fio->fi_fid); | |
610 | ||
611 | memset(oinfo, 0, sizeof(*oinfo)); | |
612 | oinfo->oi_oa = oa; | |
d7e09d03 PT |
613 | init_completion(&cbargs->opc_sync); |
614 | ||
615 | rc = osc_sync_base(osc_export(obj), oinfo, osc_async_upcall, cbargs, | |
616 | PTLRPCD_SET); | |
0a3bdb00 | 617 | return rc; |
d7e09d03 PT |
618 | } |
619 | ||
620 | static int osc_io_fsync_start(const struct lu_env *env, | |
621 | const struct cl_io_slice *slice) | |
622 | { | |
29ac6840 | 623 | struct cl_io *io = slice->cis_io; |
d7e09d03 | 624 | struct cl_fsync_io *fio = &io->u.ci_fsync; |
29ac6840 CH |
625 | struct cl_object *obj = slice->cis_obj; |
626 | struct osc_object *osc = cl2osc(obj); | |
627 | pgoff_t start = cl_index(obj, fio->fi_start); | |
628 | pgoff_t end = cl_index(obj, fio->fi_end); | |
629 | int result = 0; | |
d7e09d03 PT |
630 | |
631 | if (fio->fi_end == OBD_OBJECT_EOF) | |
632 | end = CL_PAGE_EOF; | |
633 | ||
634 | result = osc_cache_writeback_range(env, osc, start, end, 0, | |
635 | fio->fi_mode == CL_FSYNC_DISCARD); | |
636 | if (result > 0) { | |
637 | fio->fi_nr_written += result; | |
638 | result = 0; | |
639 | } | |
640 | if (fio->fi_mode == CL_FSYNC_ALL) { | |
641 | int rc; | |
642 | ||
643 | /* we have to wait for writeback to finish before we can | |
644 | * send OST_SYNC RPC. This is bad because it causes extents | |
645 | * to be written osc by osc. However, we usually start | |
646 | * writeback before CL_FSYNC_ALL so this won't have any real | |
30aa9c52 OD |
647 | * problem. |
648 | */ | |
d7e09d03 PT |
649 | rc = osc_cache_wait_range(env, osc, start, end); |
650 | if (result == 0) | |
651 | result = rc; | |
652 | rc = osc_fsync_ost(env, osc, fio); | |
653 | if (result == 0) | |
654 | result = rc; | |
655 | } | |
656 | ||
0a3bdb00 | 657 | return result; |
d7e09d03 PT |
658 | } |
659 | ||
660 | static void osc_io_fsync_end(const struct lu_env *env, | |
661 | const struct cl_io_slice *slice) | |
662 | { | |
663 | struct cl_fsync_io *fio = &slice->cis_io->u.ci_fsync; | |
29ac6840 | 664 | struct cl_object *obj = slice->cis_obj; |
d7e09d03 | 665 | pgoff_t start = cl_index(obj, fio->fi_start); |
29ac6840 | 666 | pgoff_t end = cl_index(obj, fio->fi_end); |
d7e09d03 PT |
667 | int result = 0; |
668 | ||
669 | if (fio->fi_mode == CL_FSYNC_LOCAL) { | |
670 | result = osc_cache_wait_range(env, cl2osc(obj), start, end); | |
671 | } else if (fio->fi_mode == CL_FSYNC_ALL) { | |
29ac6840 | 672 | struct osc_io *oio = cl2osc_io(env, slice); |
d7e09d03 PT |
673 | struct osc_async_cbargs *cbargs = &oio->oi_cbarg; |
674 | ||
675 | wait_for_completion(&cbargs->opc_sync); | |
676 | if (result == 0) | |
677 | result = cbargs->opc_rc; | |
678 | } | |
679 | slice->cis_io->ci_result = result; | |
680 | } | |
681 | ||
682 | static void osc_io_end(const struct lu_env *env, | |
683 | const struct cl_io_slice *slice) | |
684 | { | |
685 | struct osc_io *oio = cl2osc_io(env, slice); | |
686 | ||
687 | if (oio->oi_active) { | |
688 | osc_extent_release(env, oio->oi_active); | |
689 | oio->oi_active = NULL; | |
690 | } | |
691 | } | |
692 | ||
693 | static const struct cl_io_operations osc_io_ops = { | |
694 | .op = { | |
695 | [CIT_READ] = { | |
696 | .cio_start = osc_io_read_start, | |
697 | .cio_fini = osc_io_fini | |
698 | }, | |
699 | [CIT_WRITE] = { | |
5196e42c JX |
700 | .cio_iter_init = osc_io_rw_iter_init, |
701 | .cio_iter_fini = osc_io_rw_iter_fini, | |
d7e09d03 PT |
702 | .cio_start = osc_io_write_start, |
703 | .cio_end = osc_io_end, | |
704 | .cio_fini = osc_io_fini | |
705 | }, | |
706 | [CIT_SETATTR] = { | |
707 | .cio_start = osc_io_setattr_start, | |
708 | .cio_end = osc_io_setattr_end | |
709 | }, | |
710 | [CIT_FAULT] = { | |
711 | .cio_start = osc_io_fault_start, | |
712 | .cio_end = osc_io_end, | |
713 | .cio_fini = osc_io_fini | |
714 | }, | |
715 | [CIT_FSYNC] = { | |
716 | .cio_start = osc_io_fsync_start, | |
717 | .cio_end = osc_io_fsync_end, | |
718 | .cio_fini = osc_io_fini | |
719 | }, | |
720 | [CIT_MISC] = { | |
721 | .cio_fini = osc_io_fini | |
722 | } | |
723 | }, | |
77605e41 JX |
724 | .cio_submit = osc_io_submit, |
725 | .cio_commit_async = osc_io_commit_async | |
d7e09d03 PT |
726 | }; |
727 | ||
728 | /***************************************************************************** | |
729 | * | |
730 | * Transfer operations. | |
731 | * | |
732 | */ | |
733 | ||
734 | static int osc_req_prep(const struct lu_env *env, | |
735 | const struct cl_req_slice *slice) | |
736 | { | |
737 | return 0; | |
738 | } | |
739 | ||
740 | static void osc_req_completion(const struct lu_env *env, | |
741 | const struct cl_req_slice *slice, int ioret) | |
742 | { | |
743 | struct osc_req *or; | |
744 | ||
745 | or = cl2osc_req(slice); | |
50d30362 | 746 | kmem_cache_free(osc_req_kmem, or); |
d7e09d03 PT |
747 | } |
748 | ||
749 | /** | |
750 | * Implementation of struct cl_req_operations::cro_attr_set() for osc | |
751 | * layer. osc is responsible for struct obdo::o_id and struct obdo::o_seq | |
752 | * fields. | |
753 | */ | |
754 | static void osc_req_attr_set(const struct lu_env *env, | |
755 | const struct cl_req_slice *slice, | |
756 | const struct cl_object *obj, | |
21aef7d9 | 757 | struct cl_req_attr *attr, u64 flags) |
d7e09d03 PT |
758 | { |
759 | struct lov_oinfo *oinfo; | |
29ac6840 CH |
760 | struct cl_req *clerq; |
761 | struct cl_page *apage; /* _some_ page in @clerq */ | |
06563b56 | 762 | struct ldlm_lock *lock; /* _some_ lock protecting @apage */ |
29ac6840 CH |
763 | struct osc_page *opg; |
764 | struct obdo *oa; | |
765 | struct ost_lvb *lvb; | |
766 | ||
767 | oinfo = cl2osc(obj)->oo_oinfo; | |
768 | lvb = &oinfo->loi_lvb; | |
769 | oa = attr->cra_oa; | |
d7e09d03 PT |
770 | |
771 | if ((flags & OBD_MD_FLMTIME) != 0) { | |
772 | oa->o_mtime = lvb->lvb_mtime; | |
773 | oa->o_valid |= OBD_MD_FLMTIME; | |
774 | } | |
775 | if ((flags & OBD_MD_FLATIME) != 0) { | |
776 | oa->o_atime = lvb->lvb_atime; | |
777 | oa->o_valid |= OBD_MD_FLATIME; | |
778 | } | |
779 | if ((flags & OBD_MD_FLCTIME) != 0) { | |
780 | oa->o_ctime = lvb->lvb_ctime; | |
781 | oa->o_valid |= OBD_MD_FLCTIME; | |
782 | } | |
783 | if (flags & OBD_MD_FLGROUP) { | |
784 | ostid_set_seq(&oa->o_oi, ostid_seq(&oinfo->loi_oi)); | |
785 | oa->o_valid |= OBD_MD_FLGROUP; | |
786 | } | |
787 | if (flags & OBD_MD_FLID) { | |
788 | ostid_set_id(&oa->o_oi, ostid_id(&oinfo->loi_oi)); | |
789 | oa->o_valid |= OBD_MD_FLID; | |
790 | } | |
791 | if (flags & OBD_MD_FLHANDLE) { | |
792 | clerq = slice->crs_req; | |
793 | LASSERT(!list_empty(&clerq->crq_pages)); | |
794 | apage = container_of(clerq->crq_pages.next, | |
795 | struct cl_page, cp_flight); | |
7addf402 | 796 | opg = osc_cl_page_osc(apage, NULL); |
06563b56 JX |
797 | lock = osc_dlmlock_at_pgoff(env, cl2osc(obj), osc_index(opg), |
798 | 1, 1); | |
799 | if (!lock && !opg->ops_srvlock) { | |
800 | struct ldlm_resource *res; | |
801 | struct ldlm_res_id *resname; | |
802 | ||
803 | CL_PAGE_DEBUG(D_ERROR, env, apage, "uncovered page!\n"); | |
804 | ||
805 | resname = &osc_env_info(env)->oti_resname; | |
806 | ostid_build_res_name(&oinfo->loi_oi, resname); | |
807 | res = ldlm_resource_get( | |
808 | osc_export(cl2osc(obj))->exp_obd->obd_namespace, | |
809 | NULL, resname, LDLM_EXTENT, 0); | |
810 | ldlm_resource_dump(D_ERROR, res); | |
811 | ||
5d4450c4 | 812 | dump_stack(); |
d7e09d03 PT |
813 | LBUG(); |
814 | } | |
815 | ||
d7e09d03 | 816 | /* check for lockless io. */ |
06563b56 JX |
817 | if (lock) { |
818 | oa->o_handle = lock->l_remote_handle; | |
d7e09d03 | 819 | oa->o_valid |= OBD_MD_FLHANDLE; |
06563b56 | 820 | LDLM_LOCK_PUT(lock); |
d7e09d03 | 821 | } |
d7e09d03 PT |
822 | } |
823 | } | |
824 | ||
825 | static const struct cl_req_operations osc_req_ops = { | |
826 | .cro_prep = osc_req_prep, | |
827 | .cro_attr_set = osc_req_attr_set, | |
828 | .cro_completion = osc_req_completion | |
829 | }; | |
830 | ||
d7e09d03 PT |
831 | int osc_io_init(const struct lu_env *env, |
832 | struct cl_object *obj, struct cl_io *io) | |
833 | { | |
834 | struct osc_io *oio = osc_env_io(env); | |
835 | ||
836 | CL_IO_SLICE_CLEAN(oio, oi_cl); | |
837 | cl_io_slice_add(io, &oio->oi_cl, obj, &osc_io_ops); | |
838 | return 0; | |
839 | } | |
840 | ||
841 | int osc_req_init(const struct lu_env *env, struct cl_device *dev, | |
842 | struct cl_req *req) | |
843 | { | |
844 | struct osc_req *or; | |
845 | int result; | |
846 | ||
c4418dac | 847 | or = kmem_cache_zalloc(osc_req_kmem, GFP_NOFS); |
7f1ae4c0 | 848 | if (or) { |
d7e09d03 PT |
849 | cl_req_slice_add(req, &or->or_cl, dev, &osc_req_ops); |
850 | result = 0; | |
da5ecb4d | 851 | } else { |
d7e09d03 | 852 | result = -ENOMEM; |
da5ecb4d | 853 | } |
d7e09d03 PT |
854 | return result; |
855 | } | |
856 | ||
857 | /** @} osc */ |