Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'work.namespace' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull ipc namespace update from Al Viro:
"Rik's patches reducing the amount of synchronize_rcu() triggered by
ipc namespace destruction.

I've some pending stuff reducing that on the normal umount side, but
it's nowhere near ready and Rik's stuff shouldn't be held back due to
conflicts - I'll just redo the parts of my series that stray into
ipc/*"

* 'work.namespace' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
ipc,namespace: batch free ipc_namespace structures
ipc,namespace: make ipc namespace allocation wait for pending free

+41 -20
+14 -4
fs/namespace.c
··· 1283 1283 } 1284 1284 EXPORT_SYMBOL(mntget); 1285 1285 1286 + /* 1287 + * Make a mount point inaccessible to new lookups. 1288 + * Because there may still be current users, the caller MUST WAIT 1289 + * for an RCU grace period before destroying the mount point. 1290 + */ 1291 + void mnt_make_shortterm(struct vfsmount *mnt) 1292 + { 1293 + if (mnt) 1294 + real_mount(mnt)->mnt_ns = NULL; 1295 + } 1296 + 1286 1297 /** 1287 1298 * path_is_mountpoint() - Check if path is a mount in the current namespace. 1288 1299 * @path: path to check ··· 4470 4459 void kern_unmount(struct vfsmount *mnt) 4471 4460 { 4472 4461 /* release long term mount so mount point can be released */ 4473 - if (!IS_ERR_OR_NULL(mnt)) { 4474 - real_mount(mnt)->mnt_ns = NULL; 4462 + if (!IS_ERR(mnt)) { 4463 + mnt_make_shortterm(mnt); 4475 4464 synchronize_rcu(); /* yecchhh... */ 4476 4465 mntput(mnt); 4477 4466 } ··· 4483 4472 unsigned int i; 4484 4473 4485 4474 for (i = 0; i < num; i++) 4486 - if (mnt[i]) 4487 - real_mount(mnt[i])->mnt_ns = NULL; 4475 + mnt_make_shortterm(mnt[i]); 4488 4476 synchronize_rcu_expedited(); 4489 4477 for (i = 0; i < num; i++) 4490 4478 mntput(mnt[i]);
+1
include/linux/mount.h
··· 86 86 extern void mnt_drop_write_file(struct file *file); 87 87 extern void mntput(struct vfsmount *mnt); 88 88 extern struct vfsmount *mntget(struct vfsmount *mnt); 89 + extern void mnt_make_shortterm(struct vfsmount *mnt); 89 90 extern struct vfsmount *mnt_clone_internal(const struct path *path); 90 91 extern bool __mnt_is_readonly(struct vfsmount *mnt); 91 92 extern bool mnt_may_suid(struct vfsmount *mnt);
-5
ipc/mqueue.c
··· 1709 1709 ns->mq_mnt->mnt_sb->s_fs_info = NULL; 1710 1710 } 1711 1711 1712 - void mq_put_mnt(struct ipc_namespace *ns) 1713 - { 1714 - kern_unmount(ns->mq_mnt); 1715 - } 1716 - 1717 1712 static int __init init_mqueue_fs(void) 1718 1713 { 1719 1714 int error;
+26 -9
ipc/namespace.c
··· 19 19 20 20 #include "util.h" 21 21 22 + /* 23 + * The work queue is used to avoid the cost of synchronize_rcu in kern_unmount. 24 + */ 25 + static void free_ipc(struct work_struct *unused); 26 + static DECLARE_WORK(free_ipc_work, free_ipc); 27 + 22 28 static struct ucounts *inc_ipc_namespaces(struct user_namespace *ns) 23 29 { 24 30 return inc_ucount(ns, current_euid(), UCOUNT_IPC_NAMESPACES); ··· 43 37 int err; 44 38 45 39 err = -ENOSPC; 40 + again: 46 41 ucounts = inc_ipc_namespaces(user_ns); 47 - if (!ucounts) 42 + if (!ucounts) { 43 + /* 44 + * IPC namespaces are freed asynchronously, by free_ipc_work. 45 + * If frees were pending, flush_work will wait, and 46 + * return true. Fail the allocation if no frees are pending. 47 + */ 48 + if (flush_work(&free_ipc_work)) 49 + goto again; 48 50 goto fail; 51 + } 49 52 50 53 err = -ENOMEM; 51 54 ns = kzalloc(sizeof(struct ipc_namespace), GFP_KERNEL_ACCOUNT); ··· 145 130 146 131 static void free_ipc_ns(struct ipc_namespace *ns) 147 132 { 148 - /* mq_put_mnt() waits for a grace period as kern_unmount() 149 - * uses synchronize_rcu(). 133 + /* 134 + * Caller needs to wait for an RCU grace period to have passed 135 + * after making the mount point inaccessible to new accesses. 150 136 */ 151 - mq_put_mnt(ns); 137 + mntput(ns->mq_mnt); 152 138 sem_exit_ns(ns); 153 139 msg_exit_ns(ns); 154 140 shm_exit_ns(ns); ··· 170 154 struct ipc_namespace *n, *t; 171 155 172 156 llist_for_each_entry_safe(n, t, node, mnt_llist) 157 + mnt_make_shortterm(n->mq_mnt); 158 + 159 + /* Wait for any last users to have gone away. */ 160 + synchronize_rcu(); 161 + 162 + llist_for_each_entry_safe(n, t, node, mnt_llist) 173 163 free_ipc_ns(n); 174 164 } 175 - 176 - /* 177 - * The work queue is used to avoid the cost of synchronize_rcu in kern_unmount. 178 - */ 179 - static DECLARE_WORK(free_ipc_work, free_ipc); 180 165 181 166 /* 182 167 * put_ipc_ns - drop a reference to an ipc namespace.
-2
ipc/util.h
··· 56 56 57 57 #ifdef CONFIG_POSIX_MQUEUE 58 58 extern void mq_clear_sbinfo(struct ipc_namespace *ns); 59 - extern void mq_put_mnt(struct ipc_namespace *ns); 60 59 #else 61 60 static inline void mq_clear_sbinfo(struct ipc_namespace *ns) { } 62 - static inline void mq_put_mnt(struct ipc_namespace *ns) { } 63 61 #endif 64 62 65 63 #ifdef CONFIG_SYSVIPC