diff options
author | Andy Adamson <andros@netapp.com> | 2012-06-20 15:03:34 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-07-16 14:39:00 -0400 |
commit | 293b3b065c5ec5d15c3087ca42a52c991d7d8235 (patch) | |
tree | 32b9422aa2d097af2618d225b925535b75492ee0 /fs/nfs/pnfs.c | |
parent | 366d50521c57939e61e25dc27f009367447563e6 (diff) |
NFSv4.1 do not send LAYOUTRETURN on emtpy plh_segs list
mark_matching_lsegs_invalid() resets the mds_threshold counters and can
dereference the layout hdr on an initial empty plh_segs list. It returns 0 both
in the case of an initial empty list and in a non-emtpy list that was cleared
by calls to mark_lseg_invalid.
Don't send a LAYOUTRETURN if the list was initially empty.
Signed-off-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3ad768f2cef4..7fbd25afe418 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
@@ -651,7 +651,14 @@ out_err_free: | |||
651 | return NULL; | 651 | return NULL; |
652 | } | 652 | } |
653 | 653 | ||
654 | /* Initiates a LAYOUTRETURN(FILE) */ | 654 | /* |
655 | * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr | ||
656 | * when the layout segment list is empty. | ||
657 | * | ||
658 | * Note that a pnfs_layout_hdr can exist with an empty layout segment | ||
659 | * list when LAYOUTGET has failed, or when LAYOUTGET succeeded, but the | ||
660 | * deviceid is marked invalid. | ||
661 | */ | ||
655 | int | 662 | int |
656 | _pnfs_return_layout(struct inode *ino) | 663 | _pnfs_return_layout(struct inode *ino) |
657 | { | 664 | { |
@@ -660,7 +667,7 @@ _pnfs_return_layout(struct inode *ino) | |||
660 | LIST_HEAD(tmp_list); | 667 | LIST_HEAD(tmp_list); |
661 | struct nfs4_layoutreturn *lrp; | 668 | struct nfs4_layoutreturn *lrp; |
662 | nfs4_stateid stateid; | 669 | nfs4_stateid stateid; |
663 | int status = 0; | 670 | int status = 0, empty; |
664 | 671 | ||
665 | dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino); | 672 | dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino); |
666 | 673 | ||
@@ -668,13 +675,21 @@ _pnfs_return_layout(struct inode *ino) | |||
668 | lo = nfsi->layout; | 675 | lo = nfsi->layout; |
669 | if (!lo || pnfs_test_layout_returned(lo)) { | 676 | if (!lo || pnfs_test_layout_returned(lo)) { |
670 | spin_unlock(&ino->i_lock); | 677 | spin_unlock(&ino->i_lock); |
671 | dprintk("%s: no layout to return\n", __func__); | 678 | dprintk("NFS: %s no layout to return\n", __func__); |
672 | return status; | 679 | goto out; |
673 | } | 680 | } |
674 | stateid = nfsi->layout->plh_stateid; | 681 | stateid = nfsi->layout->plh_stateid; |
675 | /* Reference matched in nfs4_layoutreturn_release */ | 682 | /* Reference matched in nfs4_layoutreturn_release */ |
676 | get_layout_hdr(lo); | 683 | get_layout_hdr(lo); |
684 | empty = list_empty(&lo->plh_segs); | ||
677 | mark_matching_lsegs_invalid(lo, &tmp_list, NULL); | 685 | mark_matching_lsegs_invalid(lo, &tmp_list, NULL); |
686 | /* Don't send a LAYOUTRETURN if list was initially empty */ | ||
687 | if (empty) { | ||
688 | spin_unlock(&ino->i_lock); | ||
689 | put_layout_hdr(lo); | ||
690 | dprintk("NFS: %s no layout segments to return\n", __func__); | ||
691 | goto out; | ||
692 | } | ||
678 | lo->plh_block_lgets++; | 693 | lo->plh_block_lgets++; |
679 | pnfs_mark_layout_returned(lo); | 694 | pnfs_mark_layout_returned(lo); |
680 | spin_unlock(&ino->i_lock); | 695 | spin_unlock(&ino->i_lock); |