aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-20 20:15:57 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-28 16:03:11 -0400
commit7fdab069b7172f2348cf3d87e19c6c24340292bf (patch)
tree487de5c39bb8be13be52091acc83139435943000 /fs/nfs
parent115ce575cb10918514d053ef15f597a4e6ff60e9 (diff)
NFSv4.1: Fix a race in the pNFS return-on-close code
If we sleep after dropping the inode->i_lock, then we are no longer atomic with respect to the rpc_wake_up() call in pnfs_layout_remove_lseg(). Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs')
-rw-r--r--fs/nfs/nfs4proc.c8
-rw-r--r--fs/nfs/pnfs.c22
-rw-r--r--fs/nfs/pnfs.h4
3 files changed, 17 insertions, 17 deletions
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index e605d417a006..6d5750cabd8d 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -2137,6 +2137,7 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2137{ 2137{
2138 struct nfs4_closedata *calldata = data; 2138 struct nfs4_closedata *calldata = data;
2139 struct nfs4_state *state = calldata->state; 2139 struct nfs4_state *state = calldata->state;
2140 struct inode *inode = calldata->inode;
2140 int call_close = 0; 2141 int call_close = 0;
2141 2142
2142 dprintk("%s: begin!\n", __func__); 2143 dprintk("%s: begin!\n", __func__);
@@ -2170,16 +2171,13 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
2170 if (calldata->arg.fmode == 0) { 2171 if (calldata->arg.fmode == 0) {
2171 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE]; 2172 task->tk_msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE];
2172 if (calldata->roc && 2173 if (calldata->roc &&
2173 pnfs_roc_drain(calldata->inode, &calldata->roc_barrier)) { 2174 pnfs_roc_drain(inode, &calldata->roc_barrier, task))
2174 rpc_sleep_on(&NFS_SERVER(calldata->inode)->roc_rpcwaitq,
2175 task, NULL);
2176 goto out; 2175 goto out;
2177 }
2178 } 2176 }
2179 2177
2180 nfs_fattr_init(calldata->res.fattr); 2178 nfs_fattr_init(calldata->res.fattr);
2181 calldata->timestamp = jiffies; 2179 calldata->timestamp = jiffies;
2182 if (nfs4_setup_sequence(NFS_SERVER(calldata->inode), 2180 if (nfs4_setup_sequence(NFS_SERVER(inode),
2183 &calldata->arg.seq_args, 2181 &calldata->arg.seq_args,
2184 &calldata->res.seq_res, 2182 &calldata->res.seq_res,
2185 task)) 2183 task))
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 9ee3bd705b94..8b32f8745337 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -807,27 +807,29 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
807 spin_unlock(&ino->i_lock); 807 spin_unlock(&ino->i_lock);
808} 808}
809 809
810bool pnfs_roc_drain(struct inode *ino, u32 *barrier) 810bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
811{ 811{
812 struct nfs_inode *nfsi = NFS_I(ino); 812 struct nfs_inode *nfsi = NFS_I(ino);
813 struct pnfs_layout_hdr *lo;
813 struct pnfs_layout_segment *lseg; 814 struct pnfs_layout_segment *lseg;
815 u32 current_seqid;
814 bool found = false; 816 bool found = false;
815 817
816 spin_lock(&ino->i_lock); 818 spin_lock(&ino->i_lock);
817 list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list) 819 list_for_each_entry(lseg, &nfsi->layout->plh_segs, pls_list)
818 if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) { 820 if (test_bit(NFS_LSEG_ROC, &lseg->pls_flags)) {
821 rpc_sleep_on(&NFS_SERVER(ino)->roc_rpcwaitq, task, NULL);
819 found = true; 822 found = true;
820 break; 823 goto out;
821 } 824 }
822 if (!found) { 825 lo = nfsi->layout;
823 struct pnfs_layout_hdr *lo = nfsi->layout; 826 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
824 u32 current_seqid = be32_to_cpu(lo->plh_stateid.seqid);
825 827
826 /* Since close does not return a layout stateid for use as 828 /* Since close does not return a layout stateid for use as
827 * a barrier, we choose the worst-case barrier. 829 * a barrier, we choose the worst-case barrier.
828 */ 830 */
829 *barrier = current_seqid + atomic_read(&lo->plh_outstanding); 831 *barrier = current_seqid + atomic_read(&lo->plh_outstanding);
830 } 832out:
831 spin_unlock(&ino->i_lock); 833 spin_unlock(&ino->i_lock);
832 return found; 834 return found;
833} 835}
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h
index 9735031e1e1a..aa9fa1b1ff4a 100644
--- a/fs/nfs/pnfs.h
+++ b/fs/nfs/pnfs.h
@@ -210,7 +210,7 @@ int pnfs_mark_matching_lsegs_invalid(struct pnfs_layout_hdr *lo,
210bool pnfs_roc(struct inode *ino); 210bool pnfs_roc(struct inode *ino);
211void pnfs_roc_release(struct inode *ino); 211void pnfs_roc_release(struct inode *ino);
212void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); 212void pnfs_roc_set_barrier(struct inode *ino, u32 barrier);
213bool pnfs_roc_drain(struct inode *ino, u32 *barrier); 213bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task);
214void pnfs_set_layoutcommit(struct nfs_write_data *wdata); 214void pnfs_set_layoutcommit(struct nfs_write_data *wdata);
215void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); 215void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data);
216int pnfs_layoutcommit_inode(struct inode *inode, bool sync); 216int pnfs_layoutcommit_inode(struct inode *inode, bool sync);
@@ -442,7 +442,7 @@ pnfs_roc_set_barrier(struct inode *ino, u32 barrier)
442} 442}
443 443
444static inline bool 444static inline bool
445pnfs_roc_drain(struct inode *ino, u32 *barrier) 445pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task)
446{ 446{
447 return false; 447 return false;
448} 448}