aboutsummaryrefslogtreecommitdiffstats
path: root/ipc
diff options
context:
space:
mode:
Diffstat (limited to 'ipc')
-rw-r--r--ipc/Makefile1
-rw-r--r--ipc/ipc_sysctl.c1
-rw-r--r--ipc/mqueue.c5
-rw-r--r--ipc/msg.c57
-rw-r--r--ipc/namespace.c86
-rw-r--r--ipc/sem.c94
-rw-r--r--ipc/shm.c56
-rw-r--r--ipc/util.c122
-rw-r--r--ipc/util.h78
9 files changed, 210 insertions, 290 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
7obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o 7obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o
8obj_mq-$(CONFIG_COMPAT) += compat_mq.o 8obj_mq-$(CONFIG_COMPAT) += compat_mq.o
9obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) 9obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y)
10obj-$(CONFIG_IPC_NS) += namespace.o
10 11
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 @@
14#include <linux/nsproxy.h> 14#include <linux/nsproxy.h>
15#include <linux/sysctl.h> 15#include <linux/sysctl.h>
16#include <linux/uaccess.h> 16#include <linux/uaccess.h>
17#include <linux/ipc_namespace.h>
17 18
18static void *get_ipc(ctl_table *table) 19static void *get_ipc(ctl_table *table)
19{ 20{
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,
332 (info->notify_owner && 332 (info->notify_owner &&
333 info->notify.sigev_notify == SIGEV_SIGNAL) ? 333 info->notify.sigev_notify == SIGEV_SIGNAL) ?
334 info->notify.sigev_signo : 0, 334 info->notify.sigev_signo : 0,
335 pid_nr_ns(info->notify_owner, 335 pid_vnr(info->notify_owner));
336 current->nsproxy->pid_ns));
337 spin_unlock(&info->lock); 336 spin_unlock(&info->lock);
338 buffer[sizeof(buffer)-1] = '\0'; 337 buffer[sizeof(buffer)-1] = '\0';
339 slen = strlen(buffer)+1; 338 slen = strlen(buffer)+1;
@@ -510,7 +509,7 @@ static void __do_notify(struct mqueue_inode_info *info)
510 sig_i.si_errno = 0; 509 sig_i.si_errno = 0;
511 sig_i.si_code = SI_MESGQ; 510 sig_i.si_code = SI_MESGQ;
512 sig_i.si_value = info->notify.sigev_value; 511 sig_i.si_value = info->notify.sigev_value;
513 sig_i.si_pid = task_pid_vnr(current); 512 sig_i.si_pid = task_tgid_vnr(current);
514 sig_i.si_uid = current->uid; 513 sig_i.si_uid = current->uid;
515 514
516 kill_pid_info(info->notify.sigev_signo, 515 kill_pid_info(info->notify.sigev_signo,
diff --git a/ipc/msg.c b/ipc/msg.c
index ec0c724054b9..46585a05473e 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -36,6 +36,7 @@
36#include <linux/seq_file.h> 36#include <linux/seq_file.h>
37#include <linux/rwsem.h> 37#include <linux/rwsem.h>
38#include <linux/nsproxy.h> 38#include <linux/nsproxy.h>
39#include <linux/ipc_namespace.h>
39 40
40#include <asm/current.h> 41#include <asm/current.h>
41#include <asm/uaccess.h> 42#include <asm/uaccess.h>
@@ -66,72 +67,37 @@ struct msg_sender {
66#define SEARCH_NOTEQUAL 3 67#define SEARCH_NOTEQUAL 3
67#define SEARCH_LESSEQUAL 4 68#define SEARCH_LESSEQUAL 4
68 69
69static struct ipc_ids init_msg_ids; 70#define msg_ids(ns) ((ns)->ids[IPC_MSG_IDS])
70
71#define msg_ids(ns) (*((ns)->ids[IPC_MSG_IDS]))
72 71
73#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm) 72#define msg_unlock(msq) ipc_unlock(&(msq)->q_perm)
74#define msg_buildid(id, seq) ipc_buildid(id, seq) 73#define msg_buildid(id, seq) ipc_buildid(id, seq)
75 74
76static void freeque(struct ipc_namespace *, struct msg_queue *); 75static void freeque(struct ipc_namespace *, struct kern_ipc_perm *);
77static int newque(struct ipc_namespace *, struct ipc_params *); 76static int newque(struct ipc_namespace *, struct ipc_params *);
78#ifdef CONFIG_PROC_FS 77#ifdef CONFIG_PROC_FS
79static int sysvipc_msg_proc_show(struct seq_file *s, void *it); 78static int sysvipc_msg_proc_show(struct seq_file *s, void *it);
80#endif 79#endif
81 80
82static void __msg_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) 81void msg_init_ns(struct ipc_namespace *ns)
83{ 82{
84 ns->ids[IPC_MSG_IDS] = ids;
85 ns->msg_ctlmax = MSGMAX; 83 ns->msg_ctlmax = MSGMAX;
86 ns->msg_ctlmnb = MSGMNB; 84 ns->msg_ctlmnb = MSGMNB;
87 ns->msg_ctlmni = MSGMNI; 85 ns->msg_ctlmni = MSGMNI;
88 atomic_set(&ns->msg_bytes, 0); 86 atomic_set(&ns->msg_bytes, 0);
89 atomic_set(&ns->msg_hdrs, 0); 87 atomic_set(&ns->msg_hdrs, 0);
90 ipc_init_ids(ids); 88 ipc_init_ids(&ns->ids[IPC_MSG_IDS]);
91}
92
93int msg_init_ns(struct ipc_namespace *ns)
94{
95 struct ipc_ids *ids;
96
97 ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
98 if (ids == NULL)
99 return -ENOMEM;
100
101 __msg_init_ns(ns, ids);
102 return 0;
103} 89}
104 90
91#ifdef CONFIG_IPC_NS
105void msg_exit_ns(struct ipc_namespace *ns) 92void msg_exit_ns(struct ipc_namespace *ns)
106{ 93{
107 struct msg_queue *msq; 94 free_ipcs(ns, &msg_ids(ns), freeque);
108 struct kern_ipc_perm *perm;
109 int next_id;
110 int total, in_use;
111
112 down_write(&msg_ids(ns).rw_mutex);
113
114 in_use = msg_ids(ns).in_use;
115
116 for (total = 0, next_id = 0; total < in_use; next_id++) {
117 perm = idr_find(&msg_ids(ns).ipcs_idr, next_id);
118 if (perm == NULL)
119 continue;
120 ipc_lock_by_ptr(perm);
121 msq = container_of(perm, struct msg_queue, q_perm);
122 freeque(ns, msq);
123 total++;
124 }
125
126 up_write(&msg_ids(ns).rw_mutex);
127
128 kfree(ns->ids[IPC_MSG_IDS]);
129 ns->ids[IPC_MSG_IDS] = NULL;
130} 95}
96#endif
131 97
132void __init msg_init(void) 98void __init msg_init(void)
133{ 99{
134 __msg_init_ns(&init_ipc_ns, &init_msg_ids); 100 msg_init_ns(&init_ipc_ns);
135 ipc_init_proc_interface("sysvipc/msg", 101 ipc_init_proc_interface("sysvipc/msg",
136 " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n", 102 " key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
137 IPC_MSG_IDS, sysvipc_msg_proc_show); 103 IPC_MSG_IDS, sysvipc_msg_proc_show);
@@ -289,9 +255,10 @@ static void expunge_all(struct msg_queue *msq, int res)
289 * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held 255 * msg_ids.rw_mutex (writer) and the spinlock for this message queue are held
290 * before freeque() is called. msg_ids.rw_mutex remains locked on exit. 256 * before freeque() is called. msg_ids.rw_mutex remains locked on exit.
291 */ 257 */
292static void freeque(struct ipc_namespace *ns, struct msg_queue *msq) 258static void freeque(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
293{ 259{
294 struct list_head *tmp; 260 struct list_head *tmp;
261 struct msg_queue *msq = container_of(ipcp, struct msg_queue, q_perm);
295 262
296 expunge_all(msq, -EIDRM); 263 expunge_all(msq, -EIDRM);
297 ss_wakeup(&msq->q_senders, 1); 264 ss_wakeup(&msq->q_senders, 1);
@@ -597,7 +564,7 @@ asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf)
597 break; 564 break;
598 } 565 }
599 case IPC_RMID: 566 case IPC_RMID:
600 freeque(ns, msq); 567 freeque(ns, &msq->q_perm);
601 break; 568 break;
602 } 569 }
603 err = 0; 570 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 @@
1/*
2 * linux/ipc/namespace.c
3 * Copyright (C) 2006 Pavel Emelyanov <xemul@openvz.org> OpenVZ, SWsoft Inc.
4 */
5
6#include <linux/ipc.h>
7#include <linux/msg.h>
8#include <linux/ipc_namespace.h>
9#include <linux/rcupdate.h>
10#include <linux/nsproxy.h>
11#include <linux/slab.h>
12
13#include "util.h"
14
15static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
16{
17 struct ipc_namespace *ns;
18
19 ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
20 if (ns == NULL)
21 return ERR_PTR(-ENOMEM);
22
23 sem_init_ns(ns);
24 msg_init_ns(ns);
25 shm_init_ns(ns);
26
27 kref_init(&ns->kref);
28 return ns;
29}
30
31struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
32{
33 struct ipc_namespace *new_ns;
34
35 BUG_ON(!ns);
36 get_ipc_ns(ns);
37
38 if (!(flags & CLONE_NEWIPC))
39 return ns;
40
41 new_ns = clone_ipc_ns(ns);
42
43 put_ipc_ns(ns);
44 return new_ns;
45}
46
47/*
48 * free_ipcs - free all ipcs of one type
49 * @ns: the namespace to remove the ipcs from
50 * @ids: the table of ipcs to free
51 * @free: the function called to free each individual ipc
52 *
53 * Called for each kind of ipc when an ipc_namespace exits.
54 */
55void free_ipcs(struct ipc_namespace *ns, struct ipc_ids *ids,
56 void (*free)(struct ipc_namespace *, struct kern_ipc_perm *))
57{
58 struct kern_ipc_perm *perm;
59 int next_id;
60 int total, in_use;
61
62 down_write(&ids->rw_mutex);
63
64 in_use = ids->in_use;
65
66 for (total = 0, next_id = 0; total < in_use; next_id++) {
67 perm = idr_find(&ids->ipcs_idr, next_id);
68 if (perm == NULL)
69 continue;
70 ipc_lock_by_ptr(perm);
71 free(ns, perm);
72 total++;
73 }
74 up_write(&ids->rw_mutex);
75}
76
77void free_ipc_ns(struct kref *kref)
78{
79 struct ipc_namespace *ns;
80
81 ns = container_of(kref, struct ipc_namespace, kref);
82 sem_exit_ns(ns);
83 msg_exit_ns(ns);
84 shm_exit_ns(ns);
85 kfree(ns);
86}
diff --git a/ipc/sem.c b/ipc/sem.c
index d65e285b7e30..0b45a4d383c6 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -82,20 +82,19 @@
82#include <linux/seq_file.h> 82#include <linux/seq_file.h>
83#include <linux/rwsem.h> 83#include <linux/rwsem.h>
84#include <linux/nsproxy.h> 84#include <linux/nsproxy.h>
85#include <linux/ipc_namespace.h>
85 86
86#include <asm/uaccess.h> 87#include <asm/uaccess.h>
87#include "util.h" 88#include "util.h"
88 89
89#define sem_ids(ns) (*((ns)->ids[IPC_SEM_IDS])) 90#define sem_ids(ns) ((ns)->ids[IPC_SEM_IDS])
90 91
91#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) 92#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
92#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid) 93#define sem_checkid(sma, semid) ipc_checkid(&sma->sem_perm, semid)
93#define sem_buildid(id, seq) ipc_buildid(id, seq) 94#define sem_buildid(id, seq) ipc_buildid(id, seq)
94 95
95static struct ipc_ids init_sem_ids;
96
97static int newary(struct ipc_namespace *, struct ipc_params *); 96static int newary(struct ipc_namespace *, struct ipc_params *);
98static void freeary(struct ipc_namespace *, struct sem_array *); 97static void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
99#ifdef CONFIG_PROC_FS 98#ifdef CONFIG_PROC_FS
100static int sysvipc_sem_proc_show(struct seq_file *s, void *it); 99static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
101#endif 100#endif
@@ -117,58 +116,26 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
117#define sc_semopm sem_ctls[2] 116#define sc_semopm sem_ctls[2]
118#define sc_semmni sem_ctls[3] 117#define sc_semmni sem_ctls[3]
119 118
120static void __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) 119void sem_init_ns(struct ipc_namespace *ns)
121{ 120{
122 ns->ids[IPC_SEM_IDS] = ids;
123 ns->sc_semmsl = SEMMSL; 121 ns->sc_semmsl = SEMMSL;
124 ns->sc_semmns = SEMMNS; 122 ns->sc_semmns = SEMMNS;
125 ns->sc_semopm = SEMOPM; 123 ns->sc_semopm = SEMOPM;
126 ns->sc_semmni = SEMMNI; 124 ns->sc_semmni = SEMMNI;
127 ns->used_sems = 0; 125 ns->used_sems = 0;
128 ipc_init_ids(ids); 126 ipc_init_ids(&ns->ids[IPC_SEM_IDS]);
129}
130
131int sem_init_ns(struct ipc_namespace *ns)
132{
133 struct ipc_ids *ids;
134
135 ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
136 if (ids == NULL)
137 return -ENOMEM;
138
139 __sem_init_ns(ns, ids);
140 return 0;
141} 127}
142 128
129#ifdef CONFIG_IPC_NS
143void sem_exit_ns(struct ipc_namespace *ns) 130void sem_exit_ns(struct ipc_namespace *ns)
144{ 131{
145 struct sem_array *sma; 132 free_ipcs(ns, &sem_ids(ns), freeary);
146 struct kern_ipc_perm *perm;
147 int next_id;
148 int total, in_use;
149
150 down_write(&sem_ids(ns).rw_mutex);
151
152 in_use = sem_ids(ns).in_use;
153
154 for (total = 0, next_id = 0; total < in_use; next_id++) {
155 perm = idr_find(&sem_ids(ns).ipcs_idr, next_id);
156 if (perm == NULL)
157 continue;
158 ipc_lock_by_ptr(perm);
159 sma = container_of(perm, struct sem_array, sem_perm);
160 freeary(ns, sma);
161 total++;
162 }
163 up_write(&sem_ids(ns).rw_mutex);
164
165 kfree(ns->ids[IPC_SEM_IDS]);
166 ns->ids[IPC_SEM_IDS] = NULL;
167} 133}
134#endif
168 135
169void __init sem_init (void) 136void __init sem_init (void)
170{ 137{
171 __sem_init_ns(&init_ipc_ns, &init_sem_ids); 138 sem_init_ns(&init_ipc_ns);
172 ipc_init_proc_interface("sysvipc/sem", 139 ipc_init_proc_interface("sysvipc/sem",
173 " key semid perms nsems uid gid cuid cgid otime ctime\n", 140 " key semid perms nsems uid gid cuid cgid otime ctime\n",
174 IPC_SEM_IDS, sysvipc_sem_proc_show); 141 IPC_SEM_IDS, sysvipc_sem_proc_show);
@@ -557,10 +524,11 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
557 * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex 524 * as a writer and the spinlock for this semaphore set hold. sem_ids.rw_mutex
558 * remains locked on exit. 525 * remains locked on exit.
559 */ 526 */
560static void freeary(struct ipc_namespace *ns, struct sem_array *sma) 527static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
561{ 528{
562 struct sem_undo *un; 529 struct sem_undo *un;
563 struct sem_queue *q; 530 struct sem_queue *q;
531 struct sem_array *sma = container_of(ipcp, struct sem_array, sem_perm);
564 532
565 /* Invalidate the existing undo structures for this semaphore set. 533 /* Invalidate the existing undo structures for this semaphore set.
566 * (They will be freed without any further action in exit_sem() 534 * (They will be freed without any further action in exit_sem()
@@ -614,8 +582,8 @@ static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in,
614 } 582 }
615} 583}
616 584
617static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, 585static int semctl_nolock(struct ipc_namespace *ns, int semid,
618 int cmd, int version, union semun arg) 586 int cmd, int version, union semun arg)
619{ 587{
620 int err = -EINVAL; 588 int err = -EINVAL;
621 struct sem_array *sma; 589 struct sem_array *sma;
@@ -654,14 +622,23 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
654 return -EFAULT; 622 return -EFAULT;
655 return (max_id < 0) ? 0: max_id; 623 return (max_id < 0) ? 0: max_id;
656 } 624 }
625 case IPC_STAT:
657 case SEM_STAT: 626 case SEM_STAT:
658 { 627 {
659 struct semid64_ds tbuf; 628 struct semid64_ds tbuf;
660 int id; 629 int id;
661 630
662 sma = sem_lock(ns, semid); 631 if (cmd == SEM_STAT) {
663 if (IS_ERR(sma)) 632 sma = sem_lock(ns, semid);
664 return PTR_ERR(sma); 633 if (IS_ERR(sma))
634 return PTR_ERR(sma);
635 id = sma->sem_perm.id;
636 } else {
637 sma = sem_lock_check(ns, semid);
638 if (IS_ERR(sma))
639 return PTR_ERR(sma);
640 id = 0;
641 }
665 642
666 err = -EACCES; 643 err = -EACCES;
667 if (ipcperms (&sma->sem_perm, S_IRUGO)) 644 if (ipcperms (&sma->sem_perm, S_IRUGO))
@@ -671,8 +648,6 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
671 if (err) 648 if (err)
672 goto out_unlock; 649 goto out_unlock;
673 650
674 id = sma->sem_perm.id;
675
676 memset(&tbuf, 0, sizeof(tbuf)); 651 memset(&tbuf, 0, sizeof(tbuf));
677 652
678 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); 653 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
@@ -807,19 +782,6 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
807 err = 0; 782 err = 0;
808 goto out_unlock; 783 goto out_unlock;
809 } 784 }
810 case IPC_STAT:
811 {
812 struct semid64_ds tbuf;
813 memset(&tbuf,0,sizeof(tbuf));
814 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
815 tbuf.sem_otime = sma->sem_otime;
816 tbuf.sem_ctime = sma->sem_ctime;
817 tbuf.sem_nsems = sma->sem_nsems;
818 sem_unlock(sma);
819 if (copy_semid_to_user (arg.buf, &tbuf, version))
820 return -EFAULT;
821 return 0;
822 }
823 /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */ 785 /* GETVAL, GETPID, GETNCTN, GETZCNT, SETVAL: fall-through */
824 } 786 }
825 err = -EINVAL; 787 err = -EINVAL;
@@ -947,7 +909,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
947 909
948 switch(cmd){ 910 switch(cmd){
949 case IPC_RMID: 911 case IPC_RMID:
950 freeary(ns, sma); 912 freeary(ns, ipcp);
951 err = 0; 913 err = 0;
952 break; 914 break;
953 case IPC_SET: 915 case IPC_SET:
@@ -986,15 +948,15 @@ asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg)
986 switch(cmd) { 948 switch(cmd) {
987 case IPC_INFO: 949 case IPC_INFO:
988 case SEM_INFO: 950 case SEM_INFO:
951 case IPC_STAT:
989 case SEM_STAT: 952 case SEM_STAT:
990 err = semctl_nolock(ns,semid,semnum,cmd,version,arg); 953 err = semctl_nolock(ns, semid, cmd, version, arg);
991 return err; 954 return err;
992 case GETALL: 955 case GETALL:
993 case GETVAL: 956 case GETVAL:
994 case GETPID: 957 case GETPID:
995 case GETNCNT: 958 case GETNCNT:
996 case GETZCNT: 959 case GETZCNT:
997 case IPC_STAT:
998 case SETVAL: 960 case SETVAL:
999 case SETALL: 961 case SETALL:
1000 err = semctl_main(ns,semid,semnum,cmd,version,arg); 962 err = semctl_main(ns,semid,semnum,cmd,version,arg);
diff --git a/ipc/shm.c b/ipc/shm.c
index 65c3a294aba5..c47e87278a92 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -38,6 +38,7 @@
38#include <linux/rwsem.h> 38#include <linux/rwsem.h>
39#include <linux/nsproxy.h> 39#include <linux/nsproxy.h>
40#include <linux/mount.h> 40#include <linux/mount.h>
41#include <linux/ipc_namespace.h>
41 42
42#include <asm/uaccess.h> 43#include <asm/uaccess.h>
43 44
@@ -55,9 +56,7 @@ struct shm_file_data {
55static const struct file_operations shm_file_operations; 56static const struct file_operations shm_file_operations;
56static struct vm_operations_struct shm_vm_ops; 57static struct vm_operations_struct shm_vm_ops;
57 58
58static struct ipc_ids init_shm_ids; 59#define shm_ids(ns) ((ns)->ids[IPC_SHM_IDS])
59
60#define shm_ids(ns) (*((ns)->ids[IPC_SHM_IDS]))
61 60
62#define shm_unlock(shp) \ 61#define shm_unlock(shp) \
63 ipc_unlock(&(shp)->shm_perm) 62 ipc_unlock(&(shp)->shm_perm)
@@ -71,22 +70,24 @@ static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
71static int sysvipc_shm_proc_show(struct seq_file *s, void *it); 70static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
72#endif 71#endif
73 72
74static void __shm_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) 73void shm_init_ns(struct ipc_namespace *ns)
75{ 74{
76 ns->ids[IPC_SHM_IDS] = ids;
77 ns->shm_ctlmax = SHMMAX; 75 ns->shm_ctlmax = SHMMAX;
78 ns->shm_ctlall = SHMALL; 76 ns->shm_ctlall = SHMALL;
79 ns->shm_ctlmni = SHMMNI; 77 ns->shm_ctlmni = SHMMNI;
80 ns->shm_tot = 0; 78 ns->shm_tot = 0;
81 ipc_init_ids(ids); 79 ipc_init_ids(&ns->ids[IPC_SHM_IDS]);
82} 80}
83 81
84/* 82/*
85 * Called with shm_ids.rw_mutex (writer) and the shp structure locked. 83 * Called with shm_ids.rw_mutex (writer) and the shp structure locked.
86 * Only shm_ids.rw_mutex remains locked on exit. 84 * Only shm_ids.rw_mutex remains locked on exit.
87 */ 85 */
88static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp) 86static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
89{ 87{
88 struct shmid_kernel *shp;
89 shp = container_of(ipcp, struct shmid_kernel, shm_perm);
90
90 if (shp->shm_nattch){ 91 if (shp->shm_nattch){
91 shp->shm_perm.mode |= SHM_DEST; 92 shp->shm_perm.mode |= SHM_DEST;
92 /* Do not find it any more */ 93 /* Do not find it any more */
@@ -96,47 +97,16 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct shmid_kernel *shp)
96 shm_destroy(ns, shp); 97 shm_destroy(ns, shp);
97} 98}
98 99
99int shm_init_ns(struct ipc_namespace *ns) 100#ifdef CONFIG_IPC_NS
100{
101 struct ipc_ids *ids;
102
103 ids = kmalloc(sizeof(struct ipc_ids), GFP_KERNEL);
104 if (ids == NULL)
105 return -ENOMEM;
106
107 __shm_init_ns(ns, ids);
108 return 0;
109}
110
111void shm_exit_ns(struct ipc_namespace *ns) 101void shm_exit_ns(struct ipc_namespace *ns)
112{ 102{
113 struct shmid_kernel *shp; 103 free_ipcs(ns, &shm_ids(ns), do_shm_rmid);
114 struct kern_ipc_perm *perm;
115 int next_id;
116 int total, in_use;
117
118 down_write(&shm_ids(ns).rw_mutex);
119
120 in_use = shm_ids(ns).in_use;
121
122 for (total = 0, next_id = 0; total < in_use; next_id++) {
123 perm = idr_find(&shm_ids(ns).ipcs_idr, next_id);
124 if (perm == NULL)
125 continue;
126 ipc_lock_by_ptr(perm);
127 shp = container_of(perm, struct shmid_kernel, shm_perm);
128 do_shm_rmid(ns, shp);
129 total++;
130 }
131 up_write(&shm_ids(ns).rw_mutex);
132
133 kfree(ns->ids[IPC_SHM_IDS]);
134 ns->ids[IPC_SHM_IDS] = NULL;
135} 104}
105#endif
136 106
137void __init shm_init (void) 107void __init shm_init (void)
138{ 108{
139 __shm_init_ns(&init_ipc_ns, &init_shm_ids); 109 shm_init_ns(&init_ipc_ns);
140 ipc_init_proc_interface("sysvipc/shm", 110 ipc_init_proc_interface("sysvipc/shm",
141 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n", 111 " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n",
142 IPC_SHM_IDS, sysvipc_shm_proc_show); 112 IPC_SHM_IDS, sysvipc_shm_proc_show);
@@ -847,7 +817,7 @@ asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
847 if (err) 817 if (err)
848 goto out_unlock_up; 818 goto out_unlock_up;
849 819
850 do_shm_rmid(ns, shp); 820 do_shm_rmid(ns, &shp->shm_perm);
851 up_write(&shm_ids(ns).rw_mutex); 821 up_write(&shm_ids(ns).rw_mutex);
852 goto out; 822 goto out;
853 } 823 }
diff --git a/ipc/util.c b/ipc/util.c
index 76c1f3461e22..fd1b50da9db8 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -33,6 +33,7 @@
33#include <linux/audit.h> 33#include <linux/audit.h>
34#include <linux/nsproxy.h> 34#include <linux/nsproxy.h>
35#include <linux/rwsem.h> 35#include <linux/rwsem.h>
36#include <linux/ipc_namespace.h>
36 37
37#include <asm/unistd.h> 38#include <asm/unistd.h>
38 39
@@ -51,66 +52,6 @@ struct ipc_namespace init_ipc_ns = {
51 }, 52 },
52}; 53};
53 54
54static struct ipc_namespace *clone_ipc_ns(struct ipc_namespace *old_ns)
55{
56 int err;
57 struct ipc_namespace *ns;
58
59 err = -ENOMEM;
60 ns = kmalloc(sizeof(struct ipc_namespace), GFP_KERNEL);
61 if (ns == NULL)
62 goto err_mem;
63
64 err = sem_init_ns(ns);
65 if (err)
66 goto err_sem;
67 err = msg_init_ns(ns);
68 if (err)
69 goto err_msg;
70 err = shm_init_ns(ns);
71 if (err)
72 goto err_shm;
73
74 kref_init(&ns->kref);
75 return ns;
76
77err_shm:
78 msg_exit_ns(ns);
79err_msg:
80 sem_exit_ns(ns);
81err_sem:
82 kfree(ns);
83err_mem:
84 return ERR_PTR(err);
85}
86
87struct ipc_namespace *copy_ipcs(unsigned long flags, struct ipc_namespace *ns)
88{
89 struct ipc_namespace *new_ns;
90
91 BUG_ON(!ns);
92 get_ipc_ns(ns);
93
94 if (!(flags & CLONE_NEWIPC))
95 return ns;
96
97 new_ns = clone_ipc_ns(ns);
98
99 put_ipc_ns(ns);
100 return new_ns;
101}
102
103void free_ipc_ns(struct kref *kref)
104{
105 struct ipc_namespace *ns;
106
107 ns = container_of(kref, struct ipc_namespace, kref);
108 sem_exit_ns(ns);
109 msg_exit_ns(ns);
110 shm_exit_ns(ns);
111 kfree(ns);
112}
113
114/** 55/**
115 * ipc_init - initialise IPC subsystem 56 * ipc_init - initialise IPC subsystem
116 * 57 *
@@ -307,7 +248,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
307 * This routine is called by sys_msgget, sys_semget() and sys_shmget() 248 * This routine is called by sys_msgget, sys_semget() and sys_shmget()
308 * when the key is IPC_PRIVATE. 249 * when the key is IPC_PRIVATE.
309 */ 250 */
310int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids, 251static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
311 struct ipc_ops *ops, struct ipc_params *params) 252 struct ipc_ops *ops, struct ipc_params *params)
312{ 253{
313 int err; 254 int err;
@@ -371,7 +312,7 @@ static int ipc_check_perms(struct kern_ipc_perm *ipcp, struct ipc_ops *ops,
371 * 312 *
372 * On success, the ipc id is returned. 313 * On success, the ipc id is returned.
373 */ 314 */
374int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids, 315static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
375 struct ipc_ops *ops, struct ipc_params *params) 316 struct ipc_ops *ops, struct ipc_params *params)
376{ 317{
377 struct kern_ipc_perm *ipcp; 318 struct kern_ipc_perm *ipcp;
@@ -769,6 +710,57 @@ struct kern_ipc_perm *ipc_lock_down(struct ipc_ids *ids, int id)
769 return out; 710 return out;
770} 711}
771 712
713struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, int id)
714{
715 struct kern_ipc_perm *out;
716
717 out = ipc_lock_down(ids, id);
718 if (IS_ERR(out))
719 return out;
720
721 if (ipc_checkid(out, id)) {
722 ipc_unlock(out);
723 return ERR_PTR(-EIDRM);
724 }
725
726 return out;
727}
728
729struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id)
730{
731 struct kern_ipc_perm *out;
732
733 out = ipc_lock(ids, id);
734 if (IS_ERR(out))
735 return out;
736
737 if (ipc_checkid(out, id)) {
738 ipc_unlock(out);
739 return ERR_PTR(-EIDRM);
740 }
741
742 return out;
743}
744
745/**
746 * ipcget - Common sys_*get() code
747 * @ns : namsepace
748 * @ids : IPC identifier set
749 * @ops : operations to be called on ipc object creation, permission checks
750 * and further checks
751 * @params : the parameters needed by the previous operations.
752 *
753 * Common routine called by sys_msgget(), sys_semget() and sys_shmget().
754 */
755int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
756 struct ipc_ops *ops, struct ipc_params *params)
757{
758 if (params->key == IPC_PRIVATE)
759 return ipcget_new(ns, ids, ops, params);
760 else
761 return ipcget_public(ns, ids, ops, params);
762}
763
772#ifdef __ARCH_WANT_IPC_PARSE_VERSION 764#ifdef __ARCH_WANT_IPC_PARSE_VERSION
773 765
774 766
@@ -841,7 +833,7 @@ static void *sysvipc_proc_next(struct seq_file *s, void *it, loff_t *pos)
841 if (ipc && ipc != SEQ_START_TOKEN) 833 if (ipc && ipc != SEQ_START_TOKEN)
842 ipc_unlock(ipc); 834 ipc_unlock(ipc);
843 835
844 return sysvipc_find_ipc(iter->ns->ids[iface->ids], *pos, pos); 836 return sysvipc_find_ipc(&iter->ns->ids[iface->ids], *pos, pos);
845} 837}
846 838
847/* 839/*
@@ -854,7 +846,7 @@ static void *sysvipc_proc_start(struct seq_file *s, loff_t *pos)
854 struct ipc_proc_iface *iface = iter->iface; 846 struct ipc_proc_iface *iface = iter->iface;
855 struct ipc_ids *ids; 847 struct ipc_ids *ids;
856 848
857 ids = iter->ns->ids[iface->ids]; 849 ids = &iter->ns->ids[iface->ids];
858 850
859 /* 851 /*
860 * Take the lock - this will be released by the corresponding 852 * 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)
885 if (ipc && ipc != SEQ_START_TOKEN) 877 if (ipc && ipc != SEQ_START_TOKEN)
886 ipc_unlock(ipc); 878 ipc_unlock(ipc);
887 879
888 ids = iter->ns->ids[iface->ids]; 880 ids = &iter->ns->ids[iface->ids];
889 /* Release the lock we took in start() */ 881 /* Release the lock we took in start() */
890 up_read(&ids->rw_mutex); 882 up_read(&ids->rw_mutex);
891} 883}
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 @@
10#ifndef _IPC_UTIL_H 10#ifndef _IPC_UTIL_H
11#define _IPC_UTIL_H 11#define _IPC_UTIL_H
12 12
13#include <linux/idr.h>
14#include <linux/err.h> 13#include <linux/err.h>
15 14
16#define USHRT_MAX 0xffff 15#define USHRT_MAX 0xffff
@@ -20,22 +19,16 @@ void sem_init (void);
20void msg_init (void); 19void msg_init (void);
21void shm_init (void); 20void shm_init (void);
22 21
23int sem_init_ns(struct ipc_namespace *ns); 22struct ipc_namespace;
24int msg_init_ns(struct ipc_namespace *ns); 23
25int shm_init_ns(struct ipc_namespace *ns); 24void sem_init_ns(struct ipc_namespace *ns);
25void msg_init_ns(struct ipc_namespace *ns);
26void shm_init_ns(struct ipc_namespace *ns);
26 27
27void sem_exit_ns(struct ipc_namespace *ns); 28void sem_exit_ns(struct ipc_namespace *ns);
28void msg_exit_ns(struct ipc_namespace *ns); 29void msg_exit_ns(struct ipc_namespace *ns);
29void shm_exit_ns(struct ipc_namespace *ns); 30void shm_exit_ns(struct ipc_namespace *ns);
30 31
31struct ipc_ids {
32 int in_use;
33 unsigned short seq;
34 unsigned short seq_max;
35 struct rw_semaphore rw_mutex;
36 struct idr ipcs_idr;
37};
38
39/* 32/*
40 * Structure that holds the parameters needed by the ipc operations 33 * Structure that holds the parameters needed by the ipc operations
41 * (see after) 34 * (see after)
@@ -66,6 +59,7 @@ struct ipc_ops {
66}; 59};
67 60
68struct seq_file; 61struct seq_file;
62struct ipc_ids;
69 63
70void ipc_init_ids(struct ipc_ids *); 64void ipc_init_ids(struct ipc_ids *);
71#ifdef CONFIG_PROC_FS 65#ifdef CONFIG_PROC_FS
@@ -129,10 +123,6 @@ int ipc_parse_version (int *cmd);
129extern void free_msg(struct msg_msg *msg); 123extern void free_msg(struct msg_msg *msg);
130extern struct msg_msg *load_msg(const void __user *src, int len); 124extern struct msg_msg *load_msg(const void __user *src, int len);
131extern int store_msg(void __user *dest, struct msg_msg *msg, int len); 125extern int store_msg(void __user *dest, struct msg_msg *msg, int len);
132extern int ipcget_new(struct ipc_namespace *, struct ipc_ids *,
133 struct ipc_ops *, struct ipc_params *);
134extern int ipcget_public(struct ipc_namespace *, struct ipc_ids *,
135 struct ipc_ops *, struct ipc_params *);
136 126
137static inline int ipc_buildid(int id, int seq) 127static inline int ipc_buildid(int id, int seq)
138{ 128{
@@ -161,57 +151,9 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm)
161 rcu_read_unlock(); 151 rcu_read_unlock();
162} 152}
163 153
164static inline struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, 154struct kern_ipc_perm *ipc_lock_check_down(struct ipc_ids *ids, int id);
165 int id) 155struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids, int id);
166{ 156int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
167 struct kern_ipc_perm *out; 157 struct ipc_ops *ops, struct ipc_params *params);
168
169 out = ipc_lock_down(ids, id);
170 if (IS_ERR(out))
171 return out;
172
173 if (ipc_checkid(out, id)) {
174 ipc_unlock(out);
175 return ERR_PTR(-EIDRM);
176 }
177
178 return out;
179}
180
181static inline struct kern_ipc_perm *ipc_lock_check(struct ipc_ids *ids,
182 int id)
183{
184 struct kern_ipc_perm *out;
185
186 out = ipc_lock(ids, id);
187 if (IS_ERR(out))
188 return out;
189
190 if (ipc_checkid(out, id)) {
191 ipc_unlock(out);
192 return ERR_PTR(-EIDRM);
193 }
194
195 return out;
196}
197
198/**
199 * ipcget - Common sys_*get() code
200 * @ns : namsepace
201 * @ids : IPC identifier set
202 * @ops : operations to be called on ipc object creation, permission checks
203 * and further checks
204 * @params : the parameters needed by the previous operations.
205 *
206 * Common routine called by sys_msgget(), sys_semget() and sys_shmget().
207 */
208static inline int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
209 struct ipc_ops *ops, struct ipc_params *params)
210{
211 if (params->key == IPC_PRIVATE)
212 return ipcget_new(ns, ids, ops, params);
213 else
214 return ipcget_public(ns, ids, ops, params);
215}
216 158
217#endif 159#endif