diff options
Diffstat (limited to 'ipc')
-rw-r--r-- | ipc/Makefile | 1 | ||||
-rw-r--r-- | ipc/ipc_sysctl.c | 1 | ||||
-rw-r--r-- | ipc/mqueue.c | 5 | ||||
-rw-r--r-- | ipc/msg.c | 64 | ||||
-rw-r--r-- | ipc/namespace.c | 86 | ||||
-rw-r--r-- | ipc/sem.c | 101 | ||||
-rw-r--r-- | ipc/shm.c | 66 | ||||
-rw-r--r-- | ipc/util.c | 126 | ||||
-rw-r--r-- | ipc/util.h | 78 |
9 files changed, 242 insertions, 286 deletions
diff --git a/ipc/Makefile b/ipc/Makefile index b93bba6652f1..5fc5e33ea047 100644 --- a/ipc/Makefile +++ b/ipc/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o obj_mq-$(CONFIG_COMPAT) += compat_mq.o obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) +obj-$(CONFIG_IPC_NS) += namespace.o diff --git a/ipc/ipc_sysctl.c b/ipc/ipc_sysctl.c index 79e24e878c1e..7f4235bed51b 100644 --- a/ipc/ipc_sysctl.c +++ b/ipc/ipc_sysctl.c @@ -14,6 +14,7 @@ #include <linux/nsproxy.h> #include <linux/sysctl.h> #include <linux/uaccess.h> +#include <linux/ipc_namespace.h> static void *get_ipc(ctl_table *table) { diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 6ca7b97114f3..60f7a27f7a9e 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c @@ -332,8 +332,7 @@ static ssize_t mqueue_read_file(struct file *filp, char __user *u_data, (info->notify_owner && info->notify.sigev_notify == SIGEV_SIGNAL) ? info->notify.sigev_signo : 0, - pid_nr_ns(info->notify_owner, - current->nsproxy->pid_ns)); + pid_vnr(info->notify_owner)); spin_unlock(&info->lock); buffer[sizeof(buffer)-1] = '\0'; slen = strlen(buffer)+1; @@ -510,7 +509,7 @@ static void __do_notify(struct mqueue_inode_info *info) sig_i.si_errno = 0; sig_i.si_code = SI_MESGQ; sig_i.si_value = info->notify.sigev_value; - sig_i.si_pid = task_pid_vnr(current); + sig_i.si_pid = task_tgid_vnr(current); sig_i.si_uid = current->uid; kill_pid_info(info->notify.sigev_signo, diff --git a/ipc/msg.c b/ipc/msg.c index fdf3db5731ce..46585a05473e 100644 --- a/ipc/msg.c +++ b/ipc/msg.c @@ -36,6 +36,7 @@ #include <linux/seq_file.h> #include <linux/rwsem.h> #include <linux/nsproxy.h> +#include <linux/ipc_namespace.h> #include <asm/current.h> #include <asm/uaccess.h> @@ -66,70 +67,37 @@ struct msg_sender { #define SEARCH_NOTEQUAL 3 #define SEARCH_LESSEQUAL 4 -static struct ipc_ids init_msg_ids; - -#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS])) +#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS]) #define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) #define msg_buildid(id, seq) ipc_buildid(id, seq) -static void freeque(struct ipc_namespace *, struct msg_queue *); +static void freeque(struct ipc_namespace *, struct kern_ipc_perm *); static int newque(struct ipc_namespace *, struct ipc_params *); #ifdef CONFIG_PROC_FS static int sysvipc_msg_proc_show(struct seq_file *s, void *it); #endif -static void __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) +void msg_init_ns(struct ipc_namespace *ns) { - ns->ids[IPC_MSG_IDS] = ids; ns->msg_ctlmax = MSGMAX; ns->msg_ctlmnb = MSGMNB; ns->msg_ctlmni = MSGMNI; atomic_set(&ns->msg_bytes, 0); atomic_set(&ns->msg_hdrs, 0); - ipc_init_ids(ids); -} - -int msg_init_ns(struct ipc_namespace *ns) -{ - struct ipc_ids *ids; - - ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); - if (ids == NULL) - return -ENOMEM; - - __msg_init_ns(ns, ids); - return 0; + ipc_init_ids(&ns->ids[IPC_MSG_IDS]); } +#ifdef CONFIG_IPC_NS void msg_exit_ns(struct ipc_namespace *ns) { - struct msg_queue *msq; - int next_id; - int total, in_use; - - down_write(&msg_ids(ns).rw_mutex); - - in_use = msg_ids(ns).in_use; - - for (total = 0, next_id = 0; total < in_use; next_id++) { - msq = idr_find(&msg_ids(ns).ipcs_idr, next_id); - if (msq == NULL) - continue; - ipc_lock_by_ptr(&msq->q_perm); - freeque(ns, msq); - total++; - } - - up_write(&msg_ids(ns).rw_mutex); - - kfree(ns->ids[IPC_MSG_IDS]); - ns->ids[IPC_MSG_IDS] = NULL; + free_ipcs(ns, &msg_ids(ns), freeque); } +#endif void __init msg_init(void) { - __msg_init_ns(&init_ipc_ns, &init_msg_ids); + msg_init_ns(&init_ipc_ns); ipc_init_proc_interface("sysvipc/msg", " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", IPC_MSG_IDS, sysvipc_msg_proc_show); @@ -144,6 +112,9 @@ static inline struct msg_queue *msg_lock_check_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&msg_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct msg_queue *)ipcp; + return container_of(ipcp, struct msg_queue, q_perm); } @@ -155,6 +126,9 @@ static inline struct msg_queue *msg_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&msg_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct msg_queue *)ipcp; + return container_of(ipcp, struct msg_queue, q_perm); } @@ -163,6 +137,9 @@ static inline struct msg_queue *msg_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&msg_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct msg_queue *)ipcp; + return container_of(ipcp, struct msg_queue, q_perm); } @@ -278,9 +255,10 @@ static void expunge_all(struct msg_queue *msq, int res) * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held * before freeque() is called. msg_ids.rw_mutex remains locked on exit. */ -static void freeque(struct ipc_namespace *ns, struct msg_queue *msq) +static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) { struct list_head *tmp; + struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm); expunge_all(msq, -EIDRM); ss_wakeup(&msq->q_senders, 1); @@ -586,7 +564,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf) break; } case IPC_RMID: - freeque(ns, msq); + freeque(ns, &msq->q_perm); break; } err = 0; diff --git a/ipc/namespace.c b/ipc/namespace.c new file mode 100644 index 000000000000..1b967655eb35 --- /dev/null +++ b/ipc/namespace.c @@ -0,0 +1,86 @@ +/* + * linux/ipc/namespace.c + * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc. + */ + +#include <linux/ipc.h> +#include <linux/msg.h> +#include <linux/ipc_namespace.h> +#include <linux/rcupdate.h> +#include <linux/nsproxy.h> +#include <linux/slab.h> + +#include "util.h" + +static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) +{ + struct ipc_namespace *ns; + + ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); + if (ns == NULL) + return ERR_PTR(-ENOMEM); + + sem_init_ns(ns); + msg_init_ns(ns); + shm_init_ns(ns); + + kref_init(&ns->kref); + return ns; +} + +struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns) +{ + struct ipc_namespace *new_ns; + + BUG_ON(!ns); + get_ipc_ns(ns); + + if (!(flags & CLONE_NEWIPC)) + return ns; + + new_ns = clone_ipc_ns(ns); + + put_ipc_ns(ns); + return new_ns; +} + +/* + * free_ipcs - free all ipcs of one type + * @ns: the namespace to remove the ipcs from + * @ids: the table of ipcs to free + * @free: the function called to free each individual ipc + * + * Called for each kind of ipc when an ipc_namespace exits. + */ +void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids, + void (*free)(struct ipc_namespace *, struct kern_ipc_perm *)) +{ + struct kern_ipc_perm *perm; + int next_id; + int total, in_use; + + down_write(&ids->rw_mutex); + + in_use = ids->in_use; + + for (total = 0, next_id = 0; total < in_use; next_id++) { + perm = idr_find(&ids->ipcs_idr, next_id); + if (perm == NULL) + continue; + ipc_lock_by_ptr(perm); + free(ns, perm); + total++; + } + up_write(&ids->rw_mutex); +} + +void free_ipc_ns(struct kref *kref) +{ + struct ipc_namespace *ns; + + ns = container_of(kref, struct ipc_namespace, kref); + sem_exit_ns(ns); + msg_exit_ns(ns); + shm_exit_ns(ns); + kfree(ns); +} diff --git a/ipc/sem.c b/ipc/sem.c index 35952c0bae46..0b45a4d383c6 100644 --- a/ipc/sem.c +++ b/ipc/sem.c @@ -82,20 +82,19 @@ #include <linux/seq_file.h> #include <linux/rwsem.h> #include <linux/nsproxy.h> +#include <linux/ipc_namespace.h> #include <asm/uaccess.h> #include "util.h" -#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) +#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS]) #define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) #define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid) #define sem_buildid(id, seq) ipc_buildid(id, seq) -static struct ipc_ids init_sem_ids; - static int newary(struct ipc_namespace *, struct ipc_params *); -static void freeary(struct ipc_namespace *, struct sem_array *); +static void freeary(struct ipc_namespace *, struct kern_ipc_perm *); #ifdef CONFIG_PROC_FS static int sysvipc_sem_proc_show(struct seq_file *s, void *it); #endif @@ -117,56 +116,26 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it); #define sc_semopm sem_ctls[2] #define sc_semmni sem_ctls[3] -static void __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) +void sem_init_ns(struct ipc_namespace *ns) { - ns->ids[IPC_SEM_IDS] = ids; ns->sc_semmsl = SEMMSL; ns->sc_semmns = SEMMNS; ns->sc_semopm = SEMOPM; ns->sc_semmni = SEMMNI; ns->used_sems = 0; - ipc_init_ids(ids); -} - -int sem_init_ns(struct ipc_namespace *ns) -{ - struct ipc_ids *ids; - - ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); - if (ids == NULL) - return -ENOMEM; - - __sem_init_ns(ns, ids); - return 0; + ipc_init_ids(&ns->ids[IPC_SEM_IDS]); } +#ifdef CONFIG_IPC_NS void sem_exit_ns(struct ipc_namespace *ns) { - struct sem_array *sma; - int next_id; - int total, in_use; - - down_write(&sem_ids(ns).rw_mutex); - - in_use = sem_ids(ns).in_use; - - for (total = 0, next_id = 0; total < in_use; next_id++) { - sma = idr_find(&sem_ids(ns).ipcs_idr, next_id); - if (sma == NULL) - continue; - ipc_lock_by_ptr(&sma->sem_perm); - freeary(ns, sma); - total++; - } - up_write(&sem_ids(ns).rw_mutex); - - kfree(ns->ids[IPC_SEM_IDS]); - ns->ids[IPC_SEM_IDS] = NULL; + free_ipcs(ns, &sem_ids(ns), freeary); } +#endif void __init sem_init (void) { - __sem_init_ns(&init_ipc_ns, &init_sem_ids); + sem_init_ns(&init_ipc_ns); ipc_init_proc_interface("sysvipc/sem", " key semid perms nsems uid gid cuid cgid otime ctime\n", IPC_SEM_IDS, sysvipc_sem_proc_show); @@ -181,6 +150,9 @@ static inline struct sem_array *sem_lock_check_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&sem_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct sem_array *)ipcp; + return container_of(ipcp, struct sem_array, sem_perm); } @@ -192,6 +164,9 @@ static inline struct sem_array *sem_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&sem_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct sem_array *)ipcp; + return container_of(ipcp, struct sem_array, sem_perm); } @@ -200,6 +175,9 @@ static inline struct sem_array *sem_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&sem_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct sem_array *)ipcp; + return container_of(ipcp, struct sem_array, sem_perm); } @@ -546,10 +524,11 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum) * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex * remains locked on exit. */ -static void freeary(struct ipc_namespace *ns, struct sem_array *sma) +static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) { struct sem_undo *un; struct sem_queue *q; + struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm); /* Invalidate the existing undo structures for this semaphore set. * (They will be freed without any further action in exit_sem() @@ -603,8 +582,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, } } -static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, - int cmd, int version, union semun arg) +static int semctl_nolock(struct ipc_namespace *ns, int semid, + int cmd, int version, union semun arg) { int err = -EINVAL; struct sem_array *sma; @@ -643,14 +622,23 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, return -EFAULT; return (max_id < 0) ? 0: max_id; } + case IPC_STAT: case SEM_STAT: { struct semid64_ds tbuf; int id; - sma = sem_lock(ns, semid); - if (IS_ERR(sma)) - return PTR_ERR(sma); + if (cmd == SEM_STAT) { + sma = sem_lock(ns, semid); + if (IS_ERR(sma)) + return PTR_ERR(sma); + id = sma->sem_perm.id; + } else { + sma = sem_lock_check(ns, semid); + if (IS_ERR(sma)) + return PTR_ERR(sma); + id = 0; + } err = -EACCES; if (ipcperms (&sma->sem_perm, S_IRUGO)) @@ -660,8 +648,6 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, if (err) goto out_unlock; - id = sma->sem_perm.id; - memset(&tbuf, 0, sizeof(tbuf)); kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); @@ -796,19 +782,6 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum, err = 0; goto out_unlock; } - case IPC_STAT: - { - struct semid64_ds tbuf; - memset(&tbuf,0,sizeof(tbuf)); - kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); - tbuf.sem_otime = sma->sem_otime; - tbuf.sem_ctime = sma->sem_ctime; - tbuf.sem_nsems = sma->sem_nsems; - sem_unlock(sma); - if (copy_semid_to_user (arg.buf, &tbuf, version)) - return -EFAULT; - return 0; - } /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ } err = -EINVAL; @@ -936,7 +909,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum, switch(cmd){ case IPC_RMID: - freeary(ns, sma); + freeary(ns, ipcp); err = 0; break; case IPC_SET: @@ -975,15 +948,15 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg) switch(cmd) { case IPC_INFO: case SEM_INFO: + case IPC_STAT: case SEM_STAT: - err = semctl_nolock(ns,semid,semnum,cmd,version,arg); + err = semctl_nolock(ns, semid, cmd, version, arg); return err; case GETALL: case GETVAL: case GETPID: case GETNCNT: case GETZCNT: - case IPC_STAT: case SETVAL: case SETALL: err = semctl_main(ns,semid,semnum,cmd,version,arg); diff --git a/ipc/shm.c b/ipc/shm.c index 3818fae625c5..c47e87278a92 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -38,6 +38,7 @@ #include <linux/rwsem.h> #include <linux/nsproxy.h> #include <linux/mount.h> +#include <linux/ipc_namespace.h> #include <asm/uaccess.h> @@ -55,9 +56,7 @@ struct shm_file_data { static const struct file_operations shm_file_operations; static struct vm_operations_struct shm_vm_ops; -static struct ipc_ids init_shm_ids; - -#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS])) +#define shm_ids(ns) ((ns)->ids[IPC_SHM_IDS]) #define shm_unlock(shp) \ ipc_unlock(&(shp)->shm_perm) @@ -71,22 +70,24 @@ static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp); static int sysvipc_shm_proc_show(struct seq_file *s, void *it); #endif -static void __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) +void shm_init_ns(struct ipc_namespace *ns) { - ns->ids[IPC_SHM_IDS] = ids; ns->shm_ctlmax = SHMMAX; ns->shm_ctlall = SHMALL; ns->shm_ctlmni = SHMMNI; ns->shm_tot = 0; - ipc_init_ids(ids); + ipc_init_ids(&ns->ids[IPC_SHM_IDS]); } /* * Called with shm_ids.rw_mutex (writer) and the shp structure locked. * Only shm_ids.rw_mutex remains locked on exit. */ -static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp) +static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp) { + struct shmid_kernel *shp; + shp = container_of(ipcp, struct shmid_kernel, shm_perm); + if (shp->shm_nattch){ shp->shm_perm.mode |= SHM_DEST; /* Do not find it any more */ @@ -96,45 +97,16 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp) shm_destroy(ns, shp); } -int shm_init_ns(struct ipc_namespace *ns) -{ - struct ipc_ids *ids; - - ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL); - if (ids == NULL) - return -ENOMEM; - - __shm_init_ns(ns, ids); - return 0; -} - +#ifdef CONFIG_IPC_NS void shm_exit_ns(struct ipc_namespace *ns) { - struct shmid_kernel *shp; - int next_id; - int total, in_use; - - down_write(&shm_ids(ns).rw_mutex); - - in_use = shm_ids(ns).in_use; - - for (total = 0, next_id = 0; total < in_use; next_id++) { - shp = idr_find(&shm_ids(ns).ipcs_idr, next_id); - if (shp == NULL) - continue; - ipc_lock_by_ptr(&shp->shm_perm); - do_shm_rmid(ns, shp); - total++; - } - up_write(&shm_ids(ns).rw_mutex); - - kfree(ns->ids[IPC_SHM_IDS]); - ns->ids[IPC_SHM_IDS] = NULL; + free_ipcs(ns, &shm_ids(ns), do_shm_rmid); } +#endif void __init shm_init (void) { - __shm_init_ns(&init_ipc_ns, &init_shm_ids); + shm_init_ns(&init_ipc_ns); ipc_init_proc_interface("sysvipc/shm", " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", IPC_SHM_IDS, sysvipc_shm_proc_show); @@ -149,6 +121,9 @@ static inline struct shmid_kernel *shm_lock_down(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_down(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -158,6 +133,9 @@ static inline struct shmid_kernel *shm_lock_check_down( { struct kern_ipc_perm *ipcp = ipc_lock_check_down(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -169,6 +147,9 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) { struct kern_ipc_perm *ipcp = ipc_lock(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -177,6 +158,9 @@ static inline struct shmid_kernel *shm_lock_check(struct ipc_namespace *ns, { struct kern_ipc_perm *ipcp = ipc_lock_check(&shm_ids(ns), id); + if (IS_ERR(ipcp)) + return (struct shmid_kernel *)ipcp; + return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -833,7 +817,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf) if (err) goto out_unlock_up; - do_shm_rmid(ns, shp); + do_shm_rmid(ns, &shp->shm_perm); up_write(&shm_ids(ns).rw_mutex); goto out; } diff --git a/ipc/util.c b/ipc/util.c index 1aa0ebf71bac..fd1b50da9db8 100644 --- a/ipc/util.c +++ b/ipc/util.c @@ -33,6 +33,7 @@ #include <linux/audit.h> #include <linux/nsproxy.h> #include <linux/rwsem.h> +#include <linux/ipc_namespace.h> #include <asm/unistd.h> @@ -51,66 +52,6 @@ struct ipc_namespace init_ipc_ns = { }, }; -static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns) -{ - int err; - struct ipc_namespace *ns; - - err = -ENOMEM; - ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL); - if (ns == NULL) - goto err_mem; - - err = sem_init_ns(ns); - if (err) - goto err_sem; - err = msg_init_ns(ns); - if (err) - goto err_msg; - err = shm_init_ns(ns); - if (err) - goto err_shm; - - kref_init(&ns->kref); - return ns; - -err_shm: - msg_exit_ns(ns); -err_msg: - sem_exit_ns(ns); -err_sem: - kfree(ns); -err_mem: - return ERR_PTR(err); -} - -struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns) -{ - struct ipc_namespace *new_ns; - - BUG_ON(!ns); - get_ipc_ns(ns); - - if (!(flags & CLONE_NEWIPC)) - return ns; - - new_ns = clone_ipc_ns(ns); - - put_ipc_ns(ns); - return new_ns; -} - -void free_ipc_ns(struct kref *kref) -{ - struct ipc_namespace *ns; - - ns = container_of(kref, struct ipc_namespace, kref); - sem_exit_ns(ns); - msg_exit_ns(ns); - shm_exit_ns(ns); - kfree(ns); -} - /** * ipc_init - initialise IPC subsystem * @@ -307,7 +248,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size) * This routine is called by sys_msgget, sys_semget() and sys_shmget() * when the key is IPC_PRIVATE. */ -int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, +static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, struct ipc_ops *ops, struct ipc_params *params) { int err; @@ -371,7 +312,7 @@ static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops, * * On success, the ipc id is returned. */ -int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, +static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, struct ipc_ops *ops, struct ipc_params *params) { struct kern_ipc_perm *ipcp; @@ -769,6 +710,57 @@ struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *ids, int id) return out; } +struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, int id) +{ + struct kern_ipc_perm *out; + + out = ipc_lock_down(ids, id); + if (IS_ERR(out)) + return out; + + if (ipc_checkid(out, id)) { + ipc_unlock(out); + return ERR_PTR(-EIDRM); + } + + return out; +} + +struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id) +{ + struct kern_ipc_perm *out; + + out = ipc_lock(ids, id); + if (IS_ERR(out)) + return out; + + if (ipc_checkid(out, id)) { + ipc_unlock(out); + return ERR_PTR(-EIDRM); + } + + return out; +} + +/** + * ipcget - Common sys_*get() code + * @ns : namsepace + * @ids : IPC identifier set + * @ops : operations to be called on ipc object creation, permission checks + * and further checks + * @params : the parameters needed by the previous operations. + * + * Common routine called by sys_msgget(), sys_semget() and sys_shmget(). + */ +int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, + struct ipc_ops *ops, struct ipc_params *params) +{ + if (params->key == IPC_PRIVATE) + return ipcget_new(ns, ids, ops, params); + else + return ipcget_public(ns, ids, ops, params); +} + #ifdef __ARCH_WANT_IPC_PARSE_VERSION @@ -802,8 +794,8 @@ struct ipc_proc_iter { /* * This routine locks the ipc structure found at least at position pos. */ -struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, - loff_t *new_pos) +static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos, + loff_t *new_pos) { struct kern_ipc_perm *ipc; int total, id; @@ -841,7 +833,7 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos) if (ipc && ipc != SEQ_START_TOKEN) ipc_unlock(ipc); - return sysvipc_find_ipc(iter->ns->ids[iface->ids], *pos, pos); + return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos); } /* @@ -854,7 +846,7 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos) struct ipc_proc_iface *iface = iter->iface; struct ipc_ids *ids; - ids = iter->ns->ids[iface->ids]; + ids = &iter->ns->ids[iface->ids]; /* * Take the lock - this will be released by the corresponding @@ -885,7 +877,7 @@ static void sysvipc_proc_stop(struct seq_file *s, void *it) if (ipc && ipc != SEQ_START_TOKEN) ipc_unlock(ipc); - ids = iter->ns->ids[iface->ids]; + ids = &iter->ns->ids[iface->ids]; /* Release the lock we took in start() */ up_read(&ids->rw_mutex); } diff --git a/ipc/util.h b/ipc/util.h index 9ffea40457ce..f37d160c98fe 100644 --- a/ipc/util.h +++ b/ipc/util.h @@ -10,7 +10,6 @@ #ifndef _IPC_UTIL_H #define _IPC_UTIL_H -#include <linux/idr.h> #include <linux/err.h> #define USHRT_MAX 0xffff @@ -20,22 +19,16 @@ void sem_init (void); void msg_init (void); void shm_init (void); -int sem_init_ns(struct ipc_namespace *ns); -int msg_init_ns(struct ipc_namespace *ns); -int shm_init_ns(struct ipc_namespace *ns); +struct ipc_namespace; + +void sem_init_ns(struct ipc_namespace *ns); +void msg_init_ns(struct ipc_namespace *ns); +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); -struct ipc_ids { - int in_use; - unsigned short seq; - unsigned short seq_max; - struct rw_semaphore rw_mutex; - struct idr ipcs_idr; -}; - /* * Structure that holds the parameters needed by the ipc operations * (see after) @@ -66,6 +59,7 @@ struct ipc_ops { }; struct seq_file; +struct ipc_ids; void ipc_init_ids(struct ipc_ids *); #ifdef CONFIG_PROC_FS @@ -129,10 +123,6 @@ int ipc_parse_version (int *cmd); extern void free_msg(struct msg_msg *msg); extern struct msg_msg *load_msg(const void __user *src, int len); extern int store_msg(void __user *dest, struct msg_msg *msg, int len); -extern int ipcget_new(struct ipc_namespace *, struct ipc_ids *, - struct ipc_ops *, struct ipc_params *); -extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *, - struct ipc_ops *, struct ipc_params *); static inline int ipc_buildid(int id, int seq) { @@ -161,57 +151,9 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm) rcu_read_unlock(); } -static inline struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, - int id) -{ - struct kern_ipc_perm *out; - - out = ipc_lock_down(ids, id); - if (IS_ERR(out)) - return out; - - if (ipc_checkid(out, id)) { - ipc_unlock(out); - return ERR_PTR(-EIDRM); - } - - return out; -} - -static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, - int id) -{ - struct kern_ipc_perm *out; - - out = ipc_lock(ids, id); - if (IS_ERR(out)) - return out; - - if (ipc_checkid(out, id)) { - ipc_unlock(out); - return ERR_PTR(-EIDRM); - } - - return out; -} - -/** - * ipcget - Common sys_*get() code - * @ns : namsepace - * @ids : IPC identifier set - * @ops : operations to be called on ipc object creation, permission checks - * and further checks - * @params : the parameters needed by the previous operations. - * - * Common routine called by sys_msgget(), sys_semget() and sys_shmget(). - */ -static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, - struct ipc_ops *ops, struct ipc_params *params) -{ - if (params->key == IPC_PRIVATE) - return ipcget_new(ns, ids, ops, params); - else - return ipcget_public(ns, ids, ops, params); -} +struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, int id); +struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id); +int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids, + struct ipc_ops *ops, struct ipc_params *params); #endif |