[patch 5/7] vfs: mountinfo: allow using process root
[firefly-linux-kernel-4.4.55.git] / fs / proc / base.c
index 7313c62e3e9dd47f103bd1cf5e0e32f3e3356356..a04b3db7a296f8017913adbbbada28569241e587 100644 (file)
@@ -502,17 +502,14 @@ static const struct inode_operations proc_def_inode_operations = {
        .setattr        = proc_setattr,
 };
 
-extern const struct seq_operations mounts_op;
-struct proc_mounts {
-       struct seq_file m;
-       int event;
-};
-
-static int mounts_open(struct inode *inode, struct file *file)
+static int mounts_open_common(struct inode *inode, struct file *file,
+                             const struct seq_operations *op)
 {
        struct task_struct *task = get_proc_task(inode);
        struct nsproxy *nsp;
        struct mnt_namespace *ns = NULL;
+       struct fs_struct *fs = NULL;
+       struct path root;
        struct proc_mounts *p;
        int ret = -EINVAL;
 
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *inode, struct file *file)
                                get_mnt_ns(ns);
                }
                rcu_read_unlock();
-
+               if (ns)
+                       fs = get_fs_struct(task);
                put_task_struct(task);
        }
 
-       if (ns) {
-               ret = -ENOMEM;
-               p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
-               if (p) {
-                       file->private_data = &p->m;
-                       ret = seq_open(file, &mounts_op);
-                       if (!ret) {
-                               p->m.private = ns;
-                               p->event = ns->event;
-                               return 0;
-                       }
-                       kfree(p);
-               }
-               put_mnt_ns(ns);
-       }
+       if (!ns)
+               goto err;
+       if (!fs)
+               goto err_put_ns;
+
+       read_lock(&fs->lock);
+       root = fs->root;
+       path_get(&root);
+       read_unlock(&fs->lock);
+       put_fs_struct(fs);
+
+       ret = -ENOMEM;
+       p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
+       if (!p)
+               goto err_put_path;
+
+       file->private_data = &p->m;
+       ret = seq_open(file, op);
+       if (ret)
+               goto err_free;
+
+       p->m.private = p;
+       p->ns = ns;
+       p->root = root;
+       p->event = ns->event;
+
+       return 0;
+
+ err_free:
+       kfree(p);
+ err_put_path:
+       path_put(&root);
+ err_put_ns:
+       put_mnt_ns(ns);
+ err:
        return ret;
 }
 
 static int mounts_release(struct inode *inode, struct file *file)
 {
-       struct seq_file *m = file->private_data;
-       struct mnt_namespace *ns = m->private;
-       put_mnt_ns(ns);
+       struct proc_mounts *p = file->private_data;
+       path_put(&p->root);
+       put_mnt_ns(p->ns);
        return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
        struct proc_mounts *p = file->private_data;
-       struct mnt_namespace *ns = p->m.private;
+       struct mnt_namespace *ns = p->ns;
        unsigned res = 0;
 
        poll_wait(file, &ns->poll, wait);
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file *file, poll_table *wait)
        return res;
 }
 
+static int mounts_open(struct inode *inode, struct file *file)
+{
+       return mounts_open_common(inode, file, &mounts_op);
+}
+
 static const struct file_operations proc_mounts_operations = {
        .open           = mounts_open,
        .read           = seq_read,
@@ -581,38 +604,9 @@ static const struct file_operations proc_mounts_operations = {
        .poll           = mounts_poll,
 };
 
-extern const struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-       int ret = seq_open(file, &mountstats_op);
-
-       if (!ret) {
-               struct seq_file *m = file->private_data;
-               struct nsproxy *nsp;
-               struct mnt_namespace *mnt_ns = NULL;
-               struct task_struct *task = get_proc_task(inode);
-
-               if (task) {
-                       rcu_read_lock();
-                       nsp = task_nsproxy(task);
-                       if (nsp) {
-                               mnt_ns = nsp->mnt_ns;
-                               if (mnt_ns)
-                                       get_mnt_ns(mnt_ns);
-                       }
-                       rcu_read_unlock();
-
-                       put_task_struct(task);
-               }
-
-               if (mnt_ns)
-                       m->private = mnt_ns;
-               else {
-                       seq_release(inode, file);
-                       ret = -EINVAL;
-               }
-       }
-       return ret;
+       return mounts_open_common(inode, file, &mountstats_op);
 }
 
 static const struct file_operations proc_mountstats_operations = {