OSDN Git Service

Merge tag 'threads-v5.8' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner...
[tomoyo/tomoyo-test1.git] / fs / namespace.c
index be99e80..6d499ab 100644 (file)
@@ -648,6 +648,21 @@ struct vfsmount *lookup_mnt(const struct path *path)
        return m;
 }
 
+static inline void lock_ns_list(struct mnt_namespace *ns)
+{
+       spin_lock(&ns->ns_lock);
+}
+
+static inline void unlock_ns_list(struct mnt_namespace *ns)
+{
+       spin_unlock(&ns->ns_lock);
+}
+
+static inline bool mnt_is_cursor(struct mount *mnt)
+{
+       return mnt->mnt.mnt_flags & MNT_CURSOR;
+}
+
 /*
  * __is_local_mountpoint - Test to see if dentry is a mountpoint in the
  *                         current mount namespace.
@@ -673,11 +688,15 @@ bool __is_local_mountpoint(struct dentry *dentry)
                goto out;
 
        down_read(&namespace_sem);
+       lock_ns_list(ns);
        list_for_each_entry(mnt, &ns->list, mnt_list) {
+               if (mnt_is_cursor(mnt))
+                       continue;
                is_covered = (mnt->mnt_mountpoint == dentry);
                if (is_covered)
                        break;
        }
+       unlock_ns_list(ns);
        up_read(&namespace_sem);
 out:
        return is_covered;
@@ -1245,46 +1264,71 @@ struct vfsmount *mnt_clone_internal(const struct path *path)
 }
 
 #ifdef CONFIG_PROC_FS
+static struct mount *mnt_list_next(struct mnt_namespace *ns,
+                                  struct list_head *p)
+{
+       struct mount *mnt, *ret = NULL;
+
+       lock_ns_list(ns);
+       list_for_each_continue(p, &ns->list) {
+               mnt = list_entry(p, typeof(*mnt), mnt_list);
+               if (!mnt_is_cursor(mnt)) {
+                       ret = mnt;
+                       break;
+               }
+       }
+       unlock_ns_list(ns);
+
+       return ret;
+}
+
 /* iterator; we want it to have access to namespace_sem, thus here... */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
        struct proc_mounts *p = m->private;
+       struct list_head *prev;
 
        down_read(&namespace_sem);
-       if (p->cached_event == p->ns->event) {
-               void *v = p->cached_mount;
-               if (*pos == p->cached_index)
-                       return v;
-               if (*pos == p->cached_index + 1) {
-                       v = seq_list_next(v, &p->ns->list, &p->cached_index);
-                       return p->cached_mount = v;
-               }
+       if (!*pos) {
+               prev = &p->ns->list;
+       } else {
+               prev = &p->cursor.mnt_list;
+
+               /* Read after we'd reached the end? */
+               if (list_empty(prev))
+                       return NULL;
        }
 
-       p->cached_event = p->ns->event;
-       p->cached_mount = seq_list_start(&p->ns->list, *pos);
-       p->cached_index = *pos;
-       return p->cached_mount;
+       return mnt_list_next(p->ns, prev);
 }
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
        struct proc_mounts *p = m->private;
+       struct mount *mnt = v;
 
-       p->cached_mount = seq_list_next(v, &p->ns->list, pos);
-       p->cached_index = *pos;
-       return p->cached_mount;
+       ++*pos;
+       return mnt_list_next(p->ns, &mnt->mnt_list);
 }
 
 static void m_stop(struct seq_file *m, void *v)
 {
+       struct proc_mounts *p = m->private;
+       struct mount *mnt = v;
+
+       lock_ns_list(p->ns);
+       if (mnt)
+               list_move_tail(&p->cursor.mnt_list, &mnt->mnt_list);
+       else
+               list_del_init(&p->cursor.mnt_list);
+       unlock_ns_list(p->ns);
        up_read(&namespace_sem);
 }
 
 static int m_show(struct seq_file *m, void *v)
 {
        struct proc_mounts *p = m->private;
-       struct mount *r = list_entry(v, struct mount, mnt_list);
+       struct mount *r = v;
        return p->show(m, &r->mnt);
 }
 
@@ -1294,6 +1338,15 @@ const struct seq_operations mounts_op = {
        .stop   = m_stop,
        .show   = m_show,
 };
+
+void mnt_cursor_del(struct mnt_namespace *ns, struct mount *cursor)
+{
+       down_read(&namespace_sem);
+       lock_ns_list(ns);
+       list_del(&cursor->mnt_list);
+       unlock_ns_list(ns);
+       up_read(&namespace_sem);
+}
 #endif  /* CONFIG_PROC_FS */
 
 /**
@@ -3207,6 +3260,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
        atomic_set(&new_ns->count, 1);
        INIT_LIST_HEAD(&new_ns->list);
        init_waitqueue_head(&new_ns->poll);
+       spin_lock_init(&new_ns->ns_lock);
        new_ns->user_ns = get_user_ns(user_ns);
        new_ns->ucounts = ucounts;
        return new_ns;
@@ -3600,7 +3654,7 @@ EXPORT_SYMBOL(path_is_under);
  * file system may be mounted on put_old. After all, new_root is a mountpoint.
  *
  * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem.
- * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives
+ * See Documentation/filesystems/ramfs-rootfs-initramfs.rst for alternatives
  * in this situation.
  *
  * Notes:
@@ -3847,10 +3901,14 @@ static bool mnt_already_visible(struct mnt_namespace *ns,
        bool visible = false;
 
        down_read(&namespace_sem);
+       lock_ns_list(ns);
        list_for_each_entry(mnt, &ns->list, mnt_list) {
                struct mount *child;
                int mnt_flags;
 
+               if (mnt_is_cursor(mnt))
+                       continue;
+
                if (mnt->mnt.mnt_sb->s_type != sb->s_type)
                        continue;
 
@@ -3898,6 +3956,7 @@ static bool mnt_already_visible(struct mnt_namespace *ns,
        next:   ;
        }
 found:
+       unlock_ns_list(ns);
        up_read(&namespace_sem);
        return visible;
 }