aboutsummaryrefslogtreecommitdiffstats
path: root/ipc/sem.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/sem.c')
-rw-r--r--ipc/sem.c111
1 files changed, 65 insertions, 46 deletions
diff --git a/ipc/sem.c b/ipc/sem.c
index 64ff4261f4e2..f92a2565d12b 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -90,7 +90,6 @@
90 90
91#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id)) 91#define sem_lock(ns, id) ((struct sem_array*)ipc_lock(&sem_ids(ns), id))
92#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm) 92#define sem_unlock(sma) ipc_unlock(&(sma)->sem_perm)
93#define sem_rmid(ns, id) ((struct sem_array*)ipc_rmid(&sem_ids(ns), id))
94#define sem_checkid(ns, sma, semid) \ 93#define sem_checkid(ns, sma, semid) \
95 ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid) 94 ipc_checkid(&sem_ids(ns),&sma->sem_perm,semid)
96#define sem_buildid(ns, id, seq) \ 95#define sem_buildid(ns, id, seq) \
@@ -99,7 +98,7 @@
99static struct ipc_ids init_sem_ids; 98static struct ipc_ids init_sem_ids;
100 99
101static int newary(struct ipc_namespace *, key_t, int, int); 100static int newary(struct ipc_namespace *, key_t, int, int);
102static void freeary(struct ipc_namespace *ns, struct sem_array *sma, int id); 101static void freeary(struct ipc_namespace *, struct sem_array *);
103#ifdef CONFIG_PROC_FS 102#ifdef CONFIG_PROC_FS
104static int sysvipc_sem_proc_show(struct seq_file *s, void *it); 103static int sysvipc_sem_proc_show(struct seq_file *s, void *it);
105#endif 104#endif
@@ -129,7 +128,7 @@ static void __sem_init_ns(struct ipc_namespace *ns, struct ipc_ids *ids)
129 ns->sc_semopm = SEMOPM; 128 ns->sc_semopm = SEMOPM;
130 ns->sc_semmni = SEMMNI; 129 ns->sc_semmni = SEMMNI;
131 ns->used_sems = 0; 130 ns->used_sems = 0;
132 ipc_init_ids(ids, ns->sc_semmni); 131 ipc_init_ids(ids);
133} 132}
134 133
135int sem_init_ns(struct ipc_namespace *ns) 134int sem_init_ns(struct ipc_namespace *ns)
@@ -146,20 +145,24 @@ int sem_init_ns(struct ipc_namespace *ns)
146 145
147void sem_exit_ns(struct ipc_namespace *ns) 146void sem_exit_ns(struct ipc_namespace *ns)
148{ 147{
149 int i;
150 struct sem_array *sma; 148 struct sem_array *sma;
149 int next_id;
150 int total, in_use;
151 151
152 mutex_lock(&sem_ids(ns).mutex); 152 mutex_lock(&sem_ids(ns).mutex);
153 for (i = 0; i <= sem_ids(ns).max_id; i++) { 153
154 sma = sem_lock(ns, i); 154 in_use = sem_ids(ns).in_use;
155
156 for (total = 0, next_id = 0; total < in_use; next_id++) {
157 sma = idr_find(&sem_ids(ns).ipcs_idr, next_id);
155 if (sma == NULL) 158 if (sma == NULL)
156 continue; 159 continue;
157 160 ipc_lock_by_ptr(&sma->sem_perm);
158 freeary(ns, sma, i); 161 freeary(ns, sma);
162 total++;
159 } 163 }
160 mutex_unlock(&sem_ids(ns).mutex); 164 mutex_unlock(&sem_ids(ns).mutex);
161 165
162 ipc_fini_ids(ns->ids[IPC_SEM_IDS]);
163 kfree(ns->ids[IPC_SEM_IDS]); 166 kfree(ns->ids[IPC_SEM_IDS]);
164 ns->ids[IPC_SEM_IDS] = NULL; 167 ns->ids[IPC_SEM_IDS] = NULL;
165} 168}
@@ -172,6 +175,11 @@ void __init sem_init (void)
172 IPC_SEM_IDS, sysvipc_sem_proc_show); 175 IPC_SEM_IDS, sysvipc_sem_proc_show);
173} 176}
174 177
178static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
179{
180 ipc_rmid(&sem_ids(ns), &s->sem_perm);
181}
182
175/* 183/*
176 * Lockless wakeup algorithm: 184 * Lockless wakeup algorithm:
177 * Without the check/retry algorithm a lockless wakeup is possible: 185 * Without the check/retry algorithm a lockless wakeup is possible:
@@ -243,7 +251,7 @@ static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
243 } 251 }
244 ns->used_sems += nsems; 252 ns->used_sems += nsems;
245 253
246 sma->sem_id = sem_buildid(ns, id, sma->sem_perm.seq); 254 sma->sem_perm.id = sem_buildid(ns, id, sma->sem_perm.seq);
247 sma->sem_base = (struct sem *) &sma[1]; 255 sma->sem_base = (struct sem *) &sma[1];
248 /* sma->sem_pending = NULL; */ 256 /* sma->sem_pending = NULL; */
249 sma->sem_pending_last = &sma->sem_pending; 257 sma->sem_pending_last = &sma->sem_pending;
@@ -252,12 +260,12 @@ static int newary (struct ipc_namespace *ns, key_t key, int nsems, int semflg)
252 sma->sem_ctime = get_seconds(); 260 sma->sem_ctime = get_seconds();
253 sem_unlock(sma); 261 sem_unlock(sma);
254 262
255 return sma->sem_id; 263 return sma->sem_perm.id;
256} 264}
257 265
258asmlinkage long sys_semget (key_t key, int nsems, int semflg) 266asmlinkage long sys_semget (key_t key, int nsems, int semflg)
259{ 267{
260 int id, err = -EINVAL; 268 int err;
261 struct sem_array *sma; 269 struct sem_array *sma;
262 struct ipc_namespace *ns; 270 struct ipc_namespace *ns;
263 271
@@ -265,34 +273,50 @@ asmlinkage long sys_semget (key_t key, int nsems, int semflg)
265 273
266 if (nsems < 0 || nsems > ns->sc_semmsl) 274 if (nsems < 0 || nsems > ns->sc_semmsl)
267 return -EINVAL; 275 return -EINVAL;
268 mutex_lock(&sem_ids(ns).mutex); 276
269 277 err = idr_pre_get(&sem_ids(ns).ipcs_idr, GFP_KERNEL);
278
270 if (key == IPC_PRIVATE) { 279 if (key == IPC_PRIVATE) {
271 err = newary(ns, key, nsems, semflg); 280 if (!err)
272 } else if ((id = ipc_findkey(&sem_ids(ns), key)) == -1) { /* key not used */ 281 err = -ENOMEM;
273 if (!(semflg & IPC_CREAT)) 282 else {
274 err = -ENOENT; 283 mutex_lock(&sem_ids(ns).mutex);
275 else
276 err = newary(ns, key, nsems, semflg); 284 err = newary(ns, key, nsems, semflg);
277 } else if (semflg & IPC_CREAT && semflg & IPC_EXCL) { 285 mutex_unlock(&sem_ids(ns).mutex);
278 err = -EEXIST; 286 }
279 } else { 287 } else {
280 sma = sem_lock(ns, id); 288 mutex_lock(&sem_ids(ns).mutex);
281 BUG_ON(sma==NULL); 289 sma = (struct sem_array *) ipc_findkey(&sem_ids(ns), key);
282 if (nsems > sma->sem_nsems) 290 if (sma == NULL) {
283 err = -EINVAL; 291 /* key not used */
284 else if (ipcperms(&sma->sem_perm, semflg)) 292 if (!(semflg & IPC_CREAT))
285 err = -EACCES; 293 err = -ENOENT;
286 else { 294 else if (!err)
287 int semid = sem_buildid(ns, id, sma->sem_perm.seq); 295 err = -ENOMEM;
288 err = security_sem_associate(sma, semflg); 296 else
289 if (!err) 297 err = newary(ns, key, nsems, semflg);
290 err = semid; 298 } else {
299 /* sma has been locked by ipc_findkey() */
300
301 if (semflg & IPC_CREAT && semflg & IPC_EXCL)
302 err = -EEXIST;
303 else {
304 if (nsems > sma->sem_nsems)
305 err = -EINVAL;
306 else if (ipcperms(&sma->sem_perm, semflg))
307 err = -EACCES;
308 else {
309 err = security_sem_associate(sma,
310 semflg);
311 if (!err)
312 err = sma->sem_perm.id;
313 }
314 }
315 sem_unlock(sma);
291 } 316 }
292 sem_unlock(sma); 317 mutex_unlock(&sem_ids(ns).mutex);
293 } 318 }
294 319
295 mutex_unlock(&sem_ids(ns).mutex);
296 return err; 320 return err;
297} 321}
298 322
@@ -491,11 +515,10 @@ static int count_semzcnt (struct sem_array * sma, ushort semnum)
491 * the spinlock for this semaphore set hold. sem_ids.mutex remains locked 515 * the spinlock for this semaphore set hold. sem_ids.mutex remains locked
492 * on exit. 516 * on exit.
493 */ 517 */
494static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id) 518static void freeary(struct ipc_namespace *ns, struct sem_array *sma)
495{ 519{
496 struct sem_undo *un; 520 struct sem_undo *un;
497 struct sem_queue *q; 521 struct sem_queue *q;
498 int size;
499 522
500 /* Invalidate the existing undo structures for this semaphore set. 523 /* Invalidate the existing undo structures for this semaphore set.
501 * (They will be freed without any further action in exit_sem() 524 * (They will be freed without any further action in exit_sem()
@@ -518,12 +541,11 @@ static void freeary (struct ipc_namespace *ns, struct sem_array *sma, int id)
518 q = n; 541 q = n;
519 } 542 }
520 543
521 /* Remove the semaphore set from the ID array*/ 544 /* Remove the semaphore set from the IDR */
522 sma = sem_rmid(ns, id); 545 sem_rmid(ns, sma);
523 sem_unlock(sma); 546 sem_unlock(sma);
524 547
525 ns->used_sems -= sma->sem_nsems; 548 ns->used_sems -= sma->sem_nsems;
526 size = sizeof (*sma) + sma->sem_nsems * sizeof (struct sem);
527 security_sem_free(sma); 549 security_sem_free(sma);
528 ipc_rcu_putref(sma); 550 ipc_rcu_putref(sma);
529} 551}
@@ -584,7 +606,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
584 seminfo.semusz = SEMUSZ; 606 seminfo.semusz = SEMUSZ;
585 seminfo.semaem = SEMAEM; 607 seminfo.semaem = SEMAEM;
586 } 608 }
587 max_id = sem_ids(ns).max_id; 609 max_id = ipc_get_maxid(&sem_ids(ns));
588 mutex_unlock(&sem_ids(ns).mutex); 610 mutex_unlock(&sem_ids(ns).mutex);
589 if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo))) 611 if (copy_to_user (arg.__buf, &seminfo, sizeof(struct seminfo)))
590 return -EFAULT; 612 return -EFAULT;
@@ -595,9 +617,6 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
595 struct semid64_ds tbuf; 617 struct semid64_ds tbuf;
596 int id; 618 int id;
597 619
598 if(semid >= sem_ids(ns).entries->size)
599 return -EINVAL;
600
601 memset(&tbuf,0,sizeof(tbuf)); 620 memset(&tbuf,0,sizeof(tbuf));
602 621
603 sma = sem_lock(ns, semid); 622 sma = sem_lock(ns, semid);
@@ -612,7 +631,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid, int semnum,
612 if (err) 631 if (err)
613 goto out_unlock; 632 goto out_unlock;
614 633
615 id = sem_buildid(ns, semid, sma->sem_perm.seq); 634 id = sma->sem_perm.id;
616 635
617 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm); 636 kernel_to_ipc64_perm(&sma->sem_perm, &tbuf.sem_perm);
618 tbuf.sem_otime = sma->sem_otime; 637 tbuf.sem_otime = sma->sem_otime;
@@ -894,7 +913,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid, int semnum,
894 913
895 switch(cmd){ 914 switch(cmd){
896 case IPC_RMID: 915 case IPC_RMID:
897 freeary(ns, sma, semid); 916 freeary(ns, sma);
898 err = 0; 917 err = 0;
899 break; 918 break;
900 case IPC_SET: 919 case IPC_SET:
@@ -1402,7 +1421,7 @@ static int sysvipc_sem_proc_show(struct seq_file *s, void *it)
1402 return seq_printf(s, 1421 return seq_printf(s,
1403 "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n", 1422 "%10d %10d %4o %10lu %5u %5u %5u %5u %10lu %10lu\n",
1404 sma->sem_perm.key, 1423 sma->sem_perm.key,
1405 sma->sem_id, 1424 sma->sem_perm.id,
1406 sma->sem_perm.mode, 1425 sma->sem_perm.mode,
1407 sma->sem_nsems, 1426 sma->sem_nsems,
1408 sma->sem_perm.uid, 1427 sma->sem_perm.uid,