ipc,namespace: batch free ipc_namespace structures
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>
This commit is contained in:
parent
a80c4adcb5
commit
da27f796a8
|
@ -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]);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
@ -168,6 +169,12 @@ static void free_ipc(struct work_struct *unused)
|
|||
struct llist_node *node = llist_del_all(&free_ipc_list);
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue