Skip to content

Commit da27f79

Browse files
rikvanrielAl Viro
authored andcommitted
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 <[email protected]> Reported-by: Chris Mason <[email protected]> Tested-by: Giuseppe Scrivano <[email protected]> Suggested-by: Al Viro <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent a80c4ad commit da27f79

File tree

5 files changed

+25
-14
lines changed

5 files changed

+25
-14
lines changed

fs/namespace.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,6 +1397,17 @@ struct vfsmount *mntget(struct vfsmount *mnt)
13971397
}
13981398
EXPORT_SYMBOL(mntget);
13991399

1400+
/*
1401+
* Make a mount point inaccessible to new lookups.
1402+
* Because there may still be current users, the caller MUST WAIT
1403+
* for an RCU grace period before destroying the mount point.
1404+
*/
1405+
void mnt_make_shortterm(struct vfsmount *mnt)
1406+
{
1407+
if (mnt)
1408+
real_mount(mnt)->mnt_ns = NULL;
1409+
}
1410+
14001411
/**
14011412
* path_is_mountpoint() - Check if path is a mount in the current namespace.
14021413
* @path: path to check
@@ -4573,8 +4584,8 @@ EXPORT_SYMBOL_GPL(kern_mount);
45734584
void kern_unmount(struct vfsmount *mnt)
45744585
{
45754586
/* release long term mount so mount point can be released */
4576-
if (!IS_ERR_OR_NULL(mnt)) {
4577-
real_mount(mnt)->mnt_ns = NULL;
4587+
if (!IS_ERR(mnt)) {
4588+
mnt_make_shortterm(mnt);
45784589
synchronize_rcu(); /* yecchhh... */
45794590
mntput(mnt);
45804591
}
@@ -4586,8 +4597,7 @@ void kern_unmount_array(struct vfsmount *mnt[], unsigned int num)
45864597
unsigned int i;
45874598

45884599
for (i = 0; i < num; i++)
4589-
if (mnt[i])
4590-
real_mount(mnt[i])->mnt_ns = NULL;
4600+
mnt_make_shortterm(mnt[i]);
45914601
synchronize_rcu_expedited();
45924602
for (i = 0; i < num; i++)
45934603
mntput(mnt[i]);

include/linux/mount.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ extern void mnt_drop_write(struct vfsmount *mnt);
8888
extern void mnt_drop_write_file(struct file *file);
8989
extern void mntput(struct vfsmount *mnt);
9090
extern struct vfsmount *mntget(struct vfsmount *mnt);
91+
extern void mnt_make_shortterm(struct vfsmount *mnt);
9192
extern struct vfsmount *mnt_clone_internal(const struct path *path);
9293
extern bool __mnt_is_readonly(struct vfsmount *mnt);
9394
extern bool mnt_may_suid(struct vfsmount *mnt);

ipc/mqueue.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,11 +1709,6 @@ void mq_clear_sbinfo(struct ipc_namespace *ns)
17091709
ns->mq_mnt->mnt_sb->s_fs_info = NULL;
17101710
}
17111711

1712-
void mq_put_mnt(struct ipc_namespace *ns)
1713-
{
1714-
kern_unmount(ns->mq_mnt);
1715-
}
1716-
17171712
static int __init init_mqueue_fs(void)
17181713
{
17191714
int error;

ipc/namespace.c

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,11 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
145145

146146
static void free_ipc_ns(struct ipc_namespace *ns)
147147
{
148-
/* mq_put_mnt() waits for a grace period as kern_unmount()
149-
* uses synchronize_rcu().
148+
/*
149+
* Caller needs to wait for an RCU grace period to have passed
150+
* after making the mount point inaccessible to new accesses.
150151
*/
151-
mq_put_mnt(ns);
152+
mntput(ns->mq_mnt);
152153
sem_exit_ns(ns);
153154
msg_exit_ns(ns);
154155
shm_exit_ns(ns);
@@ -168,6 +169,12 @@ static void free_ipc(struct work_struct *unused)
168169
struct llist_node *node = llist_del_all(&free_ipc_list);
169170
struct ipc_namespace *n, *t;
170171

172+
llist_for_each_entry_safe(n, t, node, mnt_llist)
173+
mnt_make_shortterm(n->mq_mnt);
174+
175+
/* Wait for any last users to have gone away. */
176+
synchronize_rcu();
177+
171178
llist_for_each_entry_safe(n, t, node, mnt_llist)
172179
free_ipc_ns(n);
173180
}

ipc/util.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,8 @@ struct pid_namespace;
5656

5757
#ifdef CONFIG_POSIX_MQUEUE
5858
extern void mq_clear_sbinfo(struct ipc_namespace *ns);
59-
extern void mq_put_mnt(struct ipc_namespace *ns);
6059
#else
6160
static inline void mq_clear_sbinfo(struct ipc_namespace *ns) { }
62-
static inline void mq_put_mnt(struct ipc_namespace *ns) { }
6361
#endif
6462

6563
#ifdef CONFIG_SYSVIPC

0 commit comments

Comments
 (0)