aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/sem.c')
-rw-r--r--ipc/sem.c94
1 files changed, 28 insertions, 66 deletions
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);