These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / fs / locks.c
index 653faab..6333263 100644 (file)
@@ -205,28 +205,32 @@ static struct kmem_cache *filelock_cache __read_mostly;
 static struct file_lock_context *
 locks_get_lock_context(struct inode *inode, int type)
 {
-       struct file_lock_context *new;
+       struct file_lock_context *ctx;
 
-       if (likely(inode->i_flctx) || type == F_UNLCK)
+       /* paired with cmpxchg() below */
+       ctx = smp_load_acquire(&inode->i_flctx);
+       if (likely(ctx) || type == F_UNLCK)
                goto out;
 
-       new = kmem_cache_alloc(flctx_cache, GFP_KERNEL);
-       if (!new)
+       ctx = kmem_cache_alloc(flctx_cache, GFP_KERNEL);
+       if (!ctx)
                goto out;
 
-       spin_lock_init(&new->flc_lock);
-       INIT_LIST_HEAD(&new->flc_flock);
-       INIT_LIST_HEAD(&new->flc_posix);
-       INIT_LIST_HEAD(&new->flc_lease);
+       spin_lock_init(&ctx->flc_lock);
+       INIT_LIST_HEAD(&ctx->flc_flock);
+       INIT_LIST_HEAD(&ctx->flc_posix);
+       INIT_LIST_HEAD(&ctx->flc_lease);
 
        /*
         * Assign the pointer if it's not already assigned. If it is, then
         * free the context we just allocated.
         */
-       if (cmpxchg(&inode->i_flctx, NULL, new))
-               kmem_cache_free(flctx_cache, new);
+       if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
+               kmem_cache_free(flctx_cache, ctx);
+               ctx = smp_load_acquire(&inode->i_flctx);
+       }
 out:
-       return inode->i_flctx;
+       return ctx;
 }
 
 void
@@ -762,7 +766,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
        struct file_lock_context *ctx;
        struct inode *inode = file_inode(filp);
 
-       ctx = inode->i_flctx;
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (!ctx || list_empty_careful(&ctx->flc_posix)) {
                fl->fl_type = F_UNLCK;
                return;
@@ -862,12 +866,11 @@ static int posix_locks_deadlock(struct file_lock *caller_fl,
  * whether or not a lock was successfully freed by testing the return
  * value for -ENOENT.
  */
-static int flock_lock_file(struct file *filp, struct file_lock *request)
+static int flock_lock_inode(struct inode *inode, struct file_lock *request)
 {
        struct file_lock *new_fl = NULL;
        struct file_lock *fl;
        struct file_lock_context *ctx;
-       struct inode *inode = file_inode(filp);
        int error = 0;
        bool found = false;
        LIST_HEAD(dispose);
@@ -890,7 +893,7 @@ static int flock_lock_file(struct file *filp, struct file_lock *request)
                goto find_conflict;
 
        list_for_each_entry(fl, &ctx->flc_flock, fl_list) {
-               if (filp != fl->fl_file)
+               if (request->fl_file != fl->fl_file)
                        continue;
                if (request->fl_type == fl->fl_type)
                        goto out;
@@ -1164,20 +1167,18 @@ int posix_lock_file(struct file *filp, struct file_lock *fl,
 EXPORT_SYMBOL(posix_lock_file);
 
 /**
- * posix_lock_file_wait - Apply a POSIX-style lock to a file
- * @filp: The file to apply the lock to
+ * posix_lock_inode_wait - Apply a POSIX-style lock to a file
+ * @inode: inode of file to which lock request should be applied
  * @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
+ * Apply a POSIX style lock request to an inode.
  */
-int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
+static int posix_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 {
        int error;
        might_sleep ();
        for (;;) {
-               error = posix_lock_file(filp, fl, NULL);
+               error = __posix_lock_file(inode, fl, NULL);
                if (error != FILE_LOCK_DEFERRED)
                        break;
                error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1189,7 +1190,6 @@ int posix_lock_file_wait(struct file *filp, struct file_lock *fl)
        }
        return error;
 }
-EXPORT_SYMBOL(posix_lock_file_wait);
 
 /**
  * locks_mandatory_locked - Check for an active lock
@@ -1205,7 +1205,7 @@ int locks_mandatory_locked(struct file *file)
        struct file_lock_context *ctx;
        struct file_lock *fl;
 
-       ctx = inode->i_flctx;
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (!ctx || list_empty_careful(&ctx->flc_posix))
                return 0;
 
@@ -1390,7 +1390,7 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker)
 int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
 {
        int error = 0;
-       struct file_lock_context *ctx = inode->i_flctx;
+       struct file_lock_context *ctx;
        struct file_lock *new_fl, *fl, *tmp;
        unsigned long break_time;
        int want_write = (mode & O_ACCMODE) != O_RDONLY;
@@ -1402,6 +1402,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
        new_fl->fl_flags = type;
 
        /* typically we will check that ctx is non-NULL before calling */
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (!ctx) {
                WARN_ON_ONCE(1);
                return error;
@@ -1496,9 +1497,10 @@ EXPORT_SYMBOL(__break_lease);
 void lease_get_mtime(struct inode *inode, struct timespec *time)
 {
        bool has_lease = false;
-       struct file_lock_context *ctx = inode->i_flctx;
+       struct file_lock_context *ctx;
        struct file_lock *fl;
 
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (ctx && !list_empty_careful(&ctx->flc_lease)) {
                spin_lock(&ctx->flc_lock);
                if (!list_empty(&ctx->flc_lease)) {
@@ -1545,10 +1547,11 @@ int fcntl_getlease(struct file *filp)
 {
        struct file_lock *fl;
        struct inode *inode = file_inode(filp);
-       struct file_lock_context *ctx = inode->i_flctx;
+       struct file_lock_context *ctx;
        int type = F_UNLCK;
        LIST_HEAD(dispose);
 
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (ctx && !list_empty_careful(&ctx->flc_lease)) {
                spin_lock(&ctx->flc_lock);
                time_out_leases(file_inode(filp), &dispose);
@@ -1570,6 +1573,7 @@ int fcntl_getlease(struct file *filp)
  *                         desired lease.
  * @dentry:    dentry to check
  * @arg:       type of lease that we're trying to acquire
+ * @flags:     current lock flags
  *
  * Check to see if there's an existing open fd on this file that would
  * conflict with the lease we're trying to set.
@@ -1712,11 +1716,11 @@ static int generic_delete_lease(struct file *filp, void *owner)
 {
        int error = -EAGAIN;
        struct file_lock *fl, *victim = NULL;
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
-       struct file_lock_context *ctx = inode->i_flctx;
+       struct inode *inode = file_inode(filp);
+       struct file_lock_context *ctx;
        LIST_HEAD(dispose);
 
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (!ctx) {
                trace_generic_delete_lease(inode, NULL);
                return error;
@@ -1752,8 +1756,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
 int generic_setlease(struct file *filp, long arg, struct file_lock **flp,
                        void **priv)
 {
-       struct dentry *dentry = filp->f_path.dentry;
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = file_inode(filp);
        int error;
 
        if ((!uid_eq(current_fsuid(), inode->i_uid)) && !capable(CAP_LEASE))
@@ -1851,18 +1854,18 @@ int fcntl_setlease(unsigned int fd, struct file *filp, long arg)
 }
 
 /**
- * flock_lock_file_wait - Apply a FLOCK-style lock to a file
- * @filp: The file to apply the lock to
+ * flock_lock_inode_wait - Apply a FLOCK-style lock to a file
+ * @inode: inode of the file to apply to
  * @fl: The lock to be applied
  *
- * Add a FLOCK style lock to a file.
+ * Apply a FLOCK style lock request to an inode.
  */
-int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
+static int flock_lock_inode_wait(struct inode *inode, struct file_lock *fl)
 {
        int error;
        might_sleep();
        for (;;) {
-               error = flock_lock_file(filp, fl);
+               error = flock_lock_inode(inode, fl);
                if (error != FILE_LOCK_DEFERRED)
                        break;
                error = wait_event_interruptible(fl->fl_wait, !fl->fl_next);
@@ -1875,7 +1878,29 @@ int flock_lock_file_wait(struct file *filp, struct file_lock *fl)
        return error;
 }
 
-EXPORT_SYMBOL(flock_lock_file_wait);
+/**
+ * locks_lock_inode_wait - Apply a lock to an inode
+ * @inode: inode of the file to apply to
+ * @fl: The lock to be applied
+ *
+ * Apply a POSIX or FLOCK style lock request to an inode.
+ */
+int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl)
+{
+       int res = 0;
+       switch (fl->fl_flags & (FL_POSIX|FL_FLOCK)) {
+               case FL_POSIX:
+                       res = posix_lock_inode_wait(inode, fl);
+                       break;
+               case FL_FLOCK:
+                       res = flock_lock_inode_wait(inode, fl);
+                       break;
+               default:
+                       BUG();
+       }
+       return res;
+}
+EXPORT_SYMBOL(locks_lock_inode_wait);
 
 /**
  *     sys_flock: - flock() system call.
@@ -1933,7 +1958,7 @@ SYSCALL_DEFINE2(flock, unsigned int, fd, unsigned int, cmd)
                                          (can_sleep) ? F_SETLKW : F_SETLK,
                                          lock);
        else
-               error = flock_lock_file_wait(f.file, lock);
+               error = locks_lock_file_wait(f.file, lock);
 
  out_free:
        locks_free_lock(lock);
@@ -2109,7 +2134,7 @@ static int do_lock_file_wait(struct file *filp, unsigned int cmd,
        return error;
 }
 
-/* Ensure that fl->fl_filp has compatible f_mode for F_SETLK calls */
+/* Ensure that fl->fl_file has compatible f_mode for F_SETLK calls */
 static int
 check_fmode_for_setlk(struct file_lock *fl)
 {
@@ -2157,7 +2182,6 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
                goto out;
        }
 
-again:
        error = flock_to_posix_lock(filp, file_lock, &flock);
        if (error)
                goto out;
@@ -2199,19 +2223,22 @@ again:
         * Attempt to detect a close/fcntl race and recover by
         * releasing the lock that was just acquired.
         */
-       /*
-        * we need that spin_lock here - it prevents reordering between
-        * update of i_flctx->flc_posix and check for it done in close().
-        * rcu_read_lock() wouldn't do.
-        */
-       spin_lock(&current->files->file_lock);
-       f = fcheck(fd);
-       spin_unlock(&current->files->file_lock);
-       if (!error && f != filp && flock.l_type != F_UNLCK) {
-               flock.l_type = F_UNLCK;
-               goto again;
+       if (!error && file_lock->fl_type != F_UNLCK) {
+               /*
+                * We need that spin_lock here - it prevents reordering between
+                * update of i_flctx->flc_posix and check for it done in
+                * close(). rcu_read_lock() wouldn't do.
+                */
+               spin_lock(&current->files->file_lock);
+               f = fcheck(fd);
+               spin_unlock(&current->files->file_lock);
+               if (f != filp) {
+                       file_lock->fl_type = F_UNLCK;
+                       error = do_lock_file_wait(filp, cmd, file_lock);
+                       WARN_ON_ONCE(error);
+                       error = -EBADF;
+               }
        }
-
 out:
        locks_free_lock(file_lock);
        return error;
@@ -2297,7 +2324,6 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
                goto out;
        }
 
-again:
        error = flock64_to_posix_lock(filp, file_lock, &flock);
        if (error)
                goto out;
@@ -2339,14 +2365,22 @@ again:
         * Attempt to detect a close/fcntl race and recover by
         * releasing the lock that was just acquired.
         */
-       spin_lock(&current->files->file_lock);
-       f = fcheck(fd);
-       spin_unlock(&current->files->file_lock);
-       if (!error && f != filp && flock.l_type != F_UNLCK) {
-               flock.l_type = F_UNLCK;
-               goto again;
+       if (!error && file_lock->fl_type != F_UNLCK) {
+               /*
+                * We need that spin_lock here - it prevents reordering between
+                * update of i_flctx->flc_posix and check for it done in
+                * close(). rcu_read_lock() wouldn't do.
+                */
+               spin_lock(&current->files->file_lock);
+               f = fcheck(fd);
+               spin_unlock(&current->files->file_lock);
+               if (f != filp) {
+                       file_lock->fl_type = F_UNLCK;
+                       error = do_lock_file_wait(filp, cmd, file_lock);
+                       WARN_ON_ONCE(error);
+                       error = -EBADF;
+               }
        }
-
 out:
        locks_free_lock(file_lock);
        return error;
@@ -2361,13 +2395,14 @@ out:
 void locks_remove_posix(struct file *filp, fl_owner_t owner)
 {
        struct file_lock lock;
-       struct file_lock_context *ctx = file_inode(filp)->i_flctx;
+       struct file_lock_context *ctx;
 
        /*
         * If there are no locks held on this file, we don't need to call
         * 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.
         */
+       ctx =  smp_load_acquire(&file_inode(filp)->i_flctx);
        if (!ctx || list_empty(&ctx->flc_posix))
                return;
 
@@ -2391,7 +2426,7 @@ EXPORT_SYMBOL(locks_remove_posix);
 
 /* The i_flctx must be valid when calling into here */
 static void
-locks_remove_flock(struct file *filp)
+locks_remove_flock(struct file *filp, struct file_lock_context *flctx)
 {
        struct file_lock fl = {
                .fl_owner = filp,
@@ -2401,7 +2436,7 @@ locks_remove_flock(struct file *filp)
                .fl_type = F_UNLCK,
                .fl_end = OFFSET_MAX,
        };
-       struct file_lock_context *flctx = file_inode(filp)->i_flctx;
+       struct inode *inode = file_inode(filp);
 
        if (list_empty(&flctx->flc_flock))
                return;
@@ -2409,7 +2444,7 @@ locks_remove_flock(struct file *filp)
        if (filp->f_op->flock)
                filp->f_op->flock(filp, F_SETLKW, &fl);
        else
-               flock_lock_file(filp, &fl);
+               flock_lock_inode(inode, &fl);
 
        if (fl.fl_ops && fl.fl_ops->fl_release_private)
                fl.fl_ops->fl_release_private(&fl);
@@ -2417,10 +2452,8 @@ locks_remove_flock(struct file *filp)
 
 /* The i_flctx must be valid when calling into here */
 static void
-locks_remove_lease(struct file *filp)
+locks_remove_lease(struct file *filp, struct file_lock_context *ctx)
 {
-       struct inode *inode = file_inode(filp);
-       struct file_lock_context *ctx = inode->i_flctx;
        struct file_lock *fl, *tmp;
        LIST_HEAD(dispose);
 
@@ -2440,17 +2473,20 @@ locks_remove_lease(struct file *filp)
  */
 void locks_remove_file(struct file *filp)
 {
-       if (!file_inode(filp)->i_flctx)
+       struct file_lock_context *ctx;
+
+       ctx = smp_load_acquire(&file_inode(filp)->i_flctx);
+       if (!ctx)
                return;
 
        /* remove any OFD locks */
        locks_remove_posix(filp, filp);
 
        /* remove flock locks */
-       locks_remove_flock(filp);
+       locks_remove_flock(filp, ctx);
 
        /* remove any leases */
-       locks_remove_lease(filp);
+       locks_remove_lease(filp, ctx);
 }
 
 /**
@@ -2617,7 +2653,7 @@ void show_fd_locks(struct seq_file *f,
        struct file_lock_context *ctx;
        int id = 0;
 
-       ctx = inode->i_flctx;
+       ctx = smp_load_acquire(&inode->i_flctx);
        if (!ctx)
                return;