pNFS: Return RW layouts on OPEN_DOWNGRADE
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 21 Nov 2016 15:56:38 +0000 (10:56 -0500)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 19 Dec 2016 22:29:55 +0000 (17:29 -0500)
If the client holds no more writeable open state, and does not hold a
write delegation, then send a layoutreturn as part of the OPEN_DOWNGRADE.

We do this only for writes, since some layout drivers may require you to
also hold a read layout if you are doing a R/W workload.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/pnfs.c

index 896df7b..59554f3 100644 (file)
@@ -1251,6 +1251,7 @@ bool pnfs_roc(struct inode *ino,
        nfs4_stateid stateid;
        enum pnfs_iomode iomode = 0;
        bool layoutreturn = false, roc = false;
+       bool skip_read = false;
 
        if (!nfs_have_layout(ino))
                return false;
@@ -1270,18 +1271,27 @@ retry:
        }
 
        /* no roc if we hold a delegation */
-       if (nfs4_check_delegation(ino, FMODE_READ))
-               goto out_noroc;
+       if (nfs4_check_delegation(ino, FMODE_READ)) {
+               if (nfs4_check_delegation(ino, FMODE_WRITE))
+                       goto out_noroc;
+               skip_read = true;
+       }
 
        list_for_each_entry(ctx, &nfsi->open_files, list) {
                state = ctx->state;
+               if (state == NULL)
+                       continue;
                /* Don't return layout if there is open file state */
-               if (state != NULL && state->state != 0)
+               if (state->state & FMODE_WRITE)
                        goto out_noroc;
+               if (state->state & FMODE_READ)
+                       skip_read = true;
        }
 
 
        list_for_each_entry_safe(lseg, next, &lo->plh_segs, pls_list) {
+               if (skip_read && lseg->pls_range.iomode == IOMODE_READ)
+                       continue;
                /* If we are sending layoutreturn, invalidate all valid lsegs */
                if (!test_and_clear_bit(NFS_LSEG_ROC, &lseg->pls_flags))
                        continue;