Commit 65b62a29f719e937b5be1df472287f4c61e53ac6

Authored by Trond Myklebust
1 parent 37380e4264

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

... ... @@ -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;
... ... @@ -93,6 +93,7 @@
93 93 struct list_head so_states;
94 94 struct nfs_seqid_counter so_seqid;
95 95 seqcount_t so_reclaim_seqcount;
  96 + struct mutex so_delegreturn_mutex;
96 97 };
97 98  
98 99 enum {
... ... @@ -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? */
... ... @@ -519,6 +519,7 @@
519 519 atomic_set(&sp->so_count, 1);
520 520 INIT_LIST_HEAD(&sp->so_lru);
521 521 seqcount_init(&sp->so_reclaim_seqcount);
  522 + mutex_init(&sp->so_delegreturn_mutex);
522 523 return sp;
523 524 }
524 525