mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 10:19:47 +00:00
NFSv4.1: Prevent deadlocks between state recovery and file locking
We currently have a deadlock in which the state recovery thread ends up blocking due to one of the locks which it is trying to recover holding the nfs_inode->rwsem. The situation is as follows: the state recovery thread is scheduled in order to recover from a reboot. It immediately drains the session, forcing all ordinary NFSv4.1 calls to nfs41_setup_sequence() to be put to sleep. This includes the file locking process that holds the nfs_inode->rwsem. When the thread gets to nfs4_reclaim_locks(), it tries to grab a write lock on nfs_inode->rwsem, and boom... Fix is to have the lock drop the nfs_inode->rwsem while it is doing RPC calls. We use a sequence lock in order to signal to the locking process whether or not a state recovery thread has run on that inode, in which case it should retry the lock. Reported-by: Andy Adamson <andros@netapp.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
c137afabe3
commit
9a99af494b
1 changed files with 9 additions and 0 deletions
|
@ -4813,8 +4813,10 @@ static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *reques
|
|||
|
||||
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
||||
{
|
||||
struct nfs4_state_owner *sp = state->owner;
|
||||
struct nfs_inode *nfsi = NFS_I(state->inode);
|
||||
unsigned char fl_flags = request->fl_flags;
|
||||
unsigned int seq;
|
||||
int status = -ENOLCK;
|
||||
|
||||
if ((fl_flags & FL_POSIX) &&
|
||||
|
@ -4836,9 +4838,16 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
|
|||
status = do_vfs_lock(request->fl_file, request);
|
||||
goto out_unlock;
|
||||
}
|
||||
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
|
||||
up_read(&nfsi->rwsem);
|
||||
status = _nfs4_do_setlk(state, cmd, request, NFS_LOCK_NEW);
|
||||
if (status != 0)
|
||||
goto out;
|
||||
down_read(&nfsi->rwsem);
|
||||
if (read_seqcount_retry(&sp->so_reclaim_seqcount, seq)) {
|
||||
status = -NFS4ERR_DELAY;
|
||||
goto out_unlock;
|
||||
}
|
||||
/* Note: we always want to sleep here! */
|
||||
request->fl_flags = fl_flags | FL_SLEEP;
|
||||
if (do_vfs_lock(request->fl_file, request) < 0)
|
||||
|
|
Loading…
Reference in a new issue