diff options
author | Peng Tao <tao.peng@primarydata.com> | 2015-08-19 07:49:19 +0200 |
---|---|---|
committer | Trond Myklebust <trond.myklebust@primarydata.com> | 2015-08-19 17:29:25 +0200 |
commit | e755d638e91be254d441602e8d7d9f1d9c944556 (patch) | |
tree | 33f151fed95bc23bdd1c906c3c918c75e33642b6 /fs | |
parent | Revert "NFSv4: Remove incorrect check in can_open_delegated()" (diff) | |
download | linux-e755d638e91be254d441602e8d7d9f1d9c944556.tar.xz linux-e755d638e91be254d441602e8d7d9f1d9c944556.zip |
NFS41: make sure sending LAYOUTRETURN before close if marked so
If layout is marked by NFS_LAYOUT_RETURN_BEFORE_CLOSE, we should always
send LAYOUTRETURN before close, and we don't need to do ROC drain if we
do send LAYOUTRETURN.
Signed-off-by: Peng Tao <tao.peng@primarydata.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfs/pnfs.c | 51 |
1 files changed, 28 insertions, 23 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 6aabbb654021..e101a491e4e7 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1064,7 +1064,7 @@ bool pnfs_roc(struct inode *ino) struct pnfs_layout_segment *lseg, *tmp; nfs4_stateid stateid; LIST_HEAD(tmp_list); - bool found = false, layoutreturn = false; + bool found = false, layoutreturn = false, roc = false; spin_lock(&ino->i_lock); lo = nfsi->layout; @@ -1072,7 +1072,7 @@ bool pnfs_roc(struct inode *ino) test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) goto out_noroc; - /* Don't return layout if we hold a delegation */ + /* no roc if we hold a delegation */ if (nfs4_check_delegation(ino, FMODE_READ)) goto out_noroc; @@ -1083,36 +1083,41 @@ bool pnfs_roc(struct inode *ino) goto out_noroc; } + stateid = lo->plh_stateid; + /* always send layoutreturn if being marked so */ + if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, + &lo->plh_flags)) + layoutreturn = pnfs_prepare_layoutreturn(lo); + pnfs_clear_retry_layoutget(lo); list_for_each_entry_safe(lseg, tmp, &lo->plh_segs, pls_list) - if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) { + /* If we are sending layoutreturn, invalidate all valid lsegs */ + if (layoutreturn || test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) { mark_lseg_invalid(lseg, &tmp_list); found = true; } - if (!found) - goto out_noroc; - if (test_and_set_bit(NFS_LAYOUT_RETURN, &lo->plh_flags)) - goto out_noroc; - lo->plh_return_iomode = IOMODE_ANY; - pnfs_get_layout_hdr(lo); /* matched in pnfs_roc_release */ - spin_unlock(&ino->i_lock); - pnfs_free_lseg_list(&tmp_list); - pnfs_layoutcommit_inode(ino, true); - return true; + /* pnfs_prepare_layoutreturn() grabs lo ref and it will be put + * in pnfs_roc_release(). We don't really send a layoutreturn but + * still want others to view us like we are sending one! + * + * If pnfs_prepare_layoutreturn() fails, it means someone else is doing + * LAYOUTRETURN, so we proceed like there are no layouts to return. + * + * ROC in three conditions: + * 1. there are ROC lsegs + * 2. we don't send layoutreturn + * 3. no others are sending layoutreturn + */ + if (found && !layoutreturn && pnfs_prepare_layoutreturn(lo)) + roc = true; out_noroc: - if (lo) { - stateid = lo->plh_stateid; - if (test_and_clear_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, - &lo->plh_flags)) - layoutreturn = pnfs_prepare_layoutreturn(lo); - } spin_unlock(&ino->i_lock); - if (layoutreturn) { - pnfs_layoutcommit_inode(ino, true); + pnfs_free_lseg_list(&tmp_list); + pnfs_layoutcommit_inode(ino, true); + if (layoutreturn) pnfs_send_layoutreturn(lo, stateid, IOMODE_ANY, true); - } - return false; + return roc; } void pnfs_roc_release(struct inode *ino) |