3.6.11.2 stable review patch.
If anyone has any objections, please let me know.

------------------

From: Trond Myklebust <trond.mykleb...@netapp.com>

[ Upstream commit 24956804349ca0eadcdde032d65e8c00b4214096 ]

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.mykleb...@netapp.com>
Acked-by: Benny Halevy <bhal...@tonian.com>
Cc: sta...@vger.kernel.org
Signed-off-by: Steven Rostedt <rost...@goodmis.org>
---
 fs/nfs/pnfs.c |   35 +++++++++++++++++++++++++++--------
 1 file changed, 27 insertions(+), 8 deletions(-)

diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index c5fe1a5..49dffeb5 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -364,6 +364,16 @@ should_free_lseg(struct pnfs_layout_range *lseg_range,
               lo_seg_intersecting(lseg_range, recall_range);
 }
 
+static bool pnfs_lseg_dec_and_remove_zero(struct pnfs_layout_segment *lseg,
+               struct list_head *tmp_list)
+{
+       if (!atomic_dec_and_test(&lseg->pls_refcount))
+               return false;
+       put_lseg_common(lseg);
+       list_add(&lseg->pls_list, tmp_list);
+       return true;
+}
+
 /* Returns 1 if lseg is removed from list, 0 otherwise */
 static int mark_lseg_invalid(struct pnfs_layout_segment *lseg,
                             struct list_head *tmp_list)
@@ -377,11 +387,8 @@ static int mark_lseg_invalid(struct pnfs_layout_segment 
*lseg,
                 */
                dprintk("%s: lseg %p ref %d\n", __func__, lseg,
                        atomic_read(&lseg->pls_refcount));
-               if (atomic_dec_and_test(&lseg->pls_refcount)) {
-                       put_lseg_common(lseg);
-                       list_add(&lseg->pls_list, tmp_list);
+               if (pnfs_lseg_dec_and_remove_zero(lseg, tmp_list))
                        rv = 1;
-               }
        }
        return rv;
 }
@@ -614,6 +621,21 @@ send_layoutget(struct pnfs_layout_hdr *lo,
        return lseg;
 }
 
+static void pnfs_clear_layoutcommit(struct inode *inode,
+               struct list_head *head)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+       struct pnfs_layout_segment *lseg, *tmp;
+
+       if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
+               return;
+       list_for_each_entry_safe(lseg, tmp, &nfsi->layout->plh_segs, pls_list) {
+               if (!test_and_clear_bit(NFS_LSEG_LAYOUTCOMMIT, 
&lseg->pls_flags))
+                       continue;
+               pnfs_lseg_dec_and_remove_zero(lseg, head);
+       }
+}
+
 /*
  * Initiates a LAYOUTRETURN(FILE), and removes the pnfs_layout_hdr
  * when the layout segment list is empty.
@@ -645,6 +667,7 @@ _pnfs_return_layout(struct inode *ino)
        /* Reference matched in nfs4_layoutreturn_release */
        get_layout_hdr(lo);
        empty = list_empty(&lo->plh_segs);
+       pnfs_clear_layoutcommit(ino, &tmp_list);
        mark_matching_lsegs_invalid(lo, &tmp_list, NULL);
        /* Don't send a LAYOUTRETURN if list was initially empty */
        if (empty) {
@@ -658,8 +681,6 @@ _pnfs_return_layout(struct inode *ino)
        spin_unlock(&ino->i_lock);
        pnfs_free_lseg_list(&tmp_list);
 
-       WARN_ON(test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags));
-
        lrp = kzalloc(sizeof(*lrp), GFP_KERNEL);
        if (unlikely(lrp == NULL)) {
                status = -ENOMEM;
@@ -1283,7 +1304,6 @@ static void pnfs_ld_handle_write_error(struct 
nfs_write_data *data)
        dprintk("pnfs write error = %d\n", hdr->pnfs_error);
        if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
            PNFS_LAYOUTRET_ON_ERROR) {
-               clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
                pnfs_return_layout(hdr->inode);
        }
        if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
@@ -1435,7 +1455,6 @@ static void pnfs_ld_handle_read_error(struct 
nfs_read_data *data)
        dprintk("pnfs read error = %d\n", hdr->pnfs_error);
        if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags &
            PNFS_LAYOUTRET_ON_ERROR) {
-               clear_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(hdr->inode)->flags);
                pnfs_return_layout(hdr->inode);
        }
        if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags))
-- 
1.7.10.4


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to