diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-03-20 13:03:00 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2013-03-21 10:31:21 -0400 |
commit | 24956804349ca0eadcdde032d65e8c00b4214096 (patch) | |
tree | 8f065155073b0563dd6a27de8a73c8d1470c49a6 /fs | |
parent | a073dbff359f4741013ae4b8395f5364c5e00b48 (diff) |
NFSv4.1: Always clear the NFS_INO_LAYOUTCOMMIT in layoutreturn
Note that clearing NFS_INO_LAYOUTCOMMIT is tricky, since it requires
you to also clear the NFS_LSEG_LAYOUTCOMMIT bits from the layout
segments.
The only two sites that need to do this are the ones that call
pnfs_return_layout() without first doing a layout commit.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Acked-by: Benny Halevy <bhalevy@tonian.com>
Cc: stable@vger.kernel.org
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/nfs4filelayout.c | 1 | ||||
-rw-r--r-- | fs/nfs/pnfs.c | 35 |
2 files changed, 27 insertions, 9 deletions
diff --git a/fs/nfs/nfs4filelayout.c b/fs/nfs/nfs4filelayout.c index 49eeb044c109..4fb234d3aefb 100644 --- a/fs/nfs/nfs4filelayout.c +++ b/fs/nfs/nfs4filelayout.c | |||
@@ -129,7 +129,6 @@ static void filelayout_fenceme(struct inode *inode, struct pnfs_layout_hdr *lo) | |||
129 | { | 129 | { |
130 | if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) | 130 | if (!test_and_clear_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) |
131 | return; | 131 | return; |
132 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags); | ||
133 | pnfs_return_layout(inode); | 132 | pnfs_return_layout(inode); |
134 | } | 133 | } |
135 | 134 | ||
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3d900916fd41..5044142c1216 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -417,6 +417,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range, | |||
417 | lo_seg_intersecting(lseg_range, recall_range); | 417 | lo_seg_intersecting(lseg_range, recall_range); |
418 | } | 418 | } |
419 | 419 | ||
420 | static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg, | ||
421 | struct list_head *tmp_list) | ||
422 | { | ||
423 | if (!atomic_dec_and_test(&lseg->pls_refcount)) | ||
424 | return false; | ||
425 | pnfs_layout_remove_lseg(lseg->pls_layout, lseg); | ||
426 | list_add(&lseg->pls_list, tmp_list); | ||
427 | return true; | ||
428 | } | ||
429 | |||
420 | /* Returns 1 if lseg is removed from list, 0 otherwise */ | 430 | /* Returns 1 if lseg is removed from list, 0 otherwise */ |
421 | static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | 431 | static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, |
422 | struct list_head *tmp_list) | 432 | struct list_head *tmp_list) |
@@ -430,11 +440,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment *lseg, | |||
430 | */ | 440 | */ |
431 | dprintk("%s: lseg %p ref %d\n", __func__, lseg, | 441 | dprintk("%s: lseg %p ref %d\n", __func__, lseg, |
432 | atomic_read(&lseg->pls_refcount)); | 442 | atomic_read(&lseg->pls_refcount)); |
433 | if (atomic_dec_and_test(&lseg->pls_refcount)) { | 443 | if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list)) |
434 | pnfs_layout_remove_lseg(lseg->pls_layout, lseg); | ||
435 | list_add(&lseg->pls_list, tmp_list); | ||
436 | rv = 1; | 444 | rv = 1; |
437 | } | ||
438 | } | 445 | } |
439 | return rv; | 446 | return rv; |
440 | } | 447 | } |
@@ -777,6 +784,21 @@ send_layoutget(struct pnfs_layout_hdr *lo, | |||
777 | return lseg; | 784 | return lseg; |
778 | } | 785 | } |
779 | 786 | ||
787 | static void pnfs_clear_layoutcommit(struct inode *inode, | ||
788 | struct list_head *head) | ||
789 | { | ||
790 | struct nfs_inode *nfsi = NFS_I(inode); | ||
791 | struct pnfs_layout_segment *lseg, *tmp; | ||
792 | |||
793 | if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) | ||
794 | return; | ||
795 | list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) { | ||
796 | if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, &lseg->pls_flags)) | ||
797 | continue; | ||
798 | pnfs_lseg_dec_and_remove_zero(lseg, head); | ||
799 | } | ||
800 | } | ||
801 | |||
780 | /* | 802 | /* |
781 | * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr | 803 | * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr |
782 | * when the layout segment list is empty. | 804 | * when the layout segment list is empty. |
@@ -808,6 +830,7 @@ _pnfs_return_layout(struct inode *ino) | |||
808 | /* Reference matched in nfs4_layoutreturn_release */ | 830 | /* Reference matched in nfs4_layoutreturn_release */ |
809 | pnfs_get_layout_hdr(lo); | 831 | pnfs_get_layout_hdr(lo); |
810 | empty = list_empty(&lo->plh_segs); | 832 | empty = list_empty(&lo->plh_segs); |
833 | pnfs_clear_layoutcommit(ino, &tmp_list); | ||
811 | pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); | 834 | pnfs_mark_matching_lsegs_invalid(lo, &tmp_list, NULL); |
812 | /* Don't send a LAYOUTRETURN if list was initially empty */ | 835 | /* Don't send a LAYOUTRETURN if list was initially empty */ |
813 | if (empty) { | 836 | if (empty) { |
@@ -820,8 +843,6 @@ _pnfs_return_layout(struct inode *ino) | |||
820 | spin_unlock(&ino->i_lock); | 843 | spin_unlock(&ino->i_lock); |
821 | pnfs_free_lseg_list(&tmp_list); | 844 | pnfs_free_lseg_list(&tmp_list); |
822 | 845 | ||
823 | WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)); | ||
824 | |||
825 | lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); | 846 | lrp = kzalloc(sizeof(*lrp), GFP_KERNEL); |
826 | if (unlikely(lrp == NULL)) { | 847 | if (unlikely(lrp == NULL)) { |
827 | status = -ENOMEM; | 848 | status = -ENOMEM; |
@@ -1458,7 +1479,6 @@ static void pnfs_ld_handle_write_error(struct nfs_write_data *data) | |||
1458 | dprintk("pnfs write error = %d\n", hdr->pnfs_error); | 1479 | dprintk("pnfs write error = %d\n", hdr->pnfs_error); |
1459 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & | 1480 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & |
1460 | PNFS_LAYOUTRET_ON_ERROR) { | 1481 | PNFS_LAYOUTRET_ON_ERROR) { |
1461 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); | ||
1462 | pnfs_return_layout(hdr->inode); | 1482 | pnfs_return_layout(hdr->inode); |
1463 | } | 1483 | } |
1464 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) | 1484 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
@@ -1613,7 +1633,6 @@ static void pnfs_ld_handle_read_error(struct nfs_read_data *data) | |||
1613 | dprintk("pnfs read error = %d\n", hdr->pnfs_error); | 1633 | dprintk("pnfs read error = %d\n", hdr->pnfs_error); |
1614 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & | 1634 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & |
1615 | PNFS_LAYOUTRET_ON_ERROR) { | 1635 | PNFS_LAYOUTRET_ON_ERROR) { |
1616 | clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags); | ||
1617 | pnfs_return_layout(hdr->inode); | 1636 | pnfs_return_layout(hdr->inode); |
1618 | } | 1637 | } |
1619 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) | 1638 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |