OSDN Git Service

ipc,namespace: batch free ipc_namespace structures
authorRik van Riel <riel@surriel.com>
Fri, 27 Jan 2023 18:46:51 +0000 (13:46 -0500)
committerAl Viro <viro@zeniv.linux.org.uk>
Sat, 28 Jan 2023 00:08:00 +0000 (19:08 -0500)
Instead of waiting for an RCU grace period between each ipc_namespace
structure that is being freed, wait an RCU grace period for every batch
of ipc_namespace structures.

Thanks to Al Viro for the suggestion of the helper function.

This speeds up the run time of the test case that allocates ipc_namespaces
in a loop from 6 minutes, to a little over 1 second:

real 0m1.192s
user 0m0.038s
sys 0m1.152s

Signed-off-by: Rik van Riel <riel@surriel.com>
Reported-by: Chris Mason <clm@meta.com>
Tested-by: Giuseppe Scrivano <gscrivan@redhat.com>
Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
fs/namespace.c
include/linux/mount.h
ipc/mqueue.c
ipc/namespace.c
ipc/util.h

index ab467ee..1ad4e5a 100644 (file)
@@ -1397,6 +1397,17 @@ struct vfsmount *mntget(struct vfsmount *mnt)
 }
 EXPORT_SYMBOL(mntget);
 
+/*
+ * Make a mount point inaccessible to new lookups.
+ * Because there may still be current users, the caller MUST WAIT
+ * for an RCU grace period before destroying the mount point.
+ */
+void mnt_make_shortterm(struct vfsmount *mnt)
+{
+       if (mnt)
+               real_mount(mnt)->mnt_ns = NULL;
+}
+
 /**
  * path_is_mountpoint() - Check if path is a mount in the current namespace.
  * @path: path to check
@@ -4573,8 +4584,8 @@ EXPORT_SYMBOL_GPL(kern_mount);
 void kern_unmount(struct vfsmount *mnt)
 {
        /* release long term mount so mount point can be released */
-       if (!IS_ERR_OR_NULL(mnt)) {
-               real_mount(mnt)->mnt_ns = NULL;
+       if (!IS_ERR(mnt)) {
+               mnt_make_shortterm(mnt);
                synchronize_rcu();      /* yecchhh... */
                mntput(mnt);
        }
@@ -4586,8 +4597,7 @@ void kern_unmount_array(struct vfsmount *mnt[], unsigned int num)
        unsigned int i;
 
        for (i = 0; i < num; i++)
-               if (mnt[i])
-                       real_mount(mnt[i])->mnt_ns = NULL;
+               mnt_make_shortterm(mnt[i]);
        synchronize_rcu_expedited();
        for (i = 0; i < num; i++)
                mntput(mnt[i]);
index 6247599..ec55a03 100644 (file)
@@ -88,6 +88,7 @@ extern void mnt_drop_write(struct vfsmount *mnt);
 extern void mnt_drop_write_file(struct file *file);
 extern void mntput(struct vfsmount *mnt);
 extern struct vfsmount *mntget(struct vfsmount *mnt);
+extern void mnt_make_shortterm(struct vfsmount *mnt);
 extern struct vfsmount *mnt_clone_internal(const struct path *path);
 extern bool __mnt_is_readonly(struct vfsmount *mnt);
 extern bool mnt_may_suid(struct vfsmount *mnt);
index d09aa1c..6c5bf7c 100644 (file)
@@ -1709,11 +1709,6 @@ void mq_clear_sbinfo(struct ipc_namespace *ns)
        ns->mq_mnt->mnt_sb->s_fs_info = NULL;
 }
 
-void mq_put_mnt(struct ipc_namespace *ns)
-{
-       kern_unmount(ns->mq_mnt);
-}
-
 static int __init init_mqueue_fs(void)
 {
        int error;
index a26860a..6ecc30e 100644 (file)
@@ -145,10 +145,11 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
 
 static void free_ipc_ns(struct ipc_namespace *ns)
 {
-       /* mq_put_mnt() waits for a grace period as kern_unmount()
-        * uses synchronize_rcu().
+       /*
+        * Caller needs to wait for an RCU grace period to have passed
+        * after making the mount point inaccessible to new accesses.
         */
-       mq_put_mnt(ns);
+       mntput(ns->mq_mnt);
        sem_exit_ns(ns);
        msg_exit_ns(ns);
        shm_exit_ns(ns);
@@ -169,6 +170,12 @@ static void free_ipc(struct work_struct *unused)
        struct ipc_namespace *n, *t;
 
        llist_for_each_entry_safe(n, t, node, mnt_llist)
+               mnt_make_shortterm(n->mq_mnt);
+
+       /* Wait for any last users to have gone away. */
+       synchronize_rcu();
+
+       llist_for_each_entry_safe(n, t, node, mnt_llist)
                free_ipc_ns(n);
 }
 
index b2906e3..67bdd2a 100644 (file)
@@ -56,10 +56,8 @@ struct pid_namespace;
 
 #ifdef CONFIG_POSIX_MQUEUE
 extern void mq_clear_sbinfo(struct ipc_namespace *ns);
-extern void mq_put_mnt(struct ipc_namespace *ns);
 #else
 static inline void mq_clear_sbinfo(struct ipc_namespace *ns) { }
-static inline void mq_put_mnt(struct ipc_namespace *ns) { }
 #endif
 
 #ifdef CONFIG_SYSVIPC