diff options
Diffstat (limited to 'ipc/sem.c')
-rw-r--r-- | ipc/sem.c | 94 |
1 files changed, 28 insertions, 66 deletions
@@ -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 | ||
95 | static struct ipc_ids init_sem_ids; | ||
96 | |||
97 | static int newary(struct ipc_namespace *, struct ipc_params *); | 96 | static int newary(struct ipc_namespace *, struct ipc_params *); |
98 | static void freeary(struct ipc_namespace *, struct sem_array *); | 97 | static void freeary(struct ipc_namespace *, struct kern_ipc_perm *); |
99 | #ifdef CONFIG_PROC_FS | 98 | #ifdef CONFIG_PROC_FS |
100 | static int sysvipc_sem_proc_show(struct seq_file *s, void *it); | 99 | static 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 | ||
120 | static void __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids) | 119 | void 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 | |||
131 | int 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 | ||
143 | void sem_exit_ns(struct ipc_namespace *ns) | 130 | void 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 | ||
169 | void __init sem_init (void) | 136 | void __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 | */ |
560 | static void freeary(struct ipc_namespace *ns, struct sem_array *sma) | 527 | static 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 | ||
617 | static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum, | 585 | static 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); |