aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-02-07 10:54:07 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-02-11 15:33:13 -0500
commit65b62a29f719e937b5be1df472287f4c61e53ac6 (patch)
treeea6b552a08883d92cfedb891044fa9697cbc5619 /fs
parent37380e4264dbda9753e470a30d4322097aab7152 (diff)
NFSv4: Ensure delegation recall and byte range lock removal don't conflict
Add a mutex to the struct nfs4_state_owner to ensure that delegation recall doesn't conflict with byte range lock removal. Note that we nest the new mutex _outside_ the state manager reclaim protection (nfsi->rwsem) in order to avoid deadlocks. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/delegation.c7
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4proc.c9
-rw-r--r--fs/nfs/nfs4state.c1
4 files changed, 16 insertions, 2 deletions
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c
index 2542cdaa1116..6390a4b5fee7 100644
--- a/fs/nfs/delegation.c
+++ b/fs/nfs/delegation.c
@@ -71,8 +71,10 @@ static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_
71 int status = 0; 71 int status = 0;
72 72
73 if (inode->i_flock == NULL) 73 if (inode->i_flock == NULL)
74 goto out; 74 return 0;
75 75
76 if (inode->i_flock == NULL)
77 goto out;
76 /* Protect inode->i_flock using the file locks lock */ 78 /* Protect inode->i_flock using the file locks lock */
77 lock_flocks(); 79 lock_flocks();
78 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { 80 for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
@@ -113,12 +115,15 @@ again:
113 get_nfs_open_context(ctx); 115 get_nfs_open_context(ctx);
114 spin_unlock(&inode->i_lock); 116 spin_unlock(&inode->i_lock);
115 sp = state->owner; 117 sp = state->owner;
118 /* Block nfs4_proc_unlck */
119 mutex_lock(&sp->so_delegreturn_mutex);
116 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); 120 seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
117 err = nfs4_open_delegation_recall(ctx, state, stateid); 121 err = nfs4_open_delegation_recall(ctx, state, stateid);
118 if (!err) 122 if (!err)
119 err = nfs_delegation_claim_locks(ctx, state); 123 err = nfs_delegation_claim_locks(ctx, state);
120 if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) 124 if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
121 err = -EAGAIN; 125 err = -EAGAIN;
126 mutex_unlock(&sp->so_delegreturn_mutex);
122 put_nfs_open_context(ctx); 127 put_nfs_open_context(ctx);
123 if (err != 0) 128 if (err != 0)
124 return err; 129 return err;
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index b12b73472020..944c9a5c1039 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -93,6 +93,7 @@ struct nfs4_state_owner {
93 struct list_head so_states; 93 struct list_head so_states;
94 struct nfs_seqid_counter so_seqid; 94 struct nfs_seqid_counter so_seqid;
95 seqcount_t so_reclaim_seqcount; 95 seqcount_t so_reclaim_seqcount;
96 struct mutex so_delegreturn_mutex;
96}; 97};
97 98
98enum { 99enum {
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f7e05ade5572..d51227371c67 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -4485,7 +4485,9 @@ static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
4485 4485
4486static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request) 4486static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
4487{ 4487{
4488 struct nfs_inode *nfsi = NFS_I(state->inode); 4488 struct inode *inode = state->inode;
4489 struct nfs4_state_owner *sp = state->owner;
4490 struct nfs_inode *nfsi = NFS_I(inode);
4489 struct nfs_seqid *seqid; 4491 struct nfs_seqid *seqid;
4490 struct nfs4_lock_state *lsp; 4492 struct nfs4_lock_state *lsp;
4491 struct rpc_task *task; 4493 struct rpc_task *task;
@@ -4495,12 +4497,17 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
4495 status = nfs4_set_lock_state(state, request); 4497 status = nfs4_set_lock_state(state, request);
4496 /* Unlock _before_ we do the RPC call */ 4498 /* Unlock _before_ we do the RPC call */
4497 request->fl_flags |= FL_EXISTS; 4499 request->fl_flags |= FL_EXISTS;
4500 /* Exclude nfs_delegation_claim_locks() */
4501 mutex_lock(&sp->so_delegreturn_mutex);
4502 /* Exclude nfs4_reclaim_open_stateid() - note nesting! */
4498 down_read(&nfsi->rwsem); 4503 down_read(&nfsi->rwsem);
4499 if (do_vfs_lock(request->fl_file, request) == -ENOENT) { 4504 if (do_vfs_lock(request->fl_file, request) == -ENOENT) {
4500 up_read(&nfsi->rwsem); 4505 up_read(&nfsi->rwsem);
4506 mutex_unlock(&sp->so_delegreturn_mutex);
4501 goto out; 4507 goto out;
4502 } 4508 }
4503 up_read(&nfsi->rwsem); 4509 up_read(&nfsi->rwsem);
4510 mutex_unlock(&sp->so_delegreturn_mutex);
4504 if (status != 0) 4511 if (status != 0)
4505 goto out; 4512 goto out;
4506 /* Is this a delegated lock? */ 4513 /* Is this a delegated lock? */
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c
index fff97228cdec..6ace365c6334 100644
--- a/fs/nfs/nfs4state.c
+++ b/fs/nfs/nfs4state.c
@@ -519,6 +519,7 @@ nfs4_alloc_state_owner(struct nfs_server *server,
519 atomic_set(&sp->so_count, 1); 519 atomic_set(&sp->so_count, 1);
520 INIT_LIST_HEAD(&sp->so_lru); 520 INIT_LIST_HEAD(&sp->so_lru);
521 seqcount_init(&sp->so_reclaim_seqcount); 521 seqcount_init(&sp->so_reclaim_seqcount);
522 mutex_init(&sp->so_delegreturn_mutex);
522 return sp; 523 return sp;
523} 524}
524 525