posix mqueue namespace (v11)
cover posix mqueue namespace (v11)
(Ok I don't know what the actual version number is - it's high but 11 is probably safe)
Cedric and Nadia took several approaches to making posix message queues per-namespace. I ended up mamking some deep changes so am not retaining their Signed-off-by:s on this version, but this is definately very much based on work by both of them.
Patch 2 hopefully explains my approach. Briefly,
1. sysv and posix ipc are both under CLONE_NEWIPC
2. the mqueue sb is per-ipc-namespace
So to create a new ipc namespace, you would
unshare(CLONE_NEWIPC|CLONE_NEWNS); umount /dev/mqueue mount -t mqueue mqueue /dev/mqueue
It's perfectly valid to do vfs operations on files in another ipc_namespace's /dev/mqueue, but any use of mq_open(3) and friends will act in your own ipc_ns.
thanks,
-serge
A message that is not in the archive (sent off-list or not yet received): 20081215233747.GA27553-r/[email protected]
RFC PATCH 1/2 mqueue ns: move mqueue_mnt into struct ipc_namespace
Move mqueue vfsmount plus a few tunables into the ipc_namespace struct. The CONFIG_IPC_NS boolean and the ipc_namespace struct will serve both the posix message queue namespaces and the SYSV ipc namespaces.
Largely based on previous version by Cedric Le Goater <clg-NmTC/[email protected]> and Nadia Derbey <Nadia.Derbey-6ktuUTfB/[email protected]>.
--- include/linux/ipc_namespace.h | 32 ++++++++++-- init/Kconfig | 4 +- ipc/mqueue.c | 116 ++++++++++++++++++++++------------------- ipc/msgutil.c | 21 +++++++ ipc/namespace.c | 2 + ipc/util.c | 9 --- ipc/util.h | 15 +++++ 7 files changed, 131 insertions(+), 68 deletions(-)
include/linux/ipc_namespace.h +28 -4
@@ -44,24 +44,48 @@ struct ipc_namespace {int shm_tot;struct notifier_block ipcns_nb; + +struct vfsmount *mq_mnt; +unsigned int mq_queues_count; +unsigned int mq_queues_max; +unsigned int mq_msg_max; +unsigned int mq_msgsize_max; + };extern struct ipc_namespace init_ipc_ns;extern atomic_t nr_ipc_ns; -#ifdef CONFIG_SYSVIPC +#if defined(CONFIG_POSIX_MQUEUE ) || defined(CONFIG_SYSVIPC )#define INIT_IPC_NS (ns) .ns = &init_ipc_ns, +#else +#define INIT_IPC_NS (ns) +#endif +#ifdef CONFIG_SYSVIPC extern int register_ipcns_notifier (struct ipc_namespace *);extern int cond_register_ipcns_notifier (struct ipc_namespace *);extern void unregister_ipcns_notifier (struct ipc_namespace *);extern int ipcns_notify (unsigned long ); -#else /* CONFIG_SYSVIPC */ -#define INIT_IPC_NS (ns) +#define register_ipcns_notifier (ns) +#define cond_register_ipcns_notifier (ns) +#define unregister_ipcns_notifier (ns) +#define ipcns_notify (l)#endif /* CONFIG_SYSVIPC */ -#if defined(CONFIG_SYSVIPC ) && defined(CONFIG_IPC_NS ) +#ifdef CONFIG_POSIX_MQUEUE +extern void mq_init_ns (struct ipc_namespace *ns); +/* default values */ +#define DFLT_QUEUESMAX 256/* max number of message queues */ +#define DFLT_MSGMAX 10/* max number of messages in each queue */ +#define HARD_MSGMAX (131072/sizeof(void *)) +#define DFLT_MSGSIZEMAX 8192/* max message size */ +#else +#define mq_init_ns (ns) +#endif + +#if defined(CONFIG_IPC_NS )extern void free_ipc_ns (struct kref *kref);extern struct ipc_namespace *copy_ipcs (unsigned long flags,struct ipc_namespace *ns);
init/Kconfig +2 -2
@@ -489,10 +489,10 @@ config UTS_NS config IPC_NS bool "IPC namespace" - depends on NAMESPACES && SYSVIPC + depends on NAMESPACES && (SYSVIPC || POSIX_MQUEUE) help In this namespace tasks work with IPC ids which correspond to - different IPC objects in different namespaces + different IPC objects in different namespaces. config USER_NS bool "User namespace (EXPERIMENTAL)"
ipc/mqueue.c +63 -53
336 lines not on this page · raw message
ipc/msgutil.c +21 -0
@@ -13,10 +13,31 @@#include <linux/security.h> #include <linux/slab.h> #include <linux/ipc.h> +#include <linux/ipc_namespace.h> #include <asm/uaccess.h> #include "util.h" +/* +* The next 2 defines are here bc this is the only file +* compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE +* and not CONFIG_IPC_NS. +*/ +struct ipc_namespace init_ipc_ns = { + .kref = { + .refcount =ATOMIC_INIT (2 ), + }, +#ifdef CONFIG_POSIX_MQUEUE + .mq_mnt =NULL , + .mq_queues_count =0 , + .mq_queues_max =DFLT_QUEUESMAX , + .mq_msg_max =DFLT_MSGMAX , + .mq_msgsize_max =DFLT_MSGSIZEMAX , +#endif +}; + +atomic_t nr_ipc_ns =ATOMIC_INIT (1 ); +struct msg_msgseg {struct msg_msgseg * next;/* the next part of the message follows immediately */
ipc/namespace.c +2 -0
@@ -25,6 +25,7 @@ static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)sem_init_ns (ns);msg_init_ns (ns);shm_init_ns (ns); +mq_init_ns (ns);/* * msgmni has already been computed for the new ipc ns.
@@ -101,6 +102,7 @@ void free_ipc_ns(struct kref *kref)sem_exit_ns (ns);msg_exit_ns (ns);shm_exit_ns (ns); +mq_exit_ns (ns);kfree (ns);atomic_dec (&nr_ipc_ns);
ipc/util.c +0 -9
@@ -47,15 +47,6 @@ struct ipc_proc_iface {int (*show)(struct seq_file *,void *); }; -struct ipc_namespace init_ipc_ns = { - .kref = { - .refcount =ATOMIC_INIT (2 ), - }, -}; - -atomic_t nr_ipc_ns =ATOMIC_INIT (1 ); - -#ifdef CONFIG_MEMORY_HOTPLUG static void ipc_memory_notifier (struct work_struct *work)
ipc/util.h +15 -0
@@ -20,6 +20,13 @@ void shm_init (void);struct ipc_namespace ; +#ifdef CONFIG_POSIX_MQUEUE +void mq_exit_ns (struct ipc_namespace *ns); +#else +#define mq_exit_ns (ns) +#endif + +#ifdef CONFIG_SYSVIPC void sem_init_ns (struct ipc_namespace *ns);void msg_init_ns (struct ipc_namespace *ns);void shm_init_ns (struct ipc_namespace *ns);
@@ -27,6 +34,14 @@ void shm_init_ns(struct ipc_namespace *ns);void sem_exit_ns (struct ipc_namespace *ns);void msg_exit_ns (struct ipc_namespace *ns);void shm_exit_ns (struct ipc_namespace *ns); +#else +#define sem_init_ns (ns) +#define msg_init_ns (ns) +#define shm_init_ns (ns) +#define sem_exit_ns (ns) +#define msg_exit_ns (ns) +#define shm_exit_ns (ns) +#endif /* * Structure that holds the parameters needed by the ipc operations
Signature · 1 line
1.5.4.3
RFC PATCH 2/2 ipc namespaces: implement support for posix msqueues
In reply to a message not in the archiveImplement multiple mounts of the mqueue file system, and link it to usage of CLONE_NEWIPC.
Each ipc ns has a corresponding mqueuefs superblock. When a user does clone(CLONE_NEWIPC) or unshare(CLONE_NEWIPC), the unshare will cause an internal mount of a new mqueuefs sb linked to the new ipc ns.
When a user does 'mount -t mqueue mqueue /dev/mqueue', he mounts the mqueuefs superblock.
Posix message queues can be worked with both through the mq_* system calls (see mq_overview(7)), and through the VFS through the mqueue mount. Any usage of mq_open() and friends will work with the acting task's ipc namespace. Any actions through the VFS will work with the mqueuefs in which the file was created. So if a user doesn't remount mqueuefs after unshare(CLONE_NEWIPC), mq_open("/ab") will not be reflected in "ls /dev/mqueue".
If task a mounts mqueue for ipc_ns:1, then clones task b with a new ipcns, ipcns:2, and then task a is the last task in ipc_ns:1 to exit, then (1) ipc_ns:1 will be freed, (2) it's superblock will live on until task b umounts the corresponding mqueuefs, and vfs actions will continue to succeed, but (3) sb->s_fs_info will be NULL for the sb corresponding to the deceased ipc_ns:1.
Largely based on previous version by Cedric Le Goater <clg-NmTC/[email protected]> and Nadia Derbey <Nadia.Derbey-6ktuUTfB/[email protected]>.
--- include/linux/ipc_namespace.h | 16 ++--- ipc/mqueue.c | 150 +++++++++++++++++++++++++++++++++-------- ipc/msgutil.c | 8 +-- ipc/namespace.c | 25 +++++-- ipc/util.h | 6 +- 5 files changed, 154 insertions(+), 51 deletions(-)
include/linux/ipc_namespace.h +7 -9
@@ -25,7 +25,7 @@ struct ipc_ids { };struct ipc_namespace { -struct kref kref; +atomic_t count;struct ipc_ids ids[3 ];int sem_ctls[4 ];
@@ -56,6 +56,7 @@ struct ipc_namespace {extern struct ipc_namespace init_ipc_ns;extern atomic_t nr_ipc_ns; +extern spinlock_t mq_lock;#if defined(CONFIG_POSIX_MQUEUE ) || defined(CONFIG_SYSVIPC )#define INIT_IPC_NS (ns) .ns = &init_ipc_ns,#else
@@ -75,18 +76,18 @@ extern int ipcns_notify(unsigned long);#endif /* CONFIG_SYSVIPC */ #ifdef CONFIG_POSIX_MQUEUE -extern void mq_init_ns (struct ipc_namespace *ns); +extern int mq_init_ns (struct ipc_namespace *ns);/* default values */ #define DFLT_QUEUESMAX 256/* max number of message queues */ #define DFLT_MSGMAX 10/* max number of messages in each queue */ #define HARD_MSGMAX (131072/sizeof(void *))#define DFLT_MSGSIZEMAX 8192/* max message size */ #else -#define mq_init_ns (ns) +#define mq_init_ns (ns) (0)#endif #if defined(CONFIG_IPC_NS ) -extern void free_ipc_ns (struct kref *kref); +extern void free_ipc_ns (struct ipc_namespace *ns);extern struct ipc_namespace *copy_ipcs (unsigned long flags,struct ipc_namespace *ns); extern void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
@@ -96,14 +97,11 @@ extern void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,static inline struct ipc_namespace *get_ipc_ns (struct ipc_namespace *ns) {if (ns) -kref_get (&ns->kref); +atomic_inc (&ns->count);return ns; } -static inline void put_ipc_ns (struct ipc_namespace *ns) -{ -kref_put (&ns->kref, free_ipc_ns); -} +extern void put_ipc_ns (struct ipc_namespace *ns);#else static inline struct ipc_namespace *copy_ipcs (unsigned long flags,struct ipc_namespace *ns)
ipc/mqueue.c +121 -29
268 lines not on this page · raw message
ipc/msgutil.c +3 -5
@@ -18,18 +18,16 @@#include "util.h" +spinlock_t mq_lock; +/* * The next 2 defines are here bc this is the only file * compiled when either CONFIG_SYSVIPC and CONFIG_POSIX_MQUEUE * and not CONFIG_IPC_NS. */ struct ipc_namespace init_ipc_ns = { - .kref = { - .refcount =ATOMIC_INIT (2 ), - }, + .count =ATOMIC_INIT (2 ), #ifdef CONFIG_POSIX_MQUEUE - .mq_mnt =NULL , - .mq_queues_count =0 , .mq_queues_max =DFLT_QUEUESMAX , .mq_msg_max =DFLT_MSGMAX , .mq_msgsize_max = DFLT_MSGSIZEMAX,
ipc/namespace.c +19 -6
@@ -9,23 +9,31 @@#include <linux/rcupdate.h> #include <linux/nsproxy.h> #include <linux/slab.h> +#include <linux/fs.h> +#include <linux/mount.h> #include "util.h" static struct ipc_namespace *clone_ipc_ns (struct ipc_namespace *old_ns) {struct ipc_namespace *ns; +int err; ns =kmalloc (sizeof (struct ipc_namespace ),GFP_KERNEL );if (ns ==NULL )return ERR_PTR (-ENOMEM ); +atomic_set (&ns->count,1 ); + err =mq_init_ns (ns); +if (err) { +kfree (ns); +return ERR_PTR (err); + }atomic_inc (&nr_ipc_ns);sem_init_ns (ns);msg_init_ns (ns);shm_init_ns (ns); -mq_init_ns (ns);/* * msgmni has already been computed for the new ipc ns.
@@ -35,7 +43,6 @@ static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)ipcns_notify (IPCNS_CREATED );register_ipcns_notifier (ns); -kref_init (&ns->kref);return ns; }
@@ -85,11 +92,18 @@ void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,up_write (&ids->rw_mutex); } -void free_ipc_ns (struct kref *kref) +void put_ipc_ns (struct ipc_namespace *ns) { -struct ipc_namespace *ns; +if (ns &&atomic_dec_and_lock (&ns->count, &mq_lock)) { +mq_clear_sbinfo (ns); +spin_unlock (&mq_lock); +mq_put_mnt (ns); +free_ipc_ns (ns); + } +} - ns = container_of(kref, struct ipc_namespace, kref); +void free_ipc_ns (struct ipc_namespace *ns) +{/* * Unregistering the hotplug notifier at the beginning guarantees * that the ipc namespace won't be freed while we are inside the
@@ -102,7 +116,6 @@ void free_ipc_ns(struct kref *kref)sem_exit_ns (ns);msg_exit_ns (ns);shm_exit_ns (ns); -mq_exit_ns (ns);kfree (ns);atomic_dec (&nr_ipc_ns);
ipc/util.h +4 -2
@@ -21,9 +21,11 @@ void shm_init (void);struct ipc_namespace ;#ifdef CONFIG_POSIX_MQUEUE -void mq_exit_ns (struct ipc_namespace *ns); +extern void mq_clear_sbinfo (struct ipc_namespace *ns); +extern void mq_put_mnt (struct ipc_namespace *ns);#else -#define mq_exit_ns (ns) +#define mq_clear_sbinfo (ns) +#define mq_put_mnt (ns)#endif #ifdef CONFIG_SYSVIPC
Signature · 1 line
1.5.4.3
Quoted 8 lines · Serge E. Hallyn
(Ok I don't know what the actual version number is - it's high but 11 is probably safe)
Cedric and Nadia took several approaches to making posix message queues per-namespace. I ended up mamking some deep changes so am not retaining their Signed-off-by:s on this version, but this is definately very much based on work by both of them.
you can keep mine. i have had a similar version on 2.6.26.
http://legoater.free.fr/patches/2.6.26/2.6.26/
and it's easier to track where the patches go.
Quoted 8 lines
Patch 2 hopefully explains my approach. Briefly,
1. sysv and posix ipc are both under
CLONE_NEWIPC
2. the mqueue sb is per-ipc-namespaceSo to create a new ipc namespace, you would
unshare(CLONE_NEWIPC|CLONE_NEWNS);
does CLONE_NEWIPC requires CLONE_NEWNS ?
Quoted 2 lines
umount
/dev/mqueue
mount -t mqueue mqueue/dev/mqueue
the semantic looks good, much better than a 'newinstance' mount option.
if CLONE_NEWNS is not required, what happens to the user mount (and the mq_ns below it) when the task dies. that's the big issue. if CLONE_NEWNS is required were safe, but I think Pavel made some objection to that.
Quoted 3 lines
It's perfectly valid to do vfs operations on files in another ipc_namespace's
/dev/mqueue, but any use ofmq_open(3)and friends will act in your ownipc_ns.
ok.
C.
A message that is not in the archive (sent off-list or not yet received): 4947629D.9040807-NmTC/[email protected]
Quoted 10 lines · Cedric Le Goater
Quoted 8 lines · Serge E. Hallyn
(Ok I don't know what the actual version number is - it's high but 11 is probably safe)
Cedric and Nadia took several approaches to making posix message queues per-namespace. I ended up mamking some deep changes so am not retaining their Signed-off-by:s on this version, but this is definately very much based on work by both of them.
Quoted 7 lines
you can keep mine. i have had a similar version on 2.6.26.
http://legoater.free.fr/patches/2.6.26/2.6.26/
and it's easier to track where the patches go.
Quoted 1 line
Patch 2 hopefully explains my approach. Briefly,
Thanks, Cedric, will put those back.
Quoted 8 lines
Quoted 6 lines
1. sysv and posix ipc are both under
CLONE_NEWIPC
2. the mqueue sb is per-ipc-namespaceSo to create a new ipc namespace, you would
unshare(CLONE_NEWIPC|CLONE_NEWNS);does
CLONE_NEWIPCrequiresCLONE_NEWNS?
No, the mq_* syscalls don't need the fs to be actually mounted, and a container could just chroot("/vs1"); and mount -t mqueue under /vs1/dev/mqueue, not requiring a new mounts namespace.
Quoted 5 lines
Quoted 2 lines
umount
/dev/mqueue
mount -t mqueue mqueue/dev/mqueuethe semantic looks good, much better than a 'newinstance' mount option.
Agreed. newinstance works for a pure filesystem like devpts, but it simply isn't a good fit for mqueue.
Quoted 4 lines
if
CLONE_NEWNSis not required, what happens to the user mount (and themq_nsbelow it) when the task dies. that's the big issue. ifCLONE_NEWNSis required were safe, but I think Pavel made some objection to that.
(Huh, I just noticed get_ns_from_sb() doesn't seem to be called anywhere <scribble><scribble>)
Short version:
The user mount hangs around until someone umounts it. Now of course I expect that most users WILL want to do CLONE_NEWIPC|CLONE_NEWNS.
Long version:
Any VFS actions through mqueuefs will do:
spin_lock(&mq_lock);
ipc_ns = get_ipc_ns(inode->i_sb->s_fs_info);
spin_unlock(&mq_lock);
where s_fs_info is the ipc_ns. Freeing an ipc_ns does
if (atomic_dec_and_lock(&ipc_ns->count, &mq_lock)) {
mq_ns->mnt->mnt_sb->s_fs_info = NULL;
spin_unlock(&mq_lock);
mntput(mq_ns->mnt);
}So if a vfs_create() by a task in another ipc_ns is racing with the task exit of the last task in the ipc_ns, then either
1. the vfs_create() manages to pin the ipc_ns before the other task exits. So the task exit won't free the ipc_ns. The put_ipc_ns() at the end of vfs_create() will.
or
2. the task exits first, vfs_create() finds s_fs_info NULL, and returns -EACCES. Unlink simply succeeds.
Pavel, please let me know if you have issues with my approach.
Quoted 5 lines
Quoted 3 lines
It's perfectly valid to do vfs operations on files in another ipc_namespace's
/dev/mqueue, but any use ofmq_open(3)and friends will act in your ownipc_ns.ok.
Nadia had written a cool set of ltp tests. They were based around the mount -o newinstance semantics so i'll have to see which ones are still relevant and rework some others, then will post them and repost the kernel patchset.
Thanks for taking a look, Cedric, and for getting this set going before.
-serge