Commit bde74e4b authored by Miklos Szeredi's avatar Miklos Szeredi Committed by Linus Torvalds

locks: add special return value for asynchronous locks

Use a special error value FILE_LOCK_DEFERRED to mean that a locking
operation returned asynchronously.  This is returned by

  posix_lock_file() for sleeping locks to mean that the lock has been
  queued on the block list, and will be woken up when it might become
  available and needs to be retried (either fl_lmops->fl_notify() is
  called or fl_wait is woken up).

  f_op->lock() to mean either the above, or that the filesystem will
  call back with fl_lmops->fl_grant() when the result of the locking
  operation is known.  The filesystem can do this for sleeping as well
  as non-sleeping locks.

This is to make sure, that return values of -EAGAIN and -EINPROGRESS by
filesystems are not mistaken to mean an asynchronous locking.

This also makes error handling in fs/locks.c and lockd/svclock.c slightly
cleaner.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Cc: Trond Myklebust <trond.myklebust@fys.uio.no>
Cc: "J. Bruce Fields" <bfields@fieldses.org>
Cc: Matthew Wilcox <matthew@wil.cx>
Cc: David Teigland <teigland@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent cc77b152
...@@ -116,7 +116,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file, ...@@ -116,7 +116,7 @@ int dlm_posix_lock(dlm_lockspace_t *lockspace, u64 number, struct file *file,
if (xop->callback == NULL) if (xop->callback == NULL)
wait_event(recv_wq, (op->done != 0)); wait_event(recv_wq, (op->done != 0));
else { else {
rv = -EINPROGRESS; rv = FILE_LOCK_DEFERRED;
goto out; goto out;
} }
......
...@@ -418,8 +418,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -418,8 +418,8 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out; goto out;
case -EAGAIN: case -EAGAIN:
ret = nlm_lck_denied; ret = nlm_lck_denied;
break; goto out;
case -EINPROGRESS: case FILE_LOCK_DEFERRED:
if (wait) if (wait)
break; break;
/* Filesystem lock operation is in progress /* Filesystem lock operation is in progress
...@@ -434,10 +434,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -434,10 +434,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
goto out; goto out;
} }
ret = nlm_lck_denied;
if (!wait)
goto out;
ret = nlm_lck_blocked; ret = nlm_lck_blocked;
/* Append to list of blocked */ /* Append to list of blocked */
...@@ -507,7 +503,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file, ...@@ -507,7 +503,7 @@ nlmsvc_testlock(struct svc_rqst *rqstp, struct nlm_file *file,
} }
error = vfs_test_lock(file->f_file, &lock->fl); error = vfs_test_lock(file->f_file, &lock->fl);
if (error == -EINPROGRESS) { if (error == FILE_LOCK_DEFERRED) {
ret = nlmsvc_defer_lock_rqst(rqstp, block); ret = nlmsvc_defer_lock_rqst(rqstp, block);
goto out; goto out;
} }
...@@ -731,8 +727,7 @@ nlmsvc_grant_blocked(struct nlm_block *block) ...@@ -731,8 +727,7 @@ nlmsvc_grant_blocked(struct nlm_block *block)
switch (error) { switch (error) {
case 0: case 0:
break; break;
case -EAGAIN: case FILE_LOCK_DEFERRED:
case -EINPROGRESS:
dprintk("lockd: lock still blocked error %d\n", error); dprintk("lockd: lock still blocked error %d\n", error);
nlmsvc_insert_block(block, NLM_NEVER); nlmsvc_insert_block(block, NLM_NEVER);
nlmsvc_release_block(block); nlmsvc_release_block(block);
......
...@@ -779,8 +779,10 @@ find_conflict: ...@@ -779,8 +779,10 @@ find_conflict:
if (!flock_locks_conflict(request, fl)) if (!flock_locks_conflict(request, fl))
continue; continue;
error = -EAGAIN; error = -EAGAIN;
if (request->fl_flags & FL_SLEEP) if (!(request->fl_flags & FL_SLEEP))
locks_insert_block(fl, request); goto out;
error = FILE_LOCK_DEFERRED;
locks_insert_block(fl, request);
goto out; goto out;
} }
if (request->fl_flags & FL_ACCESS) if (request->fl_flags & FL_ACCESS)
...@@ -836,7 +838,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str ...@@ -836,7 +838,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
error = -EDEADLK; error = -EDEADLK;
if (posix_locks_deadlock(request, fl)) if (posix_locks_deadlock(request, fl))
goto out; goto out;
error = -EAGAIN; error = FILE_LOCK_DEFERRED;
locks_insert_block(fl, request); locks_insert_block(fl, request);
goto out; goto out;
} }
...@@ -1035,7 +1037,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl) ...@@ -1035,7 +1037,7 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
might_sleep (); might_sleep ();
for (;;) { for (;;) {
error = posix_lock_file(filp, fl, NULL); error = posix_lock_file(filp, fl, NULL);
if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) if (error != FILE_LOCK_DEFERRED)
break; break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
if (!error) if (!error)
...@@ -1107,9 +1109,7 @@ int locks_mandatory_area(int read_write, struct inode *inode, ...@@ -1107,9 +1109,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
for (;;) { for (;;) {
error = __posix_lock_file(inode, &fl, NULL); error = __posix_lock_file(inode, &fl, NULL);
if (error != -EAGAIN) if (error != FILE_LOCK_DEFERRED)
break;
if (!(fl.fl_flags & FL_SLEEP))
break; break;
error = wait_event_interruptible(fl.fl_wait, !fl.fl_next); error = wait_event_interruptible(fl.fl_wait, !fl.fl_next);
if (!error) { if (!error) {
...@@ -1531,7 +1531,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl) ...@@ -1531,7 +1531,7 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
might_sleep(); might_sleep();
for (;;) { for (;;) {
error = flock_lock_file(filp, fl); error = flock_lock_file(filp, fl);
if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) if (error != FILE_LOCK_DEFERRED)
break; break;
error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
if (!error) if (!error)
...@@ -1716,17 +1716,17 @@ out: ...@@ -1716,17 +1716,17 @@ out:
* fl_grant is set. Callers expecting ->lock() to return asynchronously * fl_grant is set. Callers expecting ->lock() to return asynchronously
* will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if) * will only use F_SETLK, not F_SETLKW; they will set FL_SLEEP if (and only if)
* the request is for a blocking lock. When ->lock() does return asynchronously, * the request is for a blocking lock. When ->lock() does return asynchronously,
* it must return -EINPROGRESS, and call ->fl_grant() when the lock * it must return FILE_LOCK_DEFERRED, and call ->fl_grant() when the lock
* request completes. * request completes.
* If the request is for non-blocking lock the file system should return * If the request is for non-blocking lock the file system should return
* -EINPROGRESS then try to get the lock and call the callback routine with * FILE_LOCK_DEFERRED then try to get the lock and call the callback routine
* the result. If the request timed out the callback routine will return a * with the result. If the request timed out the callback routine will return a
* nonzero return code and the file system should release the lock. The file * nonzero return code and the file system should release the lock. The file
* system is also responsible to keep a corresponding posix lock when it * system is also responsible to keep a corresponding posix lock when it
* grants a lock so the VFS can find out which locks are locally held and do * grants a lock so the VFS can find out which locks are locally held and do
* the correct lock cleanup when required. * the correct lock cleanup when required.
* The underlying filesystem must not drop the kernel lock or call * The underlying filesystem must not drop the kernel lock or call
* ->fl_grant() before returning to the caller with a -EINPROGRESS * ->fl_grant() before returning to the caller with a FILE_LOCK_DEFERRED
* return code. * return code.
*/ */
int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf) int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
...@@ -1804,7 +1804,7 @@ again: ...@@ -1804,7 +1804,7 @@ again:
else { else {
for (;;) { for (;;) {
error = posix_lock_file(filp, file_lock, NULL); error = posix_lock_file(filp, file_lock, NULL);
if (error != -EAGAIN || cmd == F_SETLK) if (error != FILE_LOCK_DEFERRED)
break; break;
error = wait_event_interruptible(file_lock->fl_wait, error = wait_event_interruptible(file_lock->fl_wait,
!file_lock->fl_next); !file_lock->fl_next);
...@@ -1941,7 +1941,7 @@ again: ...@@ -1941,7 +1941,7 @@ again:
else { else {
for (;;) { for (;;) {
error = posix_lock_file(filp, file_lock, NULL); error = posix_lock_file(filp, file_lock, NULL);
if (error != -EAGAIN || cmd == F_SETLK64) if (error != FILE_LOCK_DEFERRED)
break; break;
error = wait_event_interruptible(file_lock->fl_wait, error = wait_event_interruptible(file_lock->fl_wait,
!file_lock->fl_next); !file_lock->fl_next);
......
...@@ -885,6 +885,12 @@ static inline int file_check_writeable(struct file *filp) ...@@ -885,6 +885,12 @@ static inline int file_check_writeable(struct file *filp)
#define FL_CLOSE 64 /* unlock on close */ #define FL_CLOSE 64 /* unlock on close */
#define FL_SLEEP 128 /* A blocking lock */ #define FL_SLEEP 128 /* A blocking lock */
/*
* Special return value from posix_lock_file() and vfs_lock_file() for
* asynchronous locking.
*/
#define FILE_LOCK_DEFERRED 1
/* /*
* The POSIX file lock owner is determined by * The POSIX file lock owner is determined by
* the "struct files_struct" in the thread group * the "struct files_struct" in the thread group
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment