Merge tag 'lsk-v3.10-android-14.12'
[firefly-linux-kernel-4.4.55.git] / fs / locks.c
index b286539d547a5a11db6760688fcc8f1a37360ec3..0274c953b07db22893fed58531712793206b6a72 100644 (file)
@@ -60,7 +60,7 @@
  *
  *  Initial implementation of mandatory locks. SunOS turned out to be
  *  a rotten model, so I implemented the "obvious" semantics.
- *  See 'Documentation/mandatory.txt' for details.
+ *  See 'Documentation/filesystems/mandatory-locking.txt' for details.
  *  Andy Walker (andy@lysaker.kvaerner.no), April 06, 1996.
  *
  *  Don't allow mandatory locks on mmap()'ed files. Added simple functions to
 #define IS_FLOCK(fl)   (fl->fl_flags & FL_FLOCK)
 #define IS_LEASE(fl)   (fl->fl_flags & FL_LEASE)
 
+static bool lease_breaking(struct file_lock *fl)
+{
+       return fl->fl_flags & (FL_UNLOCK_PENDING | FL_DOWNGRADE_PENDING);
+}
+
+static int target_leasetype(struct file_lock *fl)
+{
+       if (fl->fl_flags & FL_UNLOCK_PENDING)
+               return F_UNLCK;
+       if (fl->fl_flags & FL_DOWNGRADE_PENDING)
+               return F_RDLCK;
+       return fl->fl_type;
+}
+
 int leases_enable = 1;
 int lease_break_time = 45;
 
@@ -160,26 +174,20 @@ EXPORT_SYMBOL_GPL(unlock_flocks);
 
 static struct kmem_cache *filelock_cache __read_mostly;
 
-static void locks_init_lock_always(struct file_lock *fl)
+static void locks_init_lock_heads(struct file_lock *fl)
 {
-       fl->fl_next = NULL;
-       fl->fl_fasync = NULL;
-       fl->fl_owner = NULL;
-       fl->fl_pid = 0;
-       fl->fl_nspid = NULL;
-       fl->fl_file = NULL;
-       fl->fl_flags = 0;
-       fl->fl_type = 0;
-       fl->fl_start = fl->fl_end = 0;
+       INIT_LIST_HEAD(&fl->fl_link);
+       INIT_LIST_HEAD(&fl->fl_block);
+       init_waitqueue_head(&fl->fl_wait);
 }
 
 /* Allocate an empty lock structure. */
 struct file_lock *locks_alloc_lock(void)
 {
-       struct file_lock *fl = kmem_cache_alloc(filelock_cache, GFP_KERNEL);
+       struct file_lock *fl = kmem_cache_zalloc(filelock_cache, GFP_KERNEL);
 
        if (fl)
-               locks_init_lock_always(fl);
+               locks_init_lock_heads(fl);
 
        return fl;
 }
@@ -192,11 +200,7 @@ void locks_release_private(struct file_lock *fl)
                        fl->fl_ops->fl_release_private(fl);
                fl->fl_ops = NULL;
        }
-       if (fl->fl_lmops) {
-               if (fl->fl_lmops->fl_release_private)
-                       fl->fl_lmops->fl_release_private(fl);
-               fl->fl_lmops = NULL;
-       }
+       fl->fl_lmops = NULL;
 
 }
 EXPORT_SYMBOL_GPL(locks_release_private);
@@ -215,27 +219,12 @@ EXPORT_SYMBOL(locks_free_lock);
 
 void locks_init_lock(struct file_lock *fl)
 {
-       INIT_LIST_HEAD(&fl->fl_link);
-       INIT_LIST_HEAD(&fl->fl_block);
-       init_waitqueue_head(&fl->fl_wait);
-       fl->fl_ops = NULL;
-       fl->fl_lmops = NULL;
-       locks_init_lock_always(fl);
+       memset(fl, 0, sizeof(struct file_lock));
+       locks_init_lock_heads(fl);
 }
 
 EXPORT_SYMBOL(locks_init_lock);
 
-/*
- * Initialises the fields of the file lock which are invariant for
- * free file_locks.
- */
-static void init_once(void *foo)
-{
-       struct file_lock *lock = (struct file_lock *) foo;
-
-       locks_init_lock(lock);
-}
-
 static void locks_copy_private(struct file_lock *new, struct file_lock *fl)
 {
        if (fl->fl_ops) {
@@ -315,7 +304,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock,
        return 0;
 }
 
-static int assign_type(struct file_lock *fl, int type)
+static int assign_type(struct file_lock *fl, long type)
 {
        switch (type) {
        case F_RDLCK:
@@ -345,7 +334,7 @@ static int flock_to_posix_lock(struct file *filp, struct file_lock *fl,
                start = filp->f_pos;
                break;
        case SEEK_END:
-               start = i_size_read(filp->f_path.dentry->d_inode);
+               start = i_size_read(file_inode(filp));
                break;
        default:
                return -EINVAL;
@@ -395,7 +384,7 @@ static int flock64_to_posix_lock(struct file *filp, struct file_lock *fl,
                start = filp->f_pos;
                break;
        case SEEK_END:
-               start = i_size_read(filp->f_path.dentry->d_inode);
+               start = i_size_read(file_inode(filp));
                break;
        default:
                return -EINVAL;
@@ -434,25 +423,15 @@ static void lease_break_callback(struct file_lock *fl)
        kill_fasync(&fl->fl_fasync, SIGIO, POLL_MSG);
 }
 
-static void lease_release_private_callback(struct file_lock *fl)
-{
-       if (!fl->fl_file)
-               return;
-
-       f_delown(fl->fl_file);
-       fl->fl_file->f_owner.signum = 0;
-}
-
 static const struct lock_manager_operations lease_manager_ops = {
-       .fl_break = lease_break_callback,
-       .fl_release_private = lease_release_private_callback,
-       .fl_change = lease_modify,
+       .lm_break = lease_break_callback,
+       .lm_change = lease_modify,
 };
 
 /*
  * Initialize a lease, use the default lock manager operations
  */
-static int lease_init(struct file *filp, int type, struct file_lock *fl)
+static int lease_init(struct file *filp, long type, struct file_lock *fl)
  {
        if (assign_type(fl, type) != 0)
                return -EINVAL;
@@ -470,7 +449,7 @@ static int lease_init(struct file *filp, int type, struct file_lock *fl)
 }
 
 /* Allocate a file_lock initialised to this type of lease */
-static struct file_lock *lease_alloc(struct file *filp, int type)
+static struct file_lock *lease_alloc(struct file *filp, long type)
 {
        struct file_lock *fl = locks_alloc_lock();
        int error = -ENOMEM;
@@ -499,9 +478,9 @@ static inline int locks_overlap(struct file_lock *fl1, struct file_lock *fl2)
  */
 static int posix_same_owner(struct file_lock *fl1, struct file_lock *fl2)
 {
-       if (fl1->fl_lmops && fl1->fl_lmops->fl_compare_owner)
+       if (fl1->fl_lmops && fl1->fl_lmops->lm_compare_owner)
                return fl2->fl_lmops == fl1->fl_lmops &&
-                       fl1->fl_lmops->fl_compare_owner(fl1, fl2);
+                       fl1->fl_lmops->lm_compare_owner(fl1, fl2);
        return fl1->fl_owner == fl2->fl_owner;
 }
 
@@ -517,12 +496,13 @@ static void __locks_delete_block(struct file_lock *waiter)
 
 /*
  */
-static void locks_delete_block(struct file_lock *waiter)
+void locks_delete_block(struct file_lock *waiter)
 {
        lock_flocks();
        __locks_delete_block(waiter);
        unlock_flocks();
 }
+EXPORT_SYMBOL(locks_delete_block);
 
 /* Insert waiter into blocker's block list.
  * We use a circular list so that processes can be easily woken up in
@@ -551,8 +531,8 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
                waiter = list_first_entry(&blocker->fl_block,
                                struct file_lock, fl_block);
                __locks_delete_block(waiter);
-               if (waiter->fl_lmops && waiter->fl_lmops->fl_notify)
-                       waiter->fl_lmops->fl_notify(waiter);
+               if (waiter->fl_lmops && waiter->fl_lmops->lm_notify)
+                       waiter->fl_lmops->lm_notify(waiter);
                else
                        wake_up(&waiter->fl_wait);
        }
@@ -586,12 +566,6 @@ static void locks_delete_lock(struct file_lock **thisfl_p)
        fl->fl_next = NULL;
        list_del_init(&fl->fl_link);
 
-       fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
-       if (fl->fl_fasync != NULL) {
-               printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
-               fl->fl_fasync = NULL;
-       }
-
        if (fl->fl_nspid) {
                put_pid(fl->fl_nspid);
                fl->fl_nspid = NULL;
@@ -653,7 +627,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
        struct file_lock *cfl;
 
        lock_flocks();
-       for (cfl = filp->f_path.dentry->d_inode->i_flock; cfl; cfl = cfl->fl_next) {
+       for (cfl = file_inode(filp)->i_flock; cfl; cfl = cfl->fl_next) {
                if (!IS_POSIX(cfl))
                        continue;
                if (posix_locks_conflict(fl, cfl))
@@ -734,7 +708,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
 {
        struct file_lock *new_fl = NULL;
        struct file_lock **before;
-       struct inode * inode = filp->f_path.dentry->d_inode;
+       struct inode * inode = file_inode(filp);
        int error = 0;
        int found = 0;
 
@@ -1028,7 +1002,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
 int posix_lock_file(struct file *filp, struct file_lock *fl,
                        struct file_lock *conflock)
 {
-       return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock);
+       return __posix_lock_file(file_inode(filp), fl, conflock);
 }
 EXPORT_SYMBOL(posix_lock_file);
 
@@ -1140,6 +1114,17 @@ int locks_mandatory_area(int read_write, struct inode *inode,
 
 EXPORT_SYMBOL(locks_mandatory_area);
 
+static void lease_clear_pending(struct file_lock *fl, int arg)
+{
+       switch (arg) {
+       case F_UNLCK:
+               fl->fl_flags &= ~FL_UNLOCK_PENDING;
+               /* fall through: */
+       case F_RDLCK:
+               fl->fl_flags &= ~FL_DOWNGRADE_PENDING;
+       }
+}
+
 /* We already had a lease on this file; just change its type */
 int lease_modify(struct file_lock **before, int arg)
 {
@@ -1148,27 +1133,44 @@ int lease_modify(struct file_lock **before, int arg)
 
        if (error)
                return error;
+       lease_clear_pending(fl, arg);
        locks_wake_up_blocks(fl);
-       if (arg == F_UNLCK)
+       if (arg == F_UNLCK) {
+               struct file *filp = fl->fl_file;
+
+               f_delown(filp);
+               filp->f_owner.signum = 0;
+               fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
+               if (fl->fl_fasync != NULL) {
+                       printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
+                       fl->fl_fasync = NULL;
+               }
                locks_delete_lock(before);
+       }
        return 0;
 }
 
 EXPORT_SYMBOL(lease_modify);
 
+static bool past_time(unsigned long then)
+{
+       if (!then)
+               /* 0 is a special value meaning "this never expires": */
+               return false;
+       return time_after(jiffies, then);
+}
+
 static void time_out_leases(struct inode *inode)
 {
        struct file_lock **before;
        struct file_lock *fl;
 
        before = &inode->i_flock;
-       while ((fl = *before) && IS_LEASE(fl) && (fl->fl_type & F_INPROGRESS)) {
-               if ((fl->fl_break_time == 0)
-                               || time_before(jiffies, fl->fl_break_time)) {
-                       before = &fl->fl_next;
-                       continue;
-               }
-               lease_modify(before, fl->fl_type & ~F_INPROGRESS);
+       while ((fl = *before) && IS_LEASE(fl) && lease_breaking(fl)) {
+               if (past_time(fl->fl_downgrade_time))
+                       lease_modify(before, F_RDLCK);
+               if (past_time(fl->fl_break_time))
+                       lease_modify(before, F_UNLCK);
                if (fl == *before)      /* lease_modify may have freed fl */
                        before = &fl->fl_next;
        }
@@ -1186,7 +1188,7 @@ static void time_out_leases(struct inode *inode)
  */
 int __break_lease(struct inode *inode, unsigned int mode)
 {
-       int error = 0, future;
+       int error = 0;
        struct file_lock *new_fl, *flock;
        struct file_lock *fl;
        unsigned long break_time;
@@ -1194,6 +1196,8 @@ int __break_lease(struct inode *inode, unsigned int mode)
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
 
        new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
+       if (IS_ERR(new_fl))
+               return PTR_ERR(new_fl);
 
        lock_flocks();
 
@@ -1203,30 +1207,13 @@ int __break_lease(struct inode *inode, unsigned int mode)
        if ((flock == NULL) || !IS_LEASE(flock))
                goto out;
 
+       if (!locks_conflict(flock, new_fl))
+               goto out;
+
        for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next)
                if (fl->fl_owner == current->files)
                        i_have_this_lease = 1;
 
-       if (want_write) {
-               /* If we want write access, we have to revoke any lease. */
-               future = F_UNLCK | F_INPROGRESS;
-       } else if (flock->fl_type & F_INPROGRESS) {
-               /* If the lease is already being broken, we just leave it */
-               future = flock->fl_type;
-       } else if (flock->fl_type & F_WRLCK) {
-               /* Downgrade the exclusive lease to a read-only lease. */
-               future = F_RDLCK | F_INPROGRESS;
-       } else {
-               /* the existing lease was read-only, so we can read too. */
-               goto out;
-       }
-
-       if (IS_ERR(new_fl) && !i_have_this_lease
-                       && ((mode & O_NONBLOCK) == 0)) {
-               error = PTR_ERR(new_fl);
-               goto out;
-       }
-
        break_time = 0;
        if (lease_break_time > 0) {
                break_time = jiffies + lease_break_time * HZ;
@@ -1235,12 +1222,18 @@ int __break_lease(struct inode *inode, unsigned int mode)
        }
 
        for (fl = flock; fl && IS_LEASE(fl); fl = fl->fl_next) {
-               if (fl->fl_type != future) {
-                       fl->fl_type = future;
+               if (want_write) {
+                       if (fl->fl_flags & FL_UNLOCK_PENDING)
+                               continue;
+                       fl->fl_flags |= FL_UNLOCK_PENDING;
                        fl->fl_break_time = break_time;
-                       /* lease must have lmops break callback */
-                       fl->fl_lmops->fl_break(fl);
+               } else {
+                       if (lease_breaking(flock))
+                               continue;
+                       fl->fl_flags |= FL_DOWNGRADE_PENDING;
+                       fl->fl_downgrade_time = break_time;
                }
+               fl->fl_lmops->lm_break(fl);
        }
 
        if (i_have_this_lease || (mode & O_NONBLOCK)) {
@@ -1250,11 +1243,10 @@ int __break_lease(struct inode *inode, unsigned int mode)
 
 restart:
        break_time = flock->fl_break_time;
-       if (break_time != 0) {
+       if (break_time != 0)
                break_time -= jiffies;
-               if (break_time == 0)
-                       break_time++;
-       }
+       if (break_time == 0)
+               break_time++;
        locks_insert_block(flock, new_fl);
        unlock_flocks();
        error = wait_event_interruptible_timeout(new_fl->fl_wait,
@@ -1264,10 +1256,13 @@ restart:
        if (error >= 0) {
                if (error == 0)
                        time_out_leases(inode);
-               /* Wait for the next lease that has not been broken yet */
+               /*
+                * Wait for the next conflicting lease that has not been
+                * broken yet
+                */
                for (flock = inode->i_flock; flock && IS_LEASE(flock);
                                flock = flock->fl_next) {
-                       if (flock->fl_type & F_INPROGRESS)
+                       if (locks_conflict(new_fl, flock))
                                goto restart;
                }
                error = 0;
@@ -1275,8 +1270,7 @@ restart:
 
 out:
        unlock_flocks();
-       if (!IS_ERR(new_fl))
-               locks_free_lock(new_fl);
+       locks_free_lock(new_fl);
        return error;
 }
 
@@ -1294,7 +1288,7 @@ EXPORT_SYMBOL(__break_lease);
 void lease_get_mtime(struct inode *inode, struct timespec *time)
 {
        struct file_lock *flock = inode->i_flock;
-       if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK))
+       if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))
                *time = current_fs_time(inode->i_sb);
        else
                *time = inode->i_mtime;
@@ -1331,11 +1325,11 @@ int fcntl_getlease(struct file *filp)
        int type = F_UNLCK;
 
        lock_flocks();
-       time_out_leases(filp->f_path.dentry->d_inode);
-       for (fl = filp->f_path.dentry->d_inode->i_flock; fl && IS_LEASE(fl);
+       time_out_leases(file_inode(filp));
+       for (fl = file_inode(filp)->i_flock; fl && IS_LEASE(fl);
                        fl = fl->fl_next) {
                if (fl->fl_file == filp) {
-                       type = fl->fl_type & ~F_INPROGRESS;
+                       type = target_leasetype(fl);
                        break;
                }
        }
@@ -1343,50 +1337,23 @@ int fcntl_getlease(struct file *filp)
        return type;
 }
 
-/**
- *     generic_setlease        -       sets a lease on an open file
- *     @filp: file pointer
- *     @arg: type of lease to obtain
- *     @flp: input - file_lock to use, output - file_lock inserted
- *
- *     The (input) flp->fl_lmops->fl_break function is required
- *     by break_lease().
- *
- *     Called with file_lock_lock held.
- */
-int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
+int generic_add_lease(struct file *filp, long arg, struct file_lock **flp)
 {
        struct file_lock *fl, **before, **my_before = NULL, *lease;
        struct dentry *dentry = filp->f_path.dentry;
        struct inode *inode = dentry->d_inode;
-       int error, rdlease_count = 0, wrlease_count = 0;
+       int error;
 
        lease = *flp;
 
-       error = -EACCES;
-       if ((current_fsuid() != inode->i_uid) && !capable(CAP_LEASE))
-               goto out;
-       error = -EINVAL;
-       if (!S_ISREG(inode->i_mode))
+       error = -EAGAIN;
+       if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
                goto out;
-       error = security_file_lock(filp, arg);
-       if (error)
+       if ((arg == F_WRLCK)
+           && ((dentry->d_count > 1)
+               || (atomic_read(&inode->i_count) > 1)))
                goto out;
 
-       time_out_leases(inode);
-
-       BUG_ON(!(*flp)->fl_lmops->fl_break);
-
-       if (arg != F_UNLCK) {
-               error = -EAGAIN;
-               if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
-                       goto out;
-               if ((arg == F_WRLCK)
-                   && ((dentry->d_count > 1)
-                       || (atomic_read(&inode->i_count) > 1)))
-                       goto out;
-       }
-
        /*
         * At this point, we know that if there is an exclusive
         * lease on this file, then we hold it on this filp
@@ -1395,37 +1362,35 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
         * then the file is not open by anyone (including us)
         * except for this filp.
         */
+       error = -EAGAIN;
        for (before = &inode->i_flock;
                        ((fl = *before) != NULL) && IS_LEASE(fl);
                        before = &fl->fl_next) {
-               if (fl->fl_file == filp)
+               if (fl->fl_file == filp) {
                        my_before = before;
-               else if (fl->fl_type == (F_INPROGRESS | F_UNLCK))
-                       /*
-                        * Someone is in the process of opening this
-                        * file for writing so we may not take an
-                        * exclusive lease on it.
-                        */
-                       wrlease_count++;
-               else
-                       rdlease_count++;
+                       continue;
+               }
+               /*
+                * No exclusive leases if someone else has a lease on
+                * this file:
+                */
+               if (arg == F_WRLCK)
+                       goto out;
+               /*
+                * Modifying our existing lease is OK, but no getting a
+                * new lease if someone else is opening for write:
+                */
+               if (fl->fl_flags & FL_UNLOCK_PENDING)
+                       goto out;
        }
 
-       error = -EAGAIN;
-       if ((arg == F_RDLCK && (wrlease_count > 0)) ||
-           (arg == F_WRLCK && ((rdlease_count + wrlease_count) > 0)))
-               goto out;
-
        if (my_before != NULL) {
-               error = lease->fl_lmops->fl_change(my_before, arg);
+               error = lease->fl_lmops->lm_change(my_before, arg);
                if (!error)
                        *flp = *my_before;
                goto out;
        }
 
-       if (arg == F_UNLCK)
-               goto out;
-
        error = -EINVAL;
        if (!leases_enable)
                goto out;
@@ -1436,6 +1401,62 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
 out:
        return error;
 }
+
+int generic_delete_lease(struct file *filp, struct file_lock **flp)
+{
+       struct file_lock *fl, **before;
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+
+       for (before = &inode->i_flock;
+                       ((fl = *before) != NULL) && IS_LEASE(fl);
+                       before = &fl->fl_next) {
+               if (fl->fl_file != filp)
+                       continue;
+               return (*flp)->fl_lmops->lm_change(before, F_UNLCK);
+       }
+       return -EAGAIN;
+}
+
+/**
+ *     generic_setlease        -       sets a lease on an open file
+ *     @filp: file pointer
+ *     @arg: type of lease to obtain
+ *     @flp: input - file_lock to use, output - file_lock inserted
+ *
+ *     The (input) flp->fl_lmops->lm_break function is required
+ *     by break_lease().
+ *
+ *     Called with file_lock_lock held.
+ */
+int generic_setlease(struct file *filp, long arg, struct file_lock **flp)
+{
+       struct dentry *dentry = filp->f_path.dentry;
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
+               return -EACCES;
+       if (!S_ISREG(inode->i_mode))
+               return -EINVAL;
+       error = security_file_lock(filp, arg);
+       if (error)
+               return error;
+
+       time_out_leases(inode);
+
+       BUG_ON(!(*flp)->fl_lmops->lm_break);
+
+       switch (arg) {
+       case F_UNLCK:
+               return generic_delete_lease(filp, flp);
+       case F_RDLCK:
+       case F_WRLCK:
+               return generic_add_lease(filp, arg, flp);
+       default:
+               return -EINVAL;
+       }
+}
 EXPORT_SYMBOL(generic_setlease);
 
 static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
@@ -1453,7 +1474,7 @@ static int __vfs_setlease(struct file *filp, long arg, struct file_lock **lease)
  *     @lease: file_lock to use
  *
  *     Call this to establish a lease on the file.
- *     The (*lease)->fl_lmops->fl_break operation must be set; if not,
+ *     The (*lease)->fl_lmops->lm_break operation must be set; if not,
  *     break_lease will oops!
  *
  *     This will call the filesystem's setlease file method, if
@@ -1603,14 +1624,13 @@ EXPORT_SYMBOL(flock_lock_file_wait);
  */
 SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
 {
-       struct file *filp;
+       struct fd f = fdget(fd);
        struct file_lock *lock;
        int can_sleep, unlock;
        int error;
 
        error = -EBADF;
-       filp = fget(fd);
-       if (!filp)
+       if (!f.file)
                goto out;
 
        can_sleep = !(cmd & LOCK_NB);
@@ -1618,31 +1638,31 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
        unlock = (cmd == LOCK_UN);
 
        if (!unlock && !(cmd & LOCK_MAND) &&
-           !(filp->f_mode & (FMODE_READ|FMODE_WRITE)))
+           !(f.file->f_mode & (FMODE_READ|FMODE_WRITE)))
                goto out_putf;
 
-       error = flock_make_lock(filp, &lock, cmd);
+       error = flock_make_lock(f.file, &lock, cmd);
        if (error)
                goto out_putf;
        if (can_sleep)
                lock->fl_flags |= FL_SLEEP;
 
-       error = security_file_lock(filp, lock->fl_type);
+       error = security_file_lock(f.file, lock->fl_type);
        if (error)
                goto out_free;
 
-       if (filp->f_op && filp->f_op->flock)
-               error = filp->f_op->flock(filp,
+       if (f.file->f_op && f.file->f_op->flock)
+               error = f.file->f_op->flock(f.file,
                                          (can_sleep) ? F_SETLKW : F_SETLK,
                                          lock);
        else
-               error = flock_lock_file_wait(filp, lock);
+               error = flock_lock_file_wait(f.file, lock);
 
  out_free:
        locks_free_lock(lock);
 
  out_putf:
-       fput(filp);
+       fdput(f);
  out:
        return error;
 }
@@ -1751,10 +1771,10 @@ out:
  * 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
+ * lm_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 FILE_LOCK_DEFERRED, and call ->fl_grant() when the lock
+ * it must return FILE_LOCK_DEFERRED, and call ->lm_grant() when the lock
  * request completes.
  * If the request is for non-blocking lock the file system should return
  * FILE_LOCK_DEFERRED then try to get the lock and call the callback routine
@@ -1764,7 +1784,7 @@ out:
  * 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 FILE_LOCK_DEFERRED
+ * ->lm_grant() before returning to the caller with a FILE_LOCK_DEFERRED
  * return code.
  */
 int vfs_lock_file(struct file *filp, unsigned int cmd, struct file_lock *fl, struct file_lock *conf)
@@ -1822,7 +1842,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
        if (copy_from_user(&flock, l, sizeof(flock)))
                goto out;
 
-       inode = filp->f_path.dentry->d_inode;
+       inode = file_inode(filp);
 
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
@@ -1940,7 +1960,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
        if (copy_from_user(&flock, l, sizeof(flock)))
                goto out;
 
-       inode = filp->f_path.dentry->d_inode;
+       inode = file_inode(filp);
 
        /* Don't allow mandatory locks on files that may be memory mapped
         * and shared.
@@ -2009,7 +2029,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
         * posix_lock_file().  Another process could be setting a lock on this
         * file at the same time, but we wouldn't remove that lock anyway.
         */
-       if (!filp->f_path.dentry->d_inode->i_flock)
+       if (!file_inode(filp)->i_flock)
                return;
 
        lock.fl_type = F_UNLCK;
@@ -2035,7 +2055,7 @@ EXPORT_SYMBOL(locks_remove_posix);
  */
 void locks_remove_flock(struct file *filp)
 {
-       struct inode * inode = filp->f_path.dentry->d_inode;
+       struct inode * inode = file_inode(filp);
        struct file_lock *fl;
        struct file_lock **before;
 
@@ -2131,7 +2151,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                fl_pid = fl->fl_pid;
 
        if (fl->fl_file != NULL)
-               inode = fl->fl_file->f_path.dentry->d_inode;
+               inode = file_inode(fl->fl_file);
 
        seq_printf(f, "%lld:%s ", id, pfx);
        if (IS_POSIX(fl)) {
@@ -2147,7 +2167,7 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                }
        } else if (IS_LEASE(fl)) {
                seq_printf(f, "LEASE  ");
-               if (fl->fl_type & F_INPROGRESS)
+               if (lease_breaking(fl))
                        seq_printf(f, "BREAKING  ");
                else if (fl->fl_file)
                        seq_printf(f, "ACTIVE    ");
@@ -2163,9 +2183,9 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                               : (fl->fl_type & LOCK_WRITE) ? "WRITE" : "NONE ");
        } else {
                seq_printf(f, "%s ",
-                              (fl->fl_type & F_INPROGRESS)
-                              ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ "
-                              : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ ");
+                              (lease_breaking(fl))
+                              ? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ "
+                              : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ ");
        }
        if (inode) {
 #ifdef WE_CAN_BREAK_LSLK_NOW
@@ -2333,8 +2353,8 @@ EXPORT_SYMBOL(lock_may_write);
 static int __init filelock_init(void)
 {
        filelock_cache = kmem_cache_create("file_lock_cache",
-                       sizeof(struct file_lock), 0, SLAB_PANIC,
-                       init_once);
+                       sizeof(struct file_lock), 0, SLAB_PANIC, NULL);
+
        return 0;
 }