]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Fix posix file locking (7/9)
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Mon, 23 Aug 2004 07:14:14 +0000 (00:14 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 23 Aug 2004 07:14:14 +0000 (00:14 -0700)
VFS,CIFS,NLM,NFSv4: make filesystems directly responsible for calling
   posix_lock_file() if they need it. This fixes an NFS race whereby
   in case of a server reboot, the recovery thread could re-establish
   a lock that had just been freed.

Signed-off-by: Trond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/cifs/file.c
fs/lockd/clntproc.c
fs/locks.c
fs/nfs/nfs4proc.c
include/linux/fs.h

index 73505c6ccf3cf2b063392651de68e1f2f604fa95..f4f9c11713ca3914116a1cb7bacb188e15d7dd94 100644 (file)
@@ -569,6 +569,8 @@ cifs_lock(struct file *file, int cmd, struct file_lock *pfLock)
                         netfid, length,
                         pfLock->fl_start, numUnlock, numLock, lockType,
                         wait_flag);
+       if (rc == 0 && (pfLock->fl_flags & FL_POSIX))
+               posix_lock_file(file, pfLock);
        FreeXid(xid);
        return rc;
 }
index 996950d2360febd4397f73d802dd0cfb0e4a5ead..caad617bef6d9305a8755f23b730f4f44d697071 100644 (file)
@@ -561,6 +561,10 @@ nlmclnt_lock(struct nlm_rqst *req, struct file_lock *fl)
        if (resp->status == NLM_LCK_GRANTED) {
                fl->fl_u.nfs_fl.state = host->h_state;
                fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
+               fl->fl_flags |= FL_SLEEP;
+               if (posix_lock_file_wait(fl->fl_file, fl) < 0)
+                               printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n",
+                                               __FUNCTION__);
        }
        status = nlm_stat_to_errno(resp->status);
 out:
@@ -627,6 +631,9 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
        if (req->a_flags & RPC_TASK_ASYNC) {
                status = nlmclnt_async_call(req, NLMPROC_UNLOCK,
                                        nlmclnt_unlock_callback);
+               /* Hrmf... Do the unlock early since locks_remove_posix()
+                * really expects us to free the lock synchronously */
+               posix_lock_file(fl->fl_file, fl);
                if (status < 0) {
                        nlmclnt_release_lockargs(req);
                        kfree(req);
@@ -639,6 +646,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
        if (status < 0)
                return status;
 
+       posix_lock_file(fl->fl_file, fl);
        if (resp->status == NLM_LCK_GRANTED)
                return 0;
 
@@ -669,7 +677,6 @@ nlmclnt_unlock_callback(struct rpc_task *task)
        }
        if (status != NLM_LCK_GRANTED)
                printk(KERN_WARNING "lockd: unexpected unlock status: %d\n", status);
-
 die:
        nlm_release_host(req->a_host);
        nlmclnt_release_lockargs(req);
index d53677ada954c6e91c347e2a6a3775953a6d7383..df4060fc630d42f296831d15557b8f77478d2799 100644 (file)
@@ -906,6 +906,34 @@ int posix_lock_file(struct file *filp, struct file_lock *fl)
        return __posix_lock_file(filp->f_dentry->d_inode, fl);
 }
 
+/**
+ * posix_lock_file_wait - Apply a POSIX-style lock to a file
+ * @filp: The file to apply the lock to
+ * @fl: The lock to be applied
+ *
+ * Add a POSIX style lock to a file.
+ * We merge adjacent & overlapping locks whenever possible.
+ * POSIX locks are sorted by owner task, then by starting address
+ */
+int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
+{
+       int error;
+       might_sleep ();
+       for (;;) {
+               error = __posix_lock_file(filp->f_dentry->d_inode, fl);
+               if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP))
+                       break;
+               error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
+               if (!error)
+                       continue;
+
+               locks_delete_block(fl);
+               break;
+       }
+       return error;
+}
+EXPORT_SYMBOL(posix_lock_file_wait);
+
 /**
  * locks_mandatory_locked - Check for an active lock
  * @inode: the file to check
@@ -1483,8 +1511,7 @@ int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l)
 
        if (filp->f_op && filp->f_op->lock != NULL) {
                error = filp->f_op->lock(filp, cmd, file_lock);
-               if (error < 0)
-                       goto out;
+               goto out;
        }
 
        for (;;) {
@@ -1618,8 +1645,7 @@ int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
 
        if (filp->f_op && filp->f_op->lock != NULL) {
                error = filp->f_op->lock(filp, cmd, file_lock);
-               if (error < 0)
-                       goto out;
+               goto out;
        }
 
        for (;;) {
@@ -1671,7 +1697,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
 
        if (filp->f_op && filp->f_op->lock != NULL) {
                filp->f_op->lock(filp, F_SETLK, &lock);
-               /* Ignore any error -- we must remove the locks anyway */
+               goto out;
        }
 
        /* Can't use posix_lock_file here; we need to remove it no matter
@@ -1687,6 +1713,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
                before = &fl->fl_next;
        }
        unlock_kernel();
+out:
        if (lock.fl_ops && lock.fl_ops->fl_release_private)
                lock.fl_ops->fl_release_private(&lock);
 }
index 2eb124475a23a5123419c15c45971614ab5e441d..1b7338db87cb4d6ce9ccf5bcad9971ba5bebfa46 100644 (file)
@@ -1856,6 +1856,8 @@ nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *request)
        nfs4_put_lock_state(lsp);
 out:
        up(&state->lock_sema);
+       if (status == 0)
+               posix_lock_file(request->fl_file, request);
        return nfs4_map_errors(status);
 }
 
@@ -1932,6 +1934,12 @@ nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
        nfs4_put_lock_state(lsp);
 out:
        up(&state->lock_sema);
+       if (status == 0) {
+               /* Note: we always want to sleep here! */
+               request->fl_flags |= FL_SLEEP;
+               if (posix_lock_file_wait(request->fl_file, request) < 0)
+                       printk(KERN_WARNING "%s: VFS is out of sync with lock manager!\n", __FUNCTION__);
+       }
        return nfs4_map_errors(status);
 }
 
index 2413530b359175e9a4a2cd5ecc53f30e9aa36432..f3af88a992902505445fb1b26a83ea09b5ef09ec 100644 (file)
@@ -690,6 +690,7 @@ extern void locks_remove_posix(struct file *, fl_owner_t);
 extern void locks_remove_flock(struct file *);
 extern struct file_lock *posix_test_lock(struct file *, struct file_lock *);
 extern int posix_lock_file(struct file *, struct file_lock *);
+extern int posix_lock_file_wait(struct file *, struct file_lock *);
 extern void posix_block_lock(struct file_lock *, struct file_lock *);
 extern void posix_unblock_lock(struct file *, struct file_lock *);
 extern int posix_locks_deadlock(struct file_lock *, struct file_lock *);