locks: convert an -EINVAL return to a BUG
[linux-2.6.git] / fs / locks.c
index ee46584..3c23fd2 100644 (file)
@@ -203,10 +203,6 @@ static void init_once(void *foo, struct kmem_cache *cache, unsigned long flags)
 {
        struct file_lock *lock = (struct file_lock *) foo;
 
-       if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) !=
-                                       SLAB_CTOR_CONSTRUCTOR)
-               return;
-
        locks_init_lock(lock);
 }
 
@@ -670,7 +666,6 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
 {
        struct file_lock *cfl;
 
-       fl->fl_type = F_UNLCK;
        lock_kernel();
        for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
                if (!IS_POSIX(cfl))
@@ -682,7 +677,8 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
                __locks_copy_lock(fl, cfl);
                unlock_kernel();
                return 1;
-       }
+       } else
+               fl->fl_type = F_UNLCK;
        unlock_kernel();
        return 0;
 }
@@ -1173,9 +1169,9 @@ static void time_out_leases(struct inode *inode)
  *     @inode: the inode of the file to return
  *     @mode: the open mode (read or write)
  *
- *     break_lease (inlined for speed) has checked there already
- *     is a lease on this file.  Leases are broken on a call to open()
- *     or truncate().  This function can sleep unless you
+ *     break_lease (inlined for speed) has checked there already is at least
+ *     some kind of lock (maybe a lease) on this file.  Leases are broken on
+ *     a call to open() or truncate().  This function can sleep unless you
  *     specified %O_NONBLOCK to your open().
  */
 int __break_lease(struct inode *inode, unsigned int mode)
@@ -1352,9 +1348,7 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
 
        time_out_leases(inode);
 
-       error = -EINVAL;
-       if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
-               goto out;
+       BUG_ON(!(*flp)->fl_lmops->fl_break);
 
        lease = *flp;
 
@@ -1633,6 +1627,7 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
        flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
                fl->fl_end - fl->fl_start + 1;
        flock->l_whence = 0;
+       flock->l_type = fl->fl_type;
        return 0;
 }
 
@@ -1698,6 +1693,25 @@ out:
  * If the filesystem defines a private ->lock() method, then @conf will
  * be left unchanged; so a caller that cares should initialize it to
  * some acceptable default.
+ *
+ * To avoid blocking kernel daemons, such as lockd, that need to acquire POSIX
+ * locks, the ->lock() interface may return asynchronously, before the lock has
+ * been granted or denied by the underlying filesystem, if (and only if)
+ * 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)
+ * the request is for a blocking lock. When ->lock() does return asynchronously,
+ * it must return -EINPROGRESS, and call ->fl_grant() when the lock
+ * request completes.
+ * 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
+ * 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
+ * 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
+ * the correct lock cleanup when required.
+ * The underlying filesystem must not drop the kernel lock or call
+ * ->fl_grant() before returning to the caller with a -EINPROGRESS
+ * return code.
  */
 int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
 {
@@ -2028,6 +2042,22 @@ posix_unblock_lock(struct file *filp, struct file_lock *waiter)
 
 EXPORT_SYMBOL(posix_unblock_lock);
 
+/**
+ * vfs_cancel_lock - file byte range unblock lock
+ * @filp: The file to apply the unblock to
+ * @fl: The lock to be unblocked
+ *
+ * Used by lock managers to cancel blocked requests
+ */
+int vfs_cancel_lock(struct file *filp, struct file_lock *fl)
+{
+       if (filp->f_op && filp->f_op->lock)
+               return filp->f_op->lock(filp, F_CANCELLK, fl);
+       return 0;
+}
+
+EXPORT_SYMBOL_GPL(vfs_cancel_lock);
+
 static void lock_get_status(char* out, struct file_lock *fl, int id, char *pfx)
 {
        struct inode *inode = NULL;