diff options
| author | Benny Halevy <bhalevy@panasas.com> | 2011-05-22 12:47:26 -0400 |
|---|---|---|
| committer | Boaz Harrosh <bharrosh@panasas.com> | 2011-05-29 13:52:32 -0400 |
| commit | fb3296eb4636763918edef2d22e45b85b15d4518 (patch) | |
| tree | 31c85255ccfa03cbca2d1e4e52028e489276a73b | |
| parent | f7da7a129d57bfe0f74573dc03531c63e1360fae (diff) | |
pnfs: Use byte-range for layoutget
Add offset and count parameters to pnfs_update_layout and use them to get
the layout in the pageio path.
Order cache layout segments in the following order:
* offset (ascending)
* length (descending)
* iomode (RW before READ)
Test byte range against the layout segment in use in pnfs_{read,write}_pg_test
so not to coalesce pages not using the same layout segment.
[fix lseg ordering]
[clean up pnfs_find_lseg lseg arg]
[remove unnecessary FIXME]
[fix ordering in pnfs_insert_layout]
[clean up pnfs_insert_layout]
Signed-off-by: Benny Halevy <bhalevy@panasas.com>
| -rw-r--r-- | fs/nfs/pnfs.c | 165 | ||||
| -rw-r--r-- | fs/nfs/pnfs.h | 6 | ||||
| -rw-r--r-- | fs/nfs/read.c | 8 | ||||
| -rw-r--r-- | fs/nfs/write.c | 8 |
4 files changed, 142 insertions, 45 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index f57f5281a520..c2f09e9b670e 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -261,6 +261,65 @@ put_lseg(struct pnfs_layout_segment *lseg) | |||
| 261 | } | 261 | } |
| 262 | EXPORT_SYMBOL_GPL(put_lseg); | 262 | EXPORT_SYMBOL_GPL(put_lseg); |
| 263 | 263 | ||
| 264 | static inline u64 | ||
| 265 | end_offset(u64 start, u64 len) | ||
| 266 | { | ||
| 267 | u64 end; | ||
| 268 | |||
| 269 | end = start + len; | ||
| 270 | return end >= start ? end : NFS4_MAX_UINT64; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* last octet in a range */ | ||
| 274 | static inline u64 | ||
| 275 | last_byte_offset(u64 start, u64 len) | ||
| 276 | { | ||
| 277 | u64 end; | ||
| 278 | |||
| 279 | BUG_ON(!len); | ||
| 280 | end = start + len; | ||
| 281 | return end > start ? end - 1 : NFS4_MAX_UINT64; | ||
| 282 | } | ||
| 283 | |||
| 284 | /* | ||
| 285 | * is l2 fully contained in l1? | ||
| 286 | * start1 end1 | ||
| 287 | * [----------------------------------) | ||
| 288 | * start2 end2 | ||
| 289 | * [----------------) | ||
| 290 | */ | ||
| 291 | static inline int | ||
| 292 | lo_seg_contained(struct pnfs_layout_range *l1, | ||
| 293 | struct pnfs_layout_range *l2) | ||
| 294 | { | ||
| 295 | u64 start1 = l1->offset; | ||
| 296 | u64 end1 = end_offset(start1, l1->length); | ||
| 297 | u64 start2 = l2->offset; | ||
| 298 | u64 end2 = end_offset(start2, l2->length); | ||
| 299 | |||
| 300 | return (start1 <= start2) && (end1 >= end2); | ||
| 301 | } | ||
| 302 | |||
| 303 | /* | ||
| 304 | * is l1 and l2 intersecting? | ||
| 305 | * start1 end1 | ||
| 306 | * [----------------------------------) | ||
| 307 | * start2 end2 | ||
| 308 | * [----------------) | ||
| 309 | */ | ||
| 310 | static inline int | ||
| 311 | lo_seg_intersecting(struct pnfs_layout_range *l1, | ||
| 312 | struct pnfs_layout_range *l2) | ||
| 313 | { | ||
| 314 | u64 start1 = l1->offset; | ||
| 315 | u64 end1 = end_offset(start1, l1->length); | ||
| 316 | u64 start2 = l2->offset; | ||
| 317 | u64 end2 = end_offset(start2, l2->length); | ||
| 318 | |||
| 319 | return (end1 == NFS4_MAX_UINT64 || end1 > start2) && | ||
| 320 | (end2 == NFS4_MAX_UINT64 || end2 > start1); | ||
| 321 | } | ||
| 322 | |||
| 264 | static bool | 323 | static bool |
| 265 | should_free_lseg(u32 lseg_iomode, u32 recall_iomode) | 324 | should_free_lseg(u32 lseg_iomode, u32 recall_iomode) |
| 266 | { | 325 | { |
| @@ -467,7 +526,7 @@ pnfs_choose_layoutget_stateid(nfs4_stateid *dst, struct pnfs_layout_hdr *lo, | |||
| 467 | static struct pnfs_layout_segment * | 526 | static struct pnfs_layout_segment * |
| 468 | send_layoutget(struct pnfs_layout_hdr *lo, | 527 | send_layoutget(struct pnfs_layout_hdr *lo, |
| 469 | struct nfs_open_context *ctx, | 528 | struct nfs_open_context *ctx, |
| 470 | u32 iomode, | 529 | struct pnfs_layout_range *range, |
| 471 | gfp_t gfp_flags) | 530 | gfp_t gfp_flags) |
| 472 | { | 531 | { |
| 473 | struct inode *ino = lo->plh_inode; | 532 | struct inode *ino = lo->plh_inode; |
| @@ -499,11 +558,11 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 499 | goto out_err_free; | 558 | goto out_err_free; |
| 500 | } | 559 | } |
| 501 | 560 | ||
| 502 | lgp->args.minlength = NFS4_MAX_UINT64; | 561 | lgp->args.minlength = PAGE_CACHE_SIZE; |
| 562 | if (lgp->args.minlength > range->length) | ||
| 563 | lgp->args.minlength = range->length; | ||
| 503 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; | 564 | lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; |
| 504 | lgp->args.range.iomode = iomode; | 565 | 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; | 566 | lgp->args.type = server->pnfs_curr_ld->id; |
| 508 | lgp->args.inode = ino; | 567 | lgp->args.inode = ino; |
| 509 | lgp->args.ctx = get_nfs_open_context(ctx); | 568 | lgp->args.ctx = get_nfs_open_context(ctx); |
| @@ -518,7 +577,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
| 518 | nfs4_proc_layoutget(lgp); | 577 | nfs4_proc_layoutget(lgp); |
| 519 | if (!lseg) { | 578 | if (!lseg) { |
| 520 | /* remember that LAYOUTGET failed and suspend trying */ | 579 | /* remember that LAYOUTGET failed and suspend trying */ |
| 521 | set_bit(lo_fail_bit(iomode), &lo->plh_flags); | 580 | set_bit(lo_fail_bit(range->iomode), &lo->plh_flags); |
| 522 | } | 581 | } |
| 523 | 582 | ||
| 524 | /* free xdr pages */ | 583 | /* free xdr pages */ |
| @@ -625,10 +684,23 @@ bool pnfs_roc_drain(struct inode *ino, u32 *barrier) | |||
| 625 | * are seen first. | 684 | * are seen first. |
| 626 | */ | 685 | */ |
| 627 | static s64 | 686 | static s64 |
| 628 | cmp_layout(u32 iomode1, u32 iomode2) | 687 | cmp_layout(struct pnfs_layout_range *l1, |
| 688 | struct pnfs_layout_range *l2) | ||
| 629 | { | 689 | { |
| 690 | s64 d; | ||
| 691 | |||
| 692 | /* high offset > low offset */ | ||
| 693 | d = l1->offset - l2->offset; | ||
| 694 | if (d) | ||
| 695 | return d; | ||
| 696 | |||
| 697 | /* short length > long length */ | ||
| 698 | d = l2->length - l1->length; | ||
| 699 | if (d) | ||
| 700 | return d; | ||
| 701 | |||
| 630 | /* read > read/write */ | 702 | /* read > read/write */ |
| 631 | return (int)(iomode2 == IOMODE_READ) - (int)(iomode1 == IOMODE_READ); | 703 | return (int)(l1->iomode == IOMODE_READ) - (int)(l2->iomode == IOMODE_READ); |
| 632 | } | 704 | } |
| 633 | 705 | ||
| 634 | static void | 706 | static void |
| @@ -636,13 +708,12 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, | |||
| 636 | struct pnfs_layout_segment *lseg) | 708 | struct pnfs_layout_segment *lseg) |
| 637 | { | 709 | { |
| 638 | struct pnfs_layout_segment *lp; | 710 | struct pnfs_layout_segment *lp; |
| 639 | int found = 0; | ||
| 640 | 711 | ||
| 641 | dprintk("%s:Begin\n", __func__); | 712 | dprintk("%s:Begin\n", __func__); |
| 642 | 713 | ||
| 643 | assert_spin_locked(&lo->plh_inode->i_lock); | 714 | assert_spin_locked(&lo->plh_inode->i_lock); |
| 644 | list_for_each_entry(lp, &lo->plh_segs, pls_list) { | 715 | list_for_each_entry(lp, &lo->plh_segs, pls_list) { |
| 645 | if (cmp_layout(lp->pls_range.iomode, lseg->pls_range.iomode) > 0) | 716 | if (cmp_layout(&lseg->pls_range, &lp->pls_range) > 0) |
| 646 | continue; | 717 | continue; |
| 647 | list_add_tail(&lseg->pls_list, &lp->pls_list); | 718 | list_add_tail(&lseg->pls_list, &lp->pls_list); |
| 648 | dprintk("%s: inserted lseg %p " | 719 | dprintk("%s: inserted lseg %p " |
| @@ -652,16 +723,14 @@ pnfs_insert_layout(struct pnfs_layout_hdr *lo, | |||
| 652 | lseg->pls_range.offset, lseg->pls_range.length, | 723 | lseg->pls_range.offset, lseg->pls_range.length, |
| 653 | lp, lp->pls_range.iomode, lp->pls_range.offset, | 724 | lp, lp->pls_range.iomode, lp->pls_range.offset, |
| 654 | lp->pls_range.length); | 725 | lp->pls_range.length); |
| 655 | found = 1; | 726 | 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 | } | 727 | } |
| 728 | list_add_tail(&lseg->pls_list, &lo->plh_segs); | ||
| 729 | dprintk("%s: inserted lseg %p " | ||
| 730 | "iomode %d offset %llu length %llu at tail\n", | ||
| 731 | __func__, lseg, lseg->pls_range.iomode, | ||
| 732 | lseg->pls_range.offset, lseg->pls_range.length); | ||
| 733 | out: | ||
| 665 | get_layout_hdr(lo); | 734 | get_layout_hdr(lo); |
| 666 | 735 | ||
| 667 | dprintk("%s:Return\n", __func__); | 736 | dprintk("%s:Return\n", __func__); |
| @@ -721,16 +790,28 @@ pnfs_find_alloc_layout(struct inode *ino, gfp_t gfp_flags) | |||
| 721 | * READ RW true | 790 | * READ RW true |
| 722 | */ | 791 | */ |
| 723 | static int | 792 | static int |
| 724 | is_matching_lseg(struct pnfs_layout_segment *lseg, u32 iomode) | 793 | is_matching_lseg(struct pnfs_layout_range *ls_range, |
| 794 | struct pnfs_layout_range *range) | ||
| 725 | { | 795 | { |
| 726 | return (iomode != IOMODE_RW || lseg->pls_range.iomode == IOMODE_RW); | 796 | struct pnfs_layout_range range1; |
| 797 | |||
| 798 | if ((range->iomode == IOMODE_RW && | ||
| 799 | ls_range->iomode != IOMODE_RW) || | ||
