Commit 65b62a29f719e937b5be1df472287f4c61e53ac6
1 parent
37380e4264
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 4 changed files with 16 additions and 2 deletions Side-by-side Diff
fs/nfs/delegation.c
... | ... | @@ -71,8 +71,10 @@ |
71 | 71 | int status = 0; |
72 | 72 | |
73 | 73 | if (inode->i_flock == NULL) |
74 | - goto out; | |
74 | + return 0; | |
75 | 75 | |
76 | + if (inode->i_flock == NULL) | |
77 | + goto out; | |
76 | 78 | /* Protect inode->i_flock using the file locks lock */ |
77 | 79 | lock_flocks(); |
78 | 80 | for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) { |
79 | 81 | |
... | ... | @@ -113,12 +115,15 @@ |
113 | 115 | get_nfs_open_context(ctx); |
114 | 116 | spin_unlock(&inode->i_lock); |
115 | 117 | sp = state->owner; |
118 | + /* Block nfs4_proc_unlck */ | |
119 | + mutex_lock(&sp->so_delegreturn_mutex); | |
116 | 120 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); |
117 | 121 | err = nfs4_open_delegation_recall(ctx, state, stateid); |
118 | 122 | if (!err) |
119 | 123 | err = nfs_delegation_claim_locks(ctx, state); |
120 | 124 | if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) |
121 | 125 | err = -EAGAIN; |
126 | + mutex_unlock(&sp->so_delegreturn_mutex); | |
122 | 127 | put_nfs_open_context(ctx); |
123 | 128 | if (err != 0) |
124 | 129 | return err; |
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
... | ... | @@ -4485,7 +4485,9 @@ |
4485 | 4485 | |
4486 | 4486 | static 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 | 4491 | struct nfs_seqid *seqid; |
4490 | 4492 | struct nfs4_lock_state *lsp; |
4491 | 4493 | struct rpc_task *task; |
4492 | 4494 | |
4493 | 4495 | |
... | ... | @@ -4495,12 +4497,17 @@ |
4495 | 4497 | status = nfs4_set_lock_state(state, request); |
4496 | 4498 | /* Unlock _before_ we do the RPC call */ |
4497 | 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 | 4503 | down_read(&nfsi->rwsem); |
4499 | 4504 | if (do_vfs_lock(request->fl_file, request) == -ENOENT) { |
4500 | 4505 | up_read(&nfsi->rwsem); |
4506 | + mutex_unlock(&sp->so_delegreturn_mutex); | |
4501 | 4507 | goto out; |
4502 | 4508 | } |
4503 | 4509 | up_read(&nfsi->rwsem); |
4510 | + mutex_unlock(&sp->so_delegreturn_mutex); | |
4504 | 4511 | if (status != 0) |
4505 | 4512 | goto out; |
4506 | 4513 | /* Is this a delegated lock? */ |