NFSv4.1 do not send LAYOUTRETURN on emtpy plh_segs list
authorAndy Adamson <andros@netapp.com>
Wed, 20 Jun 2012 19:03:34 +0000 (15:03 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 16 Jul 2012 18:39:00 +0000 (14:39 -0400)
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>
fs/nfs/pnfs.c

index 3ad768f2cef4064d6728b72fdf0c4aef09164bb0..7fbd25afe418af4b749a78febb78b125cdf1fe07 100644 (file)
@@ -651,7 +651,14 @@ out_err_free:
        return NULL;
 }
 
-/* Initiates a LAYOUTRETURN(FILE) */
+/*
+ * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
+ * when the layout segment list is empty.
+ *
+ * Note that a pnfs_layout_hdr can exist with an empty layout segment
+ * list when LAYOUTGET has failed, or when LAYOUTGET succeeded, but the
+ * deviceid is marked invalid.
+ */
 int
 _pnfs_return_layout(struct inode *ino)
 {
@@ -660,7 +667,7 @@ _pnfs_return_layout(struct inode *ino)
        LIST_HEAD(tmp_list);
        struct nfs4_layoutreturn *lrp;
        nfs4_stateid stateid;
-       int status = 0;
+       int status = 0, empty;
 
        dprintk("NFS: %s for inode %lu\n", __func__, ino->i_ino);
 
@@ -668,13 +675,21 @@ _pnfs_return_layout(struct inode *ino)
        lo = nfsi->layout;
        if (!lo || pnfs_test_layout_returned(lo)) {
                spin_unlock(&ino->i_lock);
-               dprintk("%s: no layout to return\n", __func__);
-               return status;
+               dprintk("NFS: %s no layout to return\n", __func__);
+               goto out;
        }
        stateid = nfsi->layout->plh_stateid;
        /* Reference matched in nfs4_layoutreturn_release */
        get_layout_hdr(lo);
+       empty = list_empty(&lo->plh_segs);
        mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
+       /* Don't send a LAYOUTRETURN if list was initially empty */
+       if (empty) {
+               spin_unlock(&ino->i_lock);
+               put_layout_hdr(lo);
+               dprintk("NFS: %s no layout segments to return\n", __func__);
+               goto out;
+       }
        lo->plh_block_lgets++;
        pnfs_mark_layout_returned(lo);
        spin_unlock(&ino->i_lock);