clk: rockchip: change pll rate without a clk-notifier
[cascardo/linux.git] / fs / locks.c
index 717fbc4..bb08857 100644 (file)
@@ -247,6 +247,18 @@ void locks_free_lock(struct file_lock *fl)
 }
 EXPORT_SYMBOL(locks_free_lock);
 
+static void
+locks_dispose_list(struct list_head *dispose)
+{
+       struct file_lock *fl;
+
+       while (!list_empty(dispose)) {
+               fl = list_first_entry(dispose, struct file_lock, fl_block);
+               list_del_init(&fl->fl_block);
+               locks_free_lock(fl);
+       }
+}
+
 void locks_init_lock(struct file_lock *fl)
 {
        memset(fl, 0, sizeof(struct file_lock));
@@ -285,7 +297,8 @@ EXPORT_SYMBOL(__locks_copy_lock);
 
 void locks_copy_lock(struct file_lock *new, struct file_lock *fl)
 {
-       locks_release_private(new);
+       /* "new" must be a freshly-initialized lock */
+       WARN_ON_ONCE(new->fl_ops);
 
        __locks_copy_lock(new, fl);
        new->fl_file = fl->fl_file;
@@ -325,7 +338,7 @@ static int flock_make_lock(struct file *filp, struct file_lock **lock,
                return -ENOMEM;
 
        fl->fl_file = filp;
-       fl->fl_owner = (fl_owner_t)filp;
+       fl->fl_owner = filp;
        fl->fl_pid = current->tgid;
        fl->fl_flags = FL_FLOCK;
        fl->fl_type = type;
@@ -431,7 +444,7 @@ static int lease_init(struct file *filp, long type, struct file_lock *fl)
        if (assign_type(fl, type) != 0)
                return -EINVAL;
 
-       fl->fl_owner = (fl_owner_t)current->files;
+       fl->fl_owner = current->files;
        fl->fl_pid = current->tgid;
 
        fl->fl_file = filp;
@@ -650,12 +663,16 @@ static void locks_unlink_lock(struct file_lock **thisfl_p)
  *
  * Must be called with i_lock held!
  */
-static void locks_delete_lock(struct file_lock **thisfl_p)
+static void locks_delete_lock(struct file_lock **thisfl_p,
+                             struct list_head *dispose)
 {
        struct file_lock *fl = *thisfl_p;
 
        locks_unlink_lock(thisfl_p);
-       locks_free_lock(fl);
+       if (dispose)
+               list_add(&fl->fl_block, dispose);
+       else
+               locks_free_lock(fl);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -811,6 +828,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
        struct inode * inode = file_inode(filp);
        int error = 0;
        int found = 0;
+       LIST_HEAD(dispose);
 
        if (!(request->fl_flags & FL_ACCESS) && (request->fl_type != F_UNLCK)) {
                new_fl = locks_alloc_lock();
@@ -833,7 +851,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                if (request->fl_type == fl->fl_type)
                        goto out;
                found = 1;
-               locks_delete_lock(before);
+               locks_delete_lock(before, &dispose);
                break;
        }
 
@@ -880,6 +898,7 @@ out:
        spin_unlock(&inode->i_lock);
        if (new_fl)
                locks_free_lock(new_fl);
+       locks_dispose_list(&dispose);
        return error;
 }
 
@@ -893,6 +912,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
        struct file_lock **before;
        int error;
        bool added = false;
+       LIST_HEAD(dispose);
 
        /*
         * We may need two file_lock structures for this operation,
@@ -988,7 +1008,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                        else
                                request->fl_end = fl->fl_end;
                        if (added) {
-                               locks_delete_lock(before);
+                               locks_delete_lock(before, &dispose);
                                continue;
                        }
                        request = fl;
@@ -1018,21 +1038,24 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                                 * one (This may happen several times).
                                 */
                                if (added) {
-                                       locks_delete_lock(before);
+                                       locks_delete_lock(before, &dispose);
                                        continue;
                                }
-                               /* Replace the old lock with the new one.
-                                * Wake up anybody waiting for the old one,
-                                * as the change in lock type might satisfy
-                                * their needs.
+                               /*
+                                * Replace the old lock with new_fl, and
+                                * remove the old one. It's safe to do the
+                                * insert here since we know that we won't be
+                                * using new_fl later, and that the lock is
+                                * just replacing an existing lock.
                                 */
-                               locks_wake_up_blocks(fl);
-                               fl->fl_start = request->fl_start;
-                               fl->fl_end = request->fl_end;
-                               fl->fl_type = request->fl_type;
-                               locks_release_private(fl);
-                               locks_copy_private(fl, request);
-                               request = fl;
+                               error = -ENOLCK;
+                               if (!new_fl)
+                                       goto out;
+                               locks_copy_lock(new_fl, request);
+                               request = new_fl;
+                               new_fl = NULL;
+                               locks_delete_lock(before, &dispose);
+                               locks_insert_lock(before, request);
                                added = true;
                        }
                }
@@ -1093,6 +1116,7 @@ static int __posix_lock_file(struct inode *inode, struct file_lock *request, str
                locks_free_lock(new_fl);
        if (new_fl2)
                locks_free_lock(new_fl2);
+       locks_dispose_list(&dispose);
        return error;
 }
 
@@ -1155,7 +1179,6 @@ EXPORT_SYMBOL(posix_lock_file_wait);
 int locks_mandatory_locked(struct file *file)
 {
        struct inode *inode = file_inode(file);
-       fl_owner_t owner = current->files;
        struct file_lock *fl;
 
        /*
@@ -1165,7 +1188,8 @@ int locks_mandatory_locked(struct file *file)
        for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
                if (!IS_POSIX(fl))
                        continue;
-               if (fl->fl_owner != owner && fl->fl_owner != (fl_owner_t)file)
+               if (fl->fl_owner != current->files &&
+                   fl->fl_owner != file)
                        break;
        }
        spin_unlock(&inode->i_lock);
@@ -1205,7 +1229,7 @@ int locks_mandatory_area(int read_write, struct inode *inode,
 
        for (;;) {
                if (filp) {
-                       fl.fl_owner = (fl_owner_t)filp;
+                       fl.fl_owner = filp;
                        fl.fl_flags &= ~FL_SLEEP;
                        error = __posix_lock_file(inode, &fl, NULL);
                        if (!error)
@@ -1268,7 +1292,7 @@ int lease_modify(struct file_lock **before, int arg)
                        printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
                        fl->fl_fasync = NULL;
                }
-               locks_delete_lock(before);
+               locks_delete_lock(before, NULL);
        }
        return 0;
 }
@@ -1595,7 +1619,7 @@ static int generic_add_lease(struct file *filp, long arg, struct file_lock **flp
        smp_mb();
        error = check_conflicting_open(dentry, arg);
        if (error)
-               locks_unlink_lock(flp);
+               locks_unlink_lock(before);
 out:
        if (is_deleg)
                mutex_unlock(&inode->i_mutex);
@@ -1737,13 +1761,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
        ret = fl;
        spin_lock(&inode->i_lock);
        error = __vfs_setlease(filp, arg, &ret);
-       if (error) {
-               spin_unlock(&inode->i_lock);
-               locks_free_lock(fl);
-               goto out_free_fasync;
-       }
-       if (ret != fl)
-               locks_free_lock(fl);
+       if (error)
+               goto out_unlock;
+       if (ret == fl)
+               fl = NULL;
 
        /*
         * fasync_insert_entry() returns the old entry if any.
@@ -1755,9 +1776,10 @@ static int do_fcntl_add_lease(unsigned int fd, struct file *filp, long arg)
                new = NULL;
 
        error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0);
+out_unlock:
        spin_unlock(&inode->i_lock);
-
-out_free_fasync:
+       if (fl)
+               locks_free_lock(fl);
        if (new)
                fasync_free(new);
        return error;
@@ -1948,7 +1970,7 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock __user *l)
 
                cmd = F_GETLK;
                file_lock.fl_flags |= FL_OFDLCK;
-               file_lock.fl_owner = (fl_owner_t)filp;
+               file_lock.fl_owner = filp;
        }
 
        error = vfs_test_lock(filp, &file_lock);
@@ -2103,7 +2125,7 @@ again:
 
                cmd = F_SETLK;
                file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = (fl_owner_t)filp;
+               file_lock->fl_owner = filp;
                break;
        case F_OFD_SETLKW:
                error = -EINVAL;
@@ -2112,7 +2134,7 @@ again:
 
                cmd = F_SETLKW;
                file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = (fl_owner_t)filp;
+               file_lock->fl_owner = filp;
                /* Fallthrough */
        case F_SETLKW:
                file_lock->fl_flags |= FL_SLEEP;
@@ -2170,7 +2192,7 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
 
                cmd = F_GETLK64;
                file_lock.fl_flags |= FL_OFDLCK;
-               file_lock.fl_owner = (fl_owner_t)filp;
+               file_lock.fl_owner = filp;
        }
 
        error = vfs_test_lock(filp, &file_lock);
@@ -2242,7 +2264,7 @@ again:
 
                cmd = F_SETLK64;
                file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = (fl_owner_t)filp;
+               file_lock->fl_owner = filp;
                break;
        case F_OFD_SETLKW:
                error = -EINVAL;
@@ -2251,7 +2273,7 @@ again:
 
                cmd = F_SETLKW64;
                file_lock->fl_flags |= FL_OFDLCK;
-               file_lock->fl_owner = (fl_owner_t)filp;
+               file_lock->fl_owner = filp;
                /* Fallthrough */
        case F_SETLKW64:
                file_lock->fl_flags |= FL_SLEEP;
@@ -2320,15 +2342,16 @@ void locks_remove_file(struct file *filp)
        struct inode * inode = file_inode(filp);
        struct file_lock *fl;
        struct file_lock **before;
+       LIST_HEAD(dispose);
 
        if (!inode->i_flock)
                return;
 
-       locks_remove_posix(filp, (fl_owner_t)filp);
+       locks_remove_posix(filp, filp);
 
        if (filp->f_op->flock) {
                struct file_lock fl = {
-                       .fl_owner = (fl_owner_t)filp,
+                       .fl_owner = filp,
                        .fl_pid = current->tgid,
                        .fl_file = filp,
                        .fl_flags = FL_FLOCK,
@@ -2365,12 +2388,13 @@ void locks_remove_file(struct file *filp)
                                fl->fl_type, fl->fl_flags,
                                fl->fl_start, fl->fl_end);
 
-                       locks_delete_lock(before);
+                       locks_delete_lock(before, &dispose);
                        continue;
                }
                before = &fl->fl_next;
        }
        spin_unlock(&inode->i_lock);
+       locks_dispose_list(&dispose);
 }
 
 /**
@@ -2452,7 +2476,11 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
                        seq_puts(f, "FLOCK  ADVISORY  ");
                }
        } else if (IS_LEASE(fl)) {
-               seq_puts(f, "LEASE  ");
+               if (fl->fl_flags & FL_DELEG)
+                       seq_puts(f, "DELEG  ");
+               else
+                       seq_puts(f, "LEASE  ");
+
                if (lease_breaking(fl))
                        seq_puts(f, "BREAKING  ");
                else if (fl->fl_file)