diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-29 17:10:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-29 17:10:13 -0400 |
commit | cd1acdf1723d71b28175f95b04305f1cc74ce363 (patch) | |
tree | 7ab58883eccd314be3d8efafd59a124d4ffbb861 /fs/nfs/pnfs.c | |
parent | fac04863cef53a69830590b2e1c54345068a9747 (diff) | |
parent | 9342077011d54f42fa1b88b7bc1f7008dcf5fff9 (diff) |
Merge branch 'pnfs-submit' of git://git.open-osd.org/linux-open-osd
* 'pnfs-submit' of git://git.open-osd.org/linux-open-osd: (32 commits)
pnfs-obj: pg_test check for max_io_size
NFSv4.1: define nfs_generic_pg_test
NFSv4.1: use pnfs_generic_pg_test directly by layout driver
NFSv4.1: change pg_test return type to bool
NFSv4.1: unify pnfs_pageio_init functions
pnfs-obj: objlayout_encode_layoutcommit implementation
pnfs: encode_layoutcommit
pnfs-obj: report errors and .encode_layoutreturn Implementation.
pnfs: encode_layoutreturn
pnfs: layoutret_on_setattr
pnfs: layoutreturn
pnfs-obj: osd raid engine read/write implementation
pnfs: support for non-rpc layout drivers
pnfs-obj: define per-inode private structure
pnfs: alloc and free layout_hdr layoutdriver methods
pnfs-obj: objio_osd device information retrieval and caching
pnfs-obj: decode layout, alloc/free lseg
pnfs-obj: pnfs_osd XDR client implementation
pnfs-obj: pnfs_osd XDR definitions
pnfs-obj: objlayoutdriver module skeleton
...
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 340 |
1 files changed, 262 insertions, 78 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 101c85a3644e..8c1309d852a6 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -177,13 +177,28 @@ get_layout_hdr(struct pnfs_layout_hdr *lo) | |||
177 | atomic_inc(&lo->plh_refcount); | 177 | atomic_inc(&lo->plh_refcount); |
178 | } | 178 | } |
179 | 179 | ||
180 | static struct pnfs_layout_hdr * | ||
181 | pnfs_alloc_layout_hdr(struct inode *ino, gfp_t gfp_flags) | ||
182 | { | ||
183 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(ino)->pnfs_curr_ld; | ||
184 | return ld->alloc_layout_hdr ? ld->alloc_layout_hdr(ino, gfp_flags) : | ||
185 | kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags); | ||
186 | } | ||
187 | |||
188 | static void | ||
189 | pnfs_free_layout_hdr(struct pnfs_layout_hdr *lo) | ||
190 | { | ||
191 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(lo->plh_inode)->pnfs_curr_ld; | ||
192 | return ld->alloc_layout_hdr ? ld->free_layout_hdr(lo) : kfree(lo); | ||
193 | } | ||
194 | |||
180 | static void | 195 | static void |
181 | destroy_layout_hdr(struct pnfs_layout_hdr *lo) | 196 | destroy_layout_hdr(struct pnfs_layout_hdr *lo) |
182 | { | 197 | { |
183 | dprintk("%s: freeing layout cache %p\n", __func__, lo); | 198 | dprintk("%s: freeing layout cache %p\n", __func__, lo); |
184 | BUG_ON(!list_empty(&lo->plh_layouts)); | 199 | BUG_ON(!list_empty(&lo->plh_layouts)); |
185 | NFS_I(lo->plh_inode)->layout = NULL; | 200 | NFS_I(lo->plh_inode)->layout = NULL; |
186 | kfree(lo); | 201 | pnfs_free_layout_hdr(lo); |
187 | } | 202 | } |
188 | 203 | ||
189 | static void | 204 | static void |
@@ -228,7 +243,7 @@ put_lseg_common(struct pnfs_layout_segment *lseg) | |||
228 | { | 243 | { |
229 | struct inode *inode = lseg->pls_layout->plh_inode; | 244 | struct inode *inode = lseg->pls_layout->plh_inode; |
230 | 245 | ||
231 | BUG_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); | 246 | WARN_ON(test_bit(NFS_LSEG_VALID, &lseg->pls_flags)); |
232 | list_del_init(&lseg->pls_list); | 247 | list_del_init(&lseg->pls_list); |
233 | if (list_empty(&lseg->pls_layout->plh_segs)) { | 248 | if (list_empty(&lseg->pls_layout->plh_segs)) { |
234 | set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); | 249 | set_bit(NFS_LAYOUT_DESTROYED, &lseg->pls_layout->plh_flags); |
@@ -261,11 +276,72 @@ put_lseg(struct pnfs_layout_segment *lseg) | |||
261 | } | 276 | } |
262 | EXPORT_SYMBOL_GPL(put_lseg); | 277 | EXPORT_SYMBOL_GPL(put_lseg); |
263 | 278 | ||
279 | static inline u64 | ||
280 | end_offset(u64 start, u64 len) | ||
281 | { | ||
282 | u64 end; | ||
283 | |||
284 | end = start + len; | ||
285 | return end >= start ? end : NFS4_MAX_UINT64; | ||
286 | } | ||
287 | |||
288 | /* last octet in a range */ | ||
289 | static inline u64 | ||
290 | last_byte_offset(u64 start, u64 len) | ||
291 | { | ||
292 | u64 end; | ||
293 | |||
294 | BUG_ON(!len); | ||
295 | end = start + len; | ||
296 | return end > start ? end - 1 : NFS4_MAX_UINT64; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * is l2 fully contained in l1? | ||
301 | * start1 end1 | ||
302 | * [----------------------------------) | ||
303 | * start2 end2 | ||
304 | * [----------------) | ||
305 | */ | ||
306 | static inline int | ||
307 | lo_seg_contained(struct pnfs_layout_range *l1, | ||
308 | struct pnfs_layout_range *l2) | ||
309 | { | ||
310 | u64 start1 = l1->offset; | ||
311 | u64 end1 = end_offset(start1, l1->length); | ||
312 | u64 start2 = l2->offset; | ||
313 | u64 end2 = end_offset(start2, l2->length); | ||
314 | |||
315 | return (start1 <= start2) && (end1 >= end2); | ||
316 | } | ||
317 | |||
318 | /* | ||
319 | * is l1 and l2 intersecting? | ||
320 | * start1 end1 | ||
321 | * [----------------------------------) | ||
322 | * start2 end2 | ||
323 | * [----------------) | ||
324 | */ | ||
325 | static inline int | ||
326 | lo_seg_intersecting(struct pnfs_layout_range *l1, | ||
327 | struct pnfs_layout_range *l2) | ||
328 | { | ||
329 | u64 start1 = l1->offset; | ||
330 | u64 end1 = end_offset(start1, l1->length); | ||
331 | u64 start2 = l2->offset; | ||
332 | u64 end2 = end_offset(start2, l2->length); | ||
333 | |||
334 | return (end1 == NFS4_MAX_UINT64 || end1 > start2) && | ||
335 | (end2 == NFS4_MAX_UINT64 || end2 > start1); | ||
336 | } | ||
337 | |||
264 | static bool | 338 | static bool |
265 | should_free_lseg(u32 lseg_iomode, u32 recall_iomode) | 339 | should_free_lseg(struct pnfs_layout_range *lseg_range, |
340 | struct pnfs_layout_range *recall_range) | ||
266 | { | 341 | { |
267 | return (recall_iomode == IOMODE_ANY || | 342 | return (recall_range->iomode == IOMODE_ANY || |
268 | lseg_iomode == recall_iomode); | 343 | lseg_range->iomode == recall_range->iomode) && |
344 | lo_seg_intersecting(lseg_range, recall_range); | ||
269 | } | 345 | } |
270 | 346 | ||
271 | /* Returns 1 if lseg is removed from list, 0 otherwise */ | 347 | /* Returns 1 if lseg is removed from list, 0 otherwise */ |
@@ -296,7 +372,7 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | |||
296 | int | 372 | int |
297 | mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | 373 | mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, |
298 | struct list_head *tmp_list, | 374 | struct list_head *tmp_list, |
299 | u32 iomode) | 375 | struct pnfs_layout_range *recall_range) |
300 | { | 376 | { |
301 | struct pnfs_layout_segment *lseg, *next; | 377 | struct pnfs_layout_segment *lseg, *next; |
302 | int invalid = 0, removed = 0; | 378 | int invalid = 0, removed = 0; |
@@ -309,7 +385,8 @@ mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo, | |||
309 | return 0; | 385 | return 0; |
310 | } | 386 | } |
311 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) | 387 | list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) |
312 | if (should_free_lseg(lseg->pls_range.iomode, iomode)) { | 388 | if (!recall_range || |
389 | should_free_lseg(&lseg->pls_range, recall_range)) { | ||
313 | dprintk("%s: freeing lseg %p iomode %d " | 390 | dprintk("%s: freeing lseg %p iomode %d " |
314 | "offset %llu length %llu\n", __func__, | 391 | "offset %llu length %llu\n", __func__, |
315 | lseg, lseg->pls_range.iomode, lseg->pls_range.offset, | 392 | lseg, lseg->pls_range.iomode, lseg->pls_range.offset, |
@@ -358,7 +435,7 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) | |||
358 | lo = nfsi->layout; | 435 | lo = nfsi->layout; |
359 | if (lo) { | 436 | if (lo) { |
360 | lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ | 437 | lo->plh_block_lgets++; /* permanently block new LAYOUTGETs */ |
361 | mark_matching_lsegs_invalid(lo, &tmp_list, IOMODE_ANY); | 438 | mark_matching_lsegs_invalid(lo, &tmp_list, NULL); |
362 | } | 439 | } |
363 | spin_unlock(&nfsi->vfs_inode.i_lock); | 440 | spin_unlock(&nfsi->vfs_inode.i_lock); |
364 | pnfs_free_lseg_list(&tmp_list); | 441 | pnfs_free_lseg_list(&tmp_list); |
@@ -467,7 +544,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | |||
467 | static struct pnfs_layout_segment * | 544 | static struct pnfs_layout_segment * |
468 | send_layoutget(struct pnfs_layout_hdr *lo, | 545 | send_layoutget(struct pnfs_layout_hdr *lo, |
469 | struct nfs_open_context *ctx, | 546 | struct nfs_open_context *ctx, |
470 | u32 iomode, | 547 | struct pnfs_layout_range *range, |
471 | gfp_t gfp_flags) | 548 | gfp_t gfp_flags) |
472 | { | 549 | { |
473 | struct inode *ino = lo->plh_inode; | 550 | struct inode *ino = lo->plh_inode; |
@@ -499,11 +576,11 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
499 | goto out_err_free; | 576 | goto out_err_free; |
500 | } | 577 | } |
501 | 578 | ||
502 | lgp->args.minlength = NFS4_MAX_UINT64; | 579 | lgp->args.minlength = PAGE_CACHE_SIZE; |
580 | if (lgp->args.minlength > range->length) | ||
581 | lgp->args.minlength = range->length; | ||
503 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; | 582 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; |
504 | lgp->args.range.iomode = iomode; | 583 | lgp->args.range = *range; |
505 | lgp->args.range.offset = 0; | ||
506 | lgp->args.range.length = NFS4_MAX_UINT64; | ||
507 | lgp->args.type = server->pnfs_curr_ld->id; | 584 | lgp->args.type = server->pnfs_curr_ld->id; |
508 | lgp->args.inode = ino; | 585 | lgp->args.inode = ino; |
509 | lgp->args.ctx = get_nfs_open_context(ctx); | 586 | lgp->args.ctx = get_nfs_open_context(ctx); |
@@ -518,7 +595,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
518 | nfs4_proc_layoutget(lgp); | 595 | nfs4_proc_layoutget(lgp); |
519 | if (!lseg) { | 596 | if (!lseg) { |
520 | /* remember that LAYOUTGET failed and suspend trying */ | 597 | /* remember that LAYOUTGET failed and suspend trying */ |
521 | set_bit(lo_fail_bit(iomode), &lo->plh_flags); | 598 | set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); |
522 | } | 599 | } |
523 | 600 | ||
524 | /* free xdr pages */ | 601 | /* free xdr pages */ |
@@ -542,6 +619,51 @@ out_err_free: | |||
542 | return NULL; | 619 | return NULL; |
543 | } | 620 | } |
544 | 621 | ||
622 | /* Initiates a LAYOUTRETURN(FILE) */ | ||
623 | int | ||
624 | _pnfs_return_layout(struct inode *ino) | ||
625 | { | ||
626 | struct pnfs_layout_hdr *lo = NULL; | ||
627 | struct nfs_inode *nfsi = NFS_I(ino); | ||
628 | LIST_HEAD(tmp_list); | ||
629 | struct nfs4_layoutreturn *lrp; | ||
630 | nfs4_stateid stateid; | ||
631 | int status = 0; | ||
632 | |||
633 | dprintk("--> %s\n", __func__); | ||
634 | |||
635 | spin_lock(&ino->i_lock); | ||
636 | lo = nfsi->layout; | ||
637 | if (!lo || !mark_matching_lsegs_invalid(lo, &tmp_list, NULL)) { | ||
638 | spin_unlock(&ino->i_lock); | ||
639 | dprintk("%s: no layout segments to return\n", __func__); | ||
640 | goto out; | ||
641 | } | ||
642 | stateid = nfsi->layout->plh_stateid; | ||
643 | /* Reference matched in nfs4_layoutreturn_release */ | ||
644 | get_layout_hdr(lo); | ||
645 | spin_unlock(&ino->i_lock); | ||
646 | pnfs_free_lseg_list(&tmp_list); | ||
647 | |||
648 | WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); | ||
649 | |||
650 | lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); | ||
651 | if (unlikely(lrp == NULL)) { | ||
652 | status = -ENOMEM; | ||
653 | goto out; | ||
654 | } | ||
655 | |||
656 | lrp->args.stateid = stateid; | ||
657 | lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id; | ||
658 | lrp->args.inode = ino; | ||
659 | lrp->clp = NFS_SERVER(ino)->nfs_client; | ||
660 | |||
661 | status = nfs4_proc_layoutreturn(lrp); | ||
662 | out: | ||
663 | dprintk("<-- %s status: %d\n", __func__, status); | ||
664 | return status; | ||
665 | } | ||
666 | |||
545 | bool pnfs_roc(struct inode *ino) | 667 | bool pnfs_roc(struct inode *ino) |
546 | { | 668 | { |
547 | struct pnfs_layout_hdr *lo; | 669 | struct pnfs_layout_hdr *lo; |
@@ -625,10 +747,23 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier) | |||
625 | * are seen first. | 747 | * are seen first. |
626 | */ | 748 | */ |
627 | static s64 | 749 | static s64 |
628 | cmp_layout(u32 iomode1, u32 iomode2) | 750 | cmp_layout(struct pnfs_layout_range *l1, |
751 | struct pnfs_layout_range *l2) | ||
629 | { | 752 | { |
753 | s64 d; | ||
754 | |||
755 | /* high offset > low offset */ | ||
756 | d = l1->offset - l2->offset; | ||
757 | if (d) | ||
758 | return d; | ||
759 | |||
760 | /* short length > long length */ | ||
761 | d = l2->length - l1->length; | ||
762 | if (d) | ||
763 | return d; | ||
764 | |||
630 | /* read > read/write */ | 765 | /* read > read/write */ |
631 | return (int)(iomode2 == IOMODE_READ) - (int)(iomode1 == IOMODE_READ); | 766 | return (int)(l1->iomode == IOMODE_READ) - (int)(l2->iomode == IOMODE_READ); |
632 | } | 767 | } |
633 | 768 | ||
634 | static void | 769 | static void |
@@ -636,13 +771,12 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, | |||
636 | struct pnfs_layout_segment *lseg) | 771 | struct pnfs_layout_segment *lseg) |
637 | { | 772 | { |
638 | struct pnfs_layout_segment *lp; | 773 | struct pnfs_layout_segment *lp; |
639 | int found = 0; | ||
640 | 774 | ||
641 | dprintk("%s:Begin\n", __func__); | 775 | dprintk("%s:Begin\n", __func__); |
642 | 776 | ||
643 | assert_spin_locked(&lo->plh_inode->i_lock); | 777 | assert_spin_locked(&lo->plh_inode->i_lock); |
644 | list_for_each_entry(lp, &lo->plh_segs, pls_list) { | 778 | list_for_each_entry(lp, &lo->plh_segs, pls_list) { |
645 | if (cmp_layout(lp->pls_range.iomode, lseg->pls_range.iomode) > 0) | 779 | if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0) |
646 | continue; | 780 | continue; |
647 | list_add_tail(&lseg->pls_list, &lp->pls_list); | 781 | list_add_tail(&lseg->pls_list, &lp->pls_list); |
648 | dprintk("%s: inserted lseg %p " | 782 | dprintk("%s: inserted lseg %p " |
@@ -652,16 +786,14 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, | |||
652 | lseg->pls_range.offset, lseg->pls_range.length, | 786 | lseg->pls_range.offset, lseg->pls_range.length, |
653 | lp, lp->pls_range.iomode, lp->pls_range.offset, | 787 | lp, lp->pls_range.iomode, lp->pls_range.offset, |
654 | lp->pls_range.length); | 788 | lp->pls_range.length); |
655 | found = 1; | 789 | goto out; |
656 | break; | ||
657 | } | ||
658 | if (!found) { | ||
659 | list_add_tail(&lseg->pls_list, &lo->plh_segs); | ||
660 | dprintk("%s: inserted lseg %p " | ||
661 | "iomode %d offset %llu length %llu at tail\n", | ||
662 | __func__, lseg, lseg->pls_range.iomode, | ||
663 | lseg->pls_range.offset, lseg->pls_range.length); | ||
664 | } | 790 | } |
791 | list_add_tail(&lseg->pls_list, &lo->plh_segs); | ||
792 | dprintk("%s: inserted lseg %p " | ||
793 | "iomode %d offset %llu length %llu at tail\n", | ||
794 | __func__, lseg, lseg->pls_range.iomode, | ||
795 | lseg->pls_range.offset, lseg->pls_range.length); | ||
796 | out: | ||
665 | get_layout_hdr(lo); | 797 | get_layout_hdr(lo); |
666 | 798 | ||
667 | dprintk("%s:Return\n", __func__); | 799 | dprintk("%s:Return\n", __func__); |
@@ -672,7 +804,7 @@ alloc_init_layout_hdr(struct inode *ino, gfp_t gfp_flags) | |||
672 | { | 804 | { |
673 | struct pnfs_layout_hdr *lo; | 805 | struct pnfs_layout_hdr *lo; |
674 | 806 | ||
675 | lo = kzalloc(sizeof(struct pnfs_layout_hdr), gfp_flags); | 807 | lo = pnfs_alloc_layout_hdr(ino, gfp_flags); |
676 | if (!lo) | 808 | if (!lo) |
677 | return NULL; | 809 | return NULL; |
678 | atomic_set(&lo->plh_refcount, 1); | 810 | atomic_set(&lo->plh_refcount, 1); |
@@ -705,7 +837,7 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) | |||
705 | if (likely(nfsi->layout == NULL)) /* Won the race? */ | 837 | if (likely(nfsi->layout == NULL)) /* Won the race? */ |
706 | nfsi->layout = new; | 838 | nfsi->layout = new; |
707 | else | 839 | else |
708 | kfree(new); | 840 | pnfs_free_layout_hdr(new); |
709 | return nfsi->layout; | 841 | return nfsi->layout; |
710 | } | 842 | } |
711 | 843 | ||
@@ -721,16 +853,28 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) | |||
721 | * READ RW true | 853 | * READ RW true |
722 | */ | 854 | */ |
723 | static int | 855 | static int |
724 | is_matching_lseg(struct pnfs_layout_segment *lseg, u32 iomode) | 856 | is_matching_lseg(struct pnfs_layout_range *ls_range, |
857 | struct pnfs_layout_range *range) | ||
725 | { | 858 | { |
726 | return (iomode != IOMODE_RW || lseg->pls_range.iomode == IOMODE_RW); | 859 | struct pnfs_layout_range range1; |
860 | |||
861 | if ((range->iomode == IOMODE_RW && | ||
862 | ls_range->iomode != IOMODE_RW) || | ||
863 | !lo_seg_intersecting(ls_range, range)) | ||
864 | return 0; | ||
865 | |||
866 | /* range1 covers only the first byte in the range */ | ||
867 | range1 = *range; | ||
868 | range1.length = 1; | ||
869 | return lo_seg_contained(ls_range, &range1); | ||
727 | } | 870 | } |
728 | 871 | ||
729 | /* | 872 | /* |
730 | * lookup range in layout | 873 | * lookup range in layout |
731 | */ | 874 | */ |
732 | static struct pnfs_layout_segment * | 875 | static struct pnfs_layout_segment * |
733 | pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) | 876 | pnfs_find_lseg(struct pnfs_layout_hdr *lo, |
877 | struct pnfs_layout_range *range) | ||
734 | { | 878 | { |
735 | struct pnfs_layout_segment *lseg, *ret = NULL; | 879 | struct pnfs_layout_segment *lseg, *ret = NULL; |
736 | 880 | ||
@@ -739,11 +883,11 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) | |||
739 | assert_spin_locked(&lo->plh_inode->i_lock); | 883 | assert_spin_locked(&lo->plh_inode->i_lock); |
740 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { | 884 | list_for_each_entry(lseg, &lo->plh_segs, pls_list) { |
741 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && | 885 | if (test_bit(NFS_LSEG_VALID, &lseg->pls_flags) && |
742 | is_matching_lseg(lseg, iomode)) { | 886 | is_matching_lseg(&lseg->pls_range, range)) { |
743 | ret = get_lseg(lseg); | 887 | ret = get_lseg(lseg); |
744 | break; | 888 | break; |
745 | } | 889 | } |
746 | if (cmp_layout(iomode, lseg->pls_range.iomode) > 0) | 890 | if (cmp_layout(range, &lseg->pls_range) > 0) |
747 | break; | 891 | break; |
748 | } | 892 | } |
749 | 893 | ||
@@ -759,9 +903,17 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, u32 iomode) | |||
759 | struct pnfs_layout_segment * | 903 | struct pnfs_layout_segment * |
760 | pnfs_update_layout(struct inode *ino, | 904 | pnfs_update_layout(struct inode *ino, |
761 | struct nfs_open_context *ctx, | 905 | struct nfs_open_context *ctx, |
906 | loff_t pos, | ||
907 | u64 count, | ||
762 | enum pnfs_iomode iomode, | 908 | enum pnfs_iomode iomode, |
763 | gfp_t gfp_flags) | 909 | gfp_t gfp_flags) |
764 | { | 910 | { |
911 | struct pnfs_layout_range arg = { | ||
912 | .iomode = iomode, | ||
913 | .offset = pos, | ||
914 | .length = count, | ||
915 | }; | ||
916 | unsigned pg_offset; | ||
765 | struct nfs_inode *nfsi = NFS_I(ino); | 917 | struct nfs_inode *nfsi = NFS_I(ino); |
766 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; | 918 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; |
767 | struct pnfs_layout_hdr *lo; | 919 | struct pnfs_layout_hdr *lo; |
@@ -789,7 +941,7 @@ pnfs_update_layout(struct inode *ino, | |||
789 | goto out_unlock; | 941 | goto out_unlock; |
790 | 942 | ||
791 | /* Check to see if the layout for the given range already exists */ | 943 | /* Check to see if the layout for the given range already exists */ |
792 | lseg = pnfs_find_lseg(lo, iomode); | 944 | lseg = pnfs_find_lseg(lo, &arg); |
793 | if (lseg) | 945 | if (lseg) |
794 | goto out_unlock; | 946 | goto out_unlock; |
795 | 947 | ||
@@ -811,7 +963,14 @@ pnfs_update_layout(struct inode *ino, | |||
811 | spin_unlock(&clp->cl_lock); | 963 | spin_unlock(&clp->cl_lock); |
812 | } | 964 | } |
813 | 965 | ||
814 | lseg = send_layoutget(lo, ctx, iomode, gfp_flags); | 966 | pg_offset = arg.offset & ~PAGE_CACHE_MASK; |
967 | if (pg_offset) { | ||
968 | arg.offset -= pg_offset; | ||
969 | arg.length += pg_offset; | ||
970 | } | ||
971 | arg.length = PAGE_CACHE_ALIGN(arg.length); | ||
972 | |||
973 | lseg = send_layoutget(lo, ctx, &arg, gfp_flags); | ||
815 | if (!lseg && first) { | 974 | if (!lseg && first) { |
816 | spin_lock(&clp->cl_lock); | 975 | spin_lock(&clp->cl_lock); |
817 | list_del_init(&lo->plh_layouts); | 976 | list_del_init(&lo->plh_layouts); |
@@ -838,17 +997,6 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) | |||
838 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; | 997 | struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; |
839 | int status = 0; | 998 | int status = 0; |
840 | 999 | ||
841 | /* Verify we got what we asked for. | ||
842 | * Note that because the xdr parsing only accepts a single | ||
843 | * element array, this can fail even if the server is behaving | ||
844 | * correctly. | ||
845 | */ | ||
846 | if (lgp->args.range.iomode > res->range.iomode || | ||
847 | res->range.offset != 0 || | ||
848 | res->range.length != NFS4_MAX_UINT64) { | ||
849 | status = -EINVAL; | ||
850 | goto out; | ||
851 | } | ||
852 | /* Inject layout blob into I/O device driver */ | 1000 | /* Inject layout blob into I/O device driver */ |
853 | lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags); | 1001 | lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags); |
854 | if (!lseg || IS_ERR(lseg)) { | 1002 | if (!lseg || IS_ERR(lseg)) { |
@@ -895,51 +1043,64 @@ out_forget_reply: | |||
895 | goto out; | 1043 | goto out; |
896 | } | 1044 | } |
897 | 1045 | ||
898 | static int pnfs_read_pg_test(struct nfs_pageio_descriptor *pgio, | 1046 | bool |
899 | struct nfs_page *prev, | 1047 | pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, |
900 | struct nfs_page *req) | 1048 | struct nfs_page *req) |
901 | { | 1049 | { |
1050 | enum pnfs_iomode access_type; | ||
1051 | gfp_t gfp_flags; | ||
1052 | |||
1053 | /* We assume that pg_ioflags == 0 iff we're reading a page */ | ||
1054 | if (pgio->pg_ioflags == 0) { | ||
1055 | access_type = IOMODE_READ; | ||
1056 | gfp_flags = GFP_KERNEL; | ||
1057 | } else { | ||
1058 | access_type = IOMODE_RW; | ||
1059 | gfp_flags = GFP_NOFS; | ||
1060 | } | ||
1061 | |||
902 | if (pgio->pg_count == prev->wb_bytes) { | 1062 | if (pgio->pg_count == prev->wb_bytes) { |
903 | /* This is first coelesce call for a series of nfs_pages */ | 1063 | /* This is first coelesce call for a series of nfs_pages */ |
904 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | 1064 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, |
905 | prev->wb_context, | 1065 | prev->wb_context, |
906 | IOMODE_READ, | 1066 | req_offset(req), |
907 | GFP_KERNEL); | 1067 | pgio->pg_count, |
1068 | access_type, | ||
1069 | gfp_flags); | ||
1070 | return true; | ||
908 | } | 1071 | } |
909 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); | ||
910 | } | ||
911 | 1072 | ||
912 | void | 1073 | if (pgio->pg_lseg && |
913 | pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode) | 1074 | req_offset(req) > end_offset(pgio->pg_lseg->pls_range.offset, |
914 | { | 1075 | pgio->pg_lseg->pls_range.length)) |
915 | struct pnfs_layoutdriver_type *ld; | 1076 | return false; |
916 | 1077 | ||
917 | ld = NFS_SERVER(inode)->pnfs_curr_ld; | 1078 | return true; |
918 | pgio->pg_test = (ld && ld->pg_test) ? pnfs_read_pg_test : NULL; | ||
919 | } | 1079 | } |
1080 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); | ||
920 | 1081 | ||
921 | static int pnfs_write_pg_test(struct nfs_pageio_descriptor *pgio, | 1082 | /* |
922 | struct nfs_page *prev, | 1083 | * Called by non rpc-based layout drivers |
923 | struct nfs_page *req) | 1084 | */ |
1085 | int | ||
1086 | pnfs_ld_write_done(struct nfs_write_data *data) | ||
924 | { | 1087 | { |
925 | if (pgio->pg_count == prev->wb_bytes) { | 1088 | int status; |
926 | /* This is first coelesce call for a series of nfs_pages */ | ||
927 | pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, | ||
928 | prev->wb_context, | ||
929 | IOMODE_RW, | ||
930 | GFP_NOFS); | ||
931 | } | ||
932 | return NFS_SERVER(pgio->pg_inode)->pnfs_curr_ld->pg_test(pgio, prev, req); | ||
933 | } | ||
934 | 1089 | ||
935 | void | 1090 | if (!data->pnfs_error) { |
936 | pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode) | 1091 | pnfs_set_layoutcommit(data); |
937 | { | 1092 | data->mds_ops->rpc_call_done(&data->task, data); |
938 | struct pnfs_layoutdriver_type *ld; | 1093 | data->mds_ops->rpc_release(data); |
1094 | return 0; | ||
1095 | } | ||
939 | 1096 | ||
940 | ld = NFS_SERVER(inode)->pnfs_curr_ld; | 1097 | dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__, |
941 | pgio->pg_test = (ld && ld->pg_test) ? pnfs_write_pg_test : NULL; | 1098 | data->pnfs_error); |
1099 | status = nfs_initiate_write(data, NFS_CLIENT(data->inode), | ||
1100 | data->mds_ops, NFS_FILE_SYNC); | ||
1101 | return status ? : -EAGAIN; | ||
942 | } | 1102 | } |
1103 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); | ||
943 | 1104 | ||
944 | enum pnfs_try_status | 1105 | enum pnfs_try_status |
945 | pnfs_try_to_write_data(struct nfs_write_data *wdata, | 1106 | pnfs_try_to_write_data(struct nfs_write_data *wdata, |
@@ -966,6 +1127,29 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata, | |||
966 | } | 1127 | } |
967 | 1128 | ||
968 | /* | 1129 | /* |
1130 | * Called by non rpc-based layout drivers | ||
1131 | */ | ||
1132 | int | ||
1133 | pnfs_ld_read_done(struct nfs_read_data *data) | ||
1134 | { | ||
1135 | int status; | ||
1136 | |||
1137 | if (!data->pnfs_error) { | ||
1138 | __nfs4_read_done_cb(data); | ||
1139 | data->mds_ops->rpc_call_done(&data->task, data); | ||
1140 | data->mds_ops->rpc_release(data); | ||
1141 | return 0; | ||
1142 | } | ||
1143 | |||
1144 | dprintk("%s: pnfs_error=%d, retry via MDS\n", __func__, | ||
1145 | data->pnfs_error); | ||
1146 | status = nfs_initiate_read(data, NFS_CLIENT(data->inode), | ||
1147 | data->mds_ops); | ||
1148 | return status ? : -EAGAIN; | ||
1149 | } | ||
1150 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); | ||
1151 | |||
1152 | /* | ||
969 | * Call the appropriate parallel I/O subsystem read function. | 1153 | * Call the appropriate parallel I/O subsystem read function. |
970 | */ | 1154 | */ |
971 | enum pnfs_try_status | 1155 | enum pnfs_try_status |