aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeng Tao <tao.peng@primarydata.com>2015-09-21 23:35:22 -0400
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-09-23 08:55:32 -0400
commit500d701f336b2771d34e46da7875a4782515a652 (patch)
tree217881fc9e1b5cc45f1f2b4042c6a161f84aebd0
parent834e465bba38f2768747bccb5f00e951e72d2bf5 (diff)
NFS41: make close wait for layoutreturn
If we send a layoutreturn asynchronously before close, the close might reach server first and layoutreturn would fail with BADSTATEID because there is nothing keeping the layout stateid alive. Also do not pretend sending layoutreturn if we are not. Signed-off-by: Peng Tao <tao.peng@primarydata.com> Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
-rw-r--r--fs/nfs/nfs4proc.c17
-rw-r--r--fs/nfs/pnfs.c35
-rw-r--r--fs/nfs/pnfs.h7
3 files changed, 49 insertions, 10 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index ef6b46e08ac6..f93b9cdb4934 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2658,6 +2658,15 @@ out:
2658 return err; 2658 return err;
2659} 2659}
2660 2660
2661static bool
2662nfs4_wait_on_layoutreturn(struct inode *inode, struct rpc_task *task)
2663{
2664 if (inode == NULL || !nfs_have_layout(inode))
2665 return false;
2666
2667 return pnfs_wait_on_layoutreturn(inode, task);
2668}
2669
2661struct nfs4_closedata { 2670struct nfs4_closedata {
2662 struct inode *inode; 2671 struct inode *inode;
2663 struct nfs4_state *state; 2672 struct nfs4_state *state;
@@ -2776,6 +2785,11 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2776 goto out_no_action; 2785 goto out_no_action;
2777 } 2786 }
2778 2787
2788 if (nfs4_wait_on_layoutreturn(inode, task)) {
2789 nfs_release_seqid(calldata->arg.seqid);
2790 goto out_wait;
2791 }
2792
2779 if (calldata->arg.fmode == 0) 2793 if (calldata->arg.fmode == 0)
2780 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; 2794 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
2781 if (calldata->roc) 2795 if (calldata->roc)
@@ -5321,6 +5335,9 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data)
5321 5335
5322 d_data = (struct nfs4_delegreturndata *)data; 5336 d_data = (struct nfs4_delegreturndata *)data;
5323 5337
5338 if (nfs4_wait_on_layoutreturn(d_data->inode, task))
5339 return;
5340
5324 if (d_data->roc) 5341 if (d_data->roc)
5325 pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier); 5342 pnfs_roc_get_barrier(d_data->inode, &d_data->roc_barrier);
5326 5343
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index ba1246433794..8abe27165ad0 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -1104,20 +1104,15 @@ bool pnfs_roc(struct inode *ino)
1104 mark_lseg_invalid(lseg, &tmp_list); 1104 mark_lseg_invalid(lseg, &tmp_list);
1105 found = true; 1105 found = true;
1106 } 1106 }
1107 /* pnfs_prepare_layoutreturn() grabs lo ref and it will be put 1107 /* ROC in two conditions:
1108 * in pnfs_roc_release(). We don't really send a layoutreturn but
1109 * still want others to view us like we are sending one!
1110 *
1111 * If pnfs_prepare_layoutreturn() fails, it means someone else is doing
1112 * LAYOUTRETURN, so we proceed like there are no layouts to return.
1113 *
1114 * ROC in three conditions:
1115 * 1. there are ROC lsegs 1108 * 1. there are ROC lsegs
1116 * 2. we don't send layoutreturn 1109 * 2. we don't send layoutreturn
1117 * 3. no others are sending layoutreturn
1118 */ 1110 */
1119 if (found && !layoutreturn && pnfs_prepare_layoutreturn(lo)) 1111 if (found && !layoutreturn) {
1112 /* lo ref dropped in pnfs_roc_release() */
1113 pnfs_get_layout_hdr(lo);
1120 roc = true; 1114 roc = true;
1115 }
1121 1116
1122out_noroc: 1117out_noroc:
1123 spin_unlock(&ino->i_lock); 1118 spin_unlock(&ino->i_lock);
@@ -1172,6 +1167,26 @@ void pnfs_roc_get_barrier(struct inode *ino, u32 *barrier)
1172 spin_unlock(&ino->i_lock); 1167 spin_unlock(&ino->i_lock);
1173} 1168}
1174 1169
1170bool pnfs_wait_on_layoutreturn(struct inode *ino, struct rpc_task *task)
1171{
1172 struct nfs_inode *nfsi = NFS_I(ino);
1173 struct pnfs_layout_hdr *lo;
1174 bool sleep = false;
1175
1176 /* we might not have grabbed lo reference. so need to check under
1177 * i_lock */
1178 spin_lock(&ino->i_lock);
1179 lo = nfsi->layout;
1180 if (lo && test_bit(NFS_LAYOUT_RETURN, &lo->plh_flags))
1181 sleep = true;
1182 spin_unlock(&ino->i_lock);
1183
1184 if (sleep)
1185 rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
1186
1187 return sleep;
1188}
1189
1175/* 1190/*
1176 * Compare two layout segments for sorting into layout cache. 1191 * Compare two layout segments for sorting into layout cache.
1177 * We want to preferentially return RW over RO layouts, so ensure those 1192 * We want to preferentially return RW over RO layouts, so ensure those
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 78c9351ff117..d1990e90e7a0 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -270,6 +270,7 @@ bool pnfs_roc(struct inode *ino);
270void pnfs_roc_release(struct inode *ino); 270void pnfs_roc_release(struct inode *ino);
271void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); 271void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
272void pnfs_roc_get_barrier(struct inode *ino, u32 *barrier); 272void pnfs_roc_get_barrier(struct inode *ino, u32 *barrier);
273bool pnfs_wait_on_layoutreturn(struct inode *ino, struct rpc_task *task);
273void pnfs_set_layoutcommit(struct inode *, struct pnfs_layout_segment *, loff_t); 274void pnfs_set_layoutcommit(struct inode *, struct pnfs_layout_segment *, loff_t);
274void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); 275void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
275int pnfs_layoutcommit_inode(struct inode *inode, bool sync); 276int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
@@ -639,6 +640,12 @@ pnfs_roc_get_barrier(struct inode *ino, u32 *barrier)
639{ 640{
640} 641}
641 642
643static inline bool
644pnfs_wait_on_layoutreturn(struct inode *ino, struct rpc_task *task)
645{
646 return false;
647}
648
642static inline void set_pnfs_layoutdriver(struct nfs_server *s, 649static inline void set_pnfs_layoutdriver(struct nfs_server *s,
643 const struct nfs_fh *mntfh, u32 id) 650 const struct nfs_fh *mntfh, u32 id)
644{ 651{