nfsd and lockd use F_SETLK cmd with the FL_SLEEP flag set to request asynchronous processing of blocking locks. Currently nfs v2/3 handles such requests by using nlmclnt_lock() -> do_vfs_lock() -> locks_lock_inode_wait() function which is blocked if request have FL_SLEEP flag set. To handle them correctly FL_SLEEP flag should be temporarily reset before executing the locks_lock_inode_wait() function. Additionally block flag is forced to set, to translate blocking lock to remote nfs server, expecting it supports async processing of the blocking locks too. https://bugzilla.kernel.org/show_bug.cgi?id=215383 Signed-off-by: Vasily Averin <vvs@xxxxxxxxxxxxx> --- fs/lockd/clntproc.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index 99fffc9cb958..5941aa7c9cc9 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -519,11 +519,18 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) unsigned char fl_flags = fl->fl_flags; unsigned char fl_type; int status = -ENOLCK; + bool async = false; if (nsm_monitor(host) < 0) goto out; req->a_args.state = nsm_local_state; + async = !req->a_args.block && + ((fl_flags & FL_SLEEP_POSIX) == FL_SLEEP_POSIX); + if (async) { + fl->fl_flags &= ~FL_SLEEP; + req->a_args.block = 1; + } fl->fl_flags |= FL_ACCESS; status = do_vfs_lock(fl); fl->fl_flags = fl_flags; @@ -573,8 +580,11 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl) up_read(&host->h_rwsem); goto again; } - /* Ensure the resulting lock will get added to granted list */ - fl->fl_flags |= FL_SLEEP; + if (async) + fl->fl_flags &= ~FL_SLEEP; + else + /* Ensure the resulting lock will get added to granted list */ + fl->fl_flags |= FL_SLEEP; if (do_vfs_lock(fl) < 0) printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __func__); up_read(&host->h_rwsem); -- 2.25.1