Merge tag 'locks-v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton...
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 6 Sep 2017 20:43:26 +0000 (13:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 6 Sep 2017 20:43:26 +0000 (13:43 -0700)
Pull file locking updates from Jeff Layton:
 "This pile just has a few file locking fixes from Ben Coddington. There
  are a couple of cleanup patches + an attempt to bring sanity to the
  l_pid value that is reported back to userland on an F_GETLK request.

  After a few gyrations, he came up with a way for filesystems to
  communicate to the VFS layer code whether the pid should be translated
  according to the namespace or presented as-is to userland"

* tag 'locks-v4.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/jlayton/linux:
  locks: restore a warn for leaked locks on close
  fs/locks: Remove fl_nspid and use fs-specific l_pid for remote locks
  fs/locks: Use allocation rather than the stack in fcntl_getlk()

drivers/staging/lustre/lustre/ldlm/ldlm_flock.c
fs/9p/vfs_file.c
fs/ceph/locks.c
fs/cifs/cifssmb.c
fs/dlm/plock.c
fs/fuse/file.c
fs/locks.c
include/linux/fs.h

index d571b8b..cb826e9 100644 (file)
@@ -596,7 +596,7 @@ granted:
                default:
                        getlk->fl_type = F_UNLCK;
                }
-               getlk->fl_pid = (pid_t)lock->l_policy_data.l_flock.pid;
+               getlk->fl_pid = -(pid_t)lock->l_policy_data.l_flock.pid;
                getlk->fl_start = (loff_t)lock->l_policy_data.l_flock.start;
                getlk->fl_end = (loff_t)lock->l_policy_data.l_flock.end;
        } else {
index 3de3b4a..43c242e 100644 (file)
@@ -288,7 +288,7 @@ static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
                        fl->fl_end = OFFSET_MAX;
                else
                        fl->fl_end = glock.start + glock.length - 1;
-               fl->fl_pid = glock.proc_id;
+               fl->fl_pid = -glock.proc_id;
        }
        kfree(glock.client_id);
        return res;
index 64ae744..8cd63e8 100644 (file)
@@ -79,7 +79,7 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        err = ceph_mdsc_do_request(mdsc, inode, req);
 
        if (operation == CEPH_MDS_OP_GETFILELOCK) {
-               fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid);
+               fl->fl_pid = -le64_to_cpu(req->r_reply_info.filelock_reply->pid);
                if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
                        fl->fl_type = F_RDLCK;
                else if (CEPH_LOCK_EXCL == req->r_reply_info.filelock_reply->type)
index 72a53bd..118a63e 100644 (file)
@@ -2522,7 +2522,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
                        pLockData->fl_start = le64_to_cpu(parm_data->start);
                        pLockData->fl_end = pLockData->fl_start +
                                        le64_to_cpu(parm_data->length) - 1;
-                       pLockData->fl_pid = le32_to_cpu(parm_data->pid);
+                       pLockData->fl_pid = -le32_to_cpu(parm_data->pid);
                }
        }
 
index d401425..e631b16 100644 (file)
@@ -367,7 +367,7 @@ int dlm_posix_get(dlm_lockspace_t *lockspace, u64 number, struct file *file,
                locks_init_lock(fl);
                fl->fl_type = (op->info.ex) ? F_WRLCK : F_RDLCK;
                fl->fl_flags = FL_POSIX;
-               fl->fl_pid = op->info.pid;
+               fl->fl_pid = -op->info.pid;
                fl->fl_start = op->info.start;
                fl->fl_end = op->info.end;
                rv = 0;
index ab60051..0273029 100644 (file)
@@ -2102,11 +2102,11 @@ static int convert_fuse_file_lock(struct fuse_conn *fc,
                fl->fl_end = ffl->end;
 
                /*
-                * Convert pid into the caller's pid namespace. If the pid
-                * does not map into the namespace fl_pid will get set to 0.
+                * Convert pid into init's pid namespace.  The locks API will
+                * translate it into the caller's pid namespace.
                 */
                rcu_read_lock();
-               fl->fl_pid = pid_vnr(find_pid_ns(ffl->pid, fc->pid_ns));
+               fl->fl_pid = pid_nr_ns(find_pid_ns(ffl->pid, fc->pid_ns), &init_pid_ns);
                rcu_read_unlock();
                break;
 
index afefeb4..1bd71c4 100644 (file)
 #define IS_FLOCK(fl)   (fl->fl_flags & FL_FLOCK)
 #define IS_LEASE(fl)   (fl->fl_flags & (FL_LEASE|FL_DELEG|FL_LAYOUT))
 #define IS_OFDLCK(fl)  (fl->fl_flags & FL_OFDLCK)
+#define IS_REMOTELCK(fl)       (fl->fl_pid <= 0)
 
 static inline bool is_remote_lock(struct file *filp)
 {
@@ -270,6 +271,22 @@ locks_check_ctx_lists(struct inode *inode)
        }
 }
 
+static void
+locks_check_ctx_file_list(struct file *filp, struct list_head *list,
+                               char *list_type)
+{
+       struct file_lock *fl;
+       struct inode *inode = locks_inode(filp);
+
+       list_for_each_entry(fl, list, fl_list)
+               if (fl->fl_file == filp)
+                       pr_warn("Leaked %s lock on dev=0x%x:0x%x ino=0x%lx "
+                               " fl_owner=%p fl_flags=0x%x fl_type=0x%x fl_pid=%u\n",
+                               list_type, MAJOR(inode->i_sb->s_dev),
+                               MINOR(inode->i_sb->s_dev), inode->i_ino,
+                               fl->fl_owner, fl->fl_flags, fl->fl_type, fl->fl_pid);
+}
+
 void
 locks_free_lock_context(struct inode *inode)
 {
@@ -733,7 +750,6 @@ static void locks_wake_up_blocks(struct file_lock *blocker)
 static void
 locks_insert_lock_ctx(struct file_lock *fl, struct list_head *before)
 {
-       fl->fl_nspid = get_pid(task_tgid(current));
        list_add_tail(&fl->fl_list, before);
        locks_insert_global_locks(fl);
 }
@@ -743,10 +759,6 @@ locks_unlink_lock_ctx(struct file_lock *fl)
 {
        locks_delete_global_locks(fl);
        list_del_init(&fl->fl_list);
-       if (fl->fl_nspid) {
-               put_pid(fl->fl_nspid);
-               fl->fl_nspid = NULL;
-       }
        locks_wake_up_blocks(fl);
 }
 
@@ -823,8 +835,6 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
        list_for_each_entry(cfl, &ctx->flc_posix, fl_list) {
                if (posix_locks_conflict(fl, cfl)) {
                        locks_copy_conflock(fl, cfl);
-                       if (cfl->fl_nspid)
-                               fl->fl_pid = pid_vnr(cfl->fl_nspid);
                        goto out;
                }
        }
@@ -2048,9 +2058,33 @@ int vfs_test_lock(struct file *filp, struct file_lock *fl)
 }
 EXPORT_SYMBOL_GPL(vfs_test_lock);
 
+/**
+ * locks_translate_pid - translate a file_lock's fl_pid number into a namespace
+ * @fl: The file_lock who's fl_pid should be translated
+ * @ns: The namespace into which the pid should be translated
+ *
+ * Used to tranlate a fl_pid into a namespace virtual pid number
+ */
+static pid_t locks_translate_pid(struct file_lock *fl, struct pid_namespace *ns)
+{
+       pid_t vnr;
+       struct pid *pid;
+
+       if (IS_OFDLCK(fl))
+               return -1;
+       if (IS_REMOTELCK(fl))
+               return fl->fl_pid;
+
+       rcu_read_lock();
+       pid = find_pid_ns(fl->fl_pid, &init_pid_ns);
+       vnr = pid_nr_ns(pid, ns);
+       rcu_read_unlock();
+       return vnr;
+}
+
 static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
 {
-       flock->l_pid = IS_OFDLCK(fl) ? -1 : fl->fl_pid;
+       flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
 #if BITS_PER_LONG == 32
        /*
         * Make sure we can represent the posix lock via
@@ -2072,7 +2106,7 @@ static int posix_lock_to_flock(struct flock *flock, struct file_lock *fl)
 #if BITS_PER_LONG == 32
 static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
 {
-       flock->l_pid = IS_OFDLCK(fl) ? -1 : fl->fl_pid;
+       flock->l_pid = locks_translate_pid(fl, task_active_pid_ns(current));
        flock->l_start = fl->fl_start;
        flock->l_len = fl->fl_end == OFFSET_MAX ? 0 :
                fl->fl_end - fl->fl_start + 1;
@@ -2086,14 +2120,17 @@ static void posix_lock_to_flock64(struct flock64 *flock, struct file_lock *fl)
  */
 int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
 {
-       struct file_lock file_lock;
+       struct file_lock *fl;
        int error;
 
+       fl = locks_alloc_lock();
+       if (fl == NULL)
+               return -ENOMEM;
        error = -EINVAL;
        if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
                goto out;
 
-       error = flock_to_posix_lock(filp, &file_lock, flock);
+       error = flock_to_posix_lock(filp, fl, flock);
        if (error)
                goto out;
 
@@ -2103,23 +2140,22 @@ int fcntl_getlk(struct file *filp, unsigned int cmd, struct flock *flock)
                        goto out;
 
                cmd = F_GETLK;
-               file_lock.fl_flags |= FL_OFDLCK;
-               file_lock.fl_owner = filp;
+               fl->fl_flags |= FL_OFDLCK;
+               fl->fl_owner = filp;
        }
 
-       error = vfs_test_lock(filp, &file_lock);
+       error = vfs_test_lock(filp, fl);
        if (error)
                goto out;
  
-       flock->l_type = file_lock.fl_type;
-       if (file_lock.fl_type != F_UNLCK) {
-               error = posix_lock_to_flock(flock, &file_lock);
+       flock->l_type = fl->fl_type;
+       if (fl->fl_type != F_UNLCK) {
+               error = posix_lock_to_flock(flock, fl);
                if (error)
-                       goto rel_priv;
+                       goto out;
        }
-rel_priv:
-       locks_release_private(&file_lock);
 out:
+       locks_free_lock(fl);
        return error;
 }
 
@@ -2298,14 +2334,18 @@ out:
  */
 int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
 {
-       struct file_lock file_lock;
+       struct file_lock *fl;
        int error;
 
+       fl = locks_alloc_lock();
+       if (fl == NULL)
+               return -ENOMEM;
+
        error = -EINVAL;
        if (flock->l_type != F_RDLCK && flock->l_type != F_WRLCK)
                goto out;
 
-       error = flock64_to_posix_lock(filp, &file_lock, flock);
+       error = flock64_to_posix_lock(filp, fl, flock);
        if (error)
                goto out;
 
@@ -2315,20 +2355,20 @@ int fcntl_getlk64(struct file *filp, unsigned int cmd, struct flock64 *flock)
                        goto out;
 
                cmd = F_GETLK64;
-               file_lock.fl_flags |= FL_OFDLCK;
-               file_lock.fl_owner = filp;
+               fl->fl_flags |= FL_OFDLCK;
+               fl->fl_owner = filp;
        }
 
-       error = vfs_test_lock(filp, &file_lock);
+       error = vfs_test_lock(filp, fl);
        if (error)
                goto out;
 
-       flock->l_type = file_lock.fl_type;
-       if (file_lock.fl_type != F_UNLCK)
-               posix_lock_to_flock64(flock, &file_lock);
+       flock->l_type = fl->fl_type;
+       if (fl->fl_type != F_UNLCK)
+               posix_lock_to_flock64(flock, fl);
 
-       locks_release_private(&file_lock);
 out:
+       locks_free_lock(fl);
        return error;
 }
 
@@ -2525,6 +2565,12 @@ void locks_remove_file(struct file *filp)
 
        /* remove any leases */
        locks_remove_lease(filp, ctx);
+
+       spin_lock(&ctx->flc_lock);
+       locks_check_ctx_file_list(filp, &ctx->flc_posix, "POSIX");
+       locks_check_ctx_file_list(filp, &ctx->flc_flock, "FLOCK");
+       locks_check_ctx_file_list(filp, &ctx->flc_lease, "LEASE");
+       spin_unlock(&ctx->flc_lock);
 }
 
 /**
@@ -2578,22 +2624,16 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,
 {
        struct inode *inode = NULL;
        unsigned int fl_pid;
+       struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
 
-       if (fl->fl_nspid) {
-               struct pid_namespace *proc_pidns = file_inode(f->file)->i_sb->s_fs_info;
-
-               /* Don't let fl_pid change based on who is reading the file */
-               fl_pid = pid_nr_ns(fl->fl_nspid, proc_pidns);
-
-               /*
-                * If there isn't a fl_pid don't display who is waiting on
-                * the lock if we are called from locks_show, or if we are
-                * called from __show_fd_info - skip lock entirely
-                */
-               if (fl_pid == 0)
-                       return;
-       } else
-               fl_pid = fl->fl_pid;
+       fl_pid = locks_translate_pid(fl, proc_pidns);
+       /*
+        * If there isn't a fl_pid don't display who is waiting on
+        * the lock if we are called from locks_show, or if we are
+        * called from __show_fd_info - skip lock entirely
+        */
+       if (fl_pid == 0)
+               return;
 
        if (fl->fl_file != NULL)
                inode = locks_inode(fl->fl_file);
@@ -2668,7 +2708,7 @@ static int locks_show(struct seq_file *f, void *v)
 
        fl = hlist_entry(v, struct file_lock, fl_link);
 
-       if (fl->fl_nspid && !pid_nr_ns(fl->fl_nspid, proc_pidns))
+       if (locks_translate_pid(fl, proc_pidns) == 0)
                return 0;
 
        lock_get_status(f, fl, iter->li_pos, "");
index 495b5c2..0a51a8b 100644 (file)
@@ -1002,7 +1002,6 @@ struct file_lock {
        unsigned char fl_type;
        unsigned int fl_pid;
        int fl_link_cpu;                /* what cpu's list is this on? */
-       struct pid *fl_nspid;
        wait_queue_head_t fl_wait;
        struct file *fl_file;
        loff_t fl_start;