Merge tag 'iwlwifi-for-kalle-2015-03-30' of https://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / fs / locks.c
index 4d0d411..4753218 100644 (file)
 
 #define IS_POSIX(fl)   (fl->fl_flags & FL_POSIX)
 #define IS_FLOCK(fl)   (fl->fl_flags & FL_FLOCK)
-#define IS_LEASE(fl)   (fl->fl_flags & (FL_LEASE|FL_DELEG))
+#define IS_LEASE(fl)   (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
 #define IS_OFDLCK(fl)  (fl->fl_flags & FL_OFDLCK)
 
 static bool lease_breaking(struct file_lock *fl)
@@ -1371,6 +1371,8 @@ static void time_out_leases(struct inode *inode, struct list_head *dispose)
 
 static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
 {
+       if ((breaker->fl_flags & FL_LAYOUT) != (lease->fl_flags & FL_LAYOUT))
+               return false;
        if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE))
                return false;
        return locks_conflict(breaker, lease);
@@ -1594,11 +1596,14 @@ int fcntl_getlease(struct file *filp)
  * conflict with the lease we're trying to set.
  */
 static int
-check_conflicting_open(const struct dentry *dentry, const long arg)
+check_conflicting_open(const struct dentry *dentry, const long arg, int flags)
 {
        int ret = 0;
        struct inode *inode = dentry->d_inode;
 
+       if (flags & FL_LAYOUT)
+               return 0;
+
        if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
                return -EAGAIN;
 
@@ -1647,7 +1652,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
 
        spin_lock(&ctx->flc_lock);
        time_out_leases(inode, &dispose);
-       error = check_conflicting_open(dentry, arg);
+       error = check_conflicting_open(dentry, arg, lease->fl_flags);
        if (error)
                goto out;
 
@@ -1661,7 +1666,8 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
         */
        error = -EAGAIN;
        list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-               if (fl->fl_file == filp) {
+               if (fl->fl_file == filp &&
+                   fl->fl_owner == lease->fl_owner) {
                        my_fl = fl;
                        continue;
                }
@@ -1702,7 +1708,7 @@ generic_add_lease(struct file *filp, long arg, struct file_lock **flp, void **pr
         * precedes these checks.
         */
        smp_mb();
-       error = check_conflicting_open(dentry, arg);
+       error = check_conflicting_open(dentry, arg, lease->fl_flags);
        if (error) {
                locks_unlink_lock_ctx(lease, &ctx->flc_lease_cnt);
                goto out;
@@ -1721,7 +1727,7 @@ out:
        return error;
 }
 
-static int generic_delete_lease(struct file *filp)
+static int generic_delete_lease(struct file *filp, void *owner)
 {
        int error = -EAGAIN;
        struct file_lock *fl, *victim = NULL;
@@ -1737,7 +1743,8 @@ static int generic_delete_lease(struct file *filp)
 
        spin_lock(&ctx->flc_lock);
        list_for_each_entry(fl, &ctx->flc_lease, fl_list) {
-               if (fl->fl_file == filp) {
+               if (fl->fl_file == filp &&
+                   fl->fl_owner == owner) {
                        victim = fl;
                        break;
                }
@@ -1778,13 +1785,14 @@ int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
 
        switch (arg) {
        case F_UNLCK:
-               return generic_delete_lease(filp);
+               return generic_delete_lease(filp, *priv);
        case F_RDLCK:
        case F_WRLCK:
                if (!(*flp)->fl_lmops->lm_break) {
                        WARN_ON_ONCE(1);
                        return -ENOLCK;
                }
+
                return generic_add_lease(filp, arg, flp, priv);
        default:
                return -EINVAL;
@@ -1857,7 +1865,7 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
 int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 {
        if (arg == F_UNLCK)
-               return vfs_setlease(filp, F_UNLCK, NULL, NULL);
+               return vfs_setlease(filp, F_UNLCK, NULL, (void **)&filp);
        return do_fcntl_add_lease(fd, filp, arg);
 }