xref: /freebsd/sys/kern/sysv_sem.c (revision b52b9d56d4e96089873a75f9e29062eec19fabba)
1 /* $FreeBSD$ */
2 
3 /*
4  * Implementation of SVID semaphores
5  *
6  * Author:  Daniel Boulet
7  *
8  * This software is provided ``AS IS'' without any warranties of any kind.
9  */
10 
11 #include "opt_sysvipc.h"
12 
13 #include <sys/param.h>
14 #include <sys/systm.h>
15 #include <sys/sysproto.h>
16 #include <sys/kernel.h>
17 #include <sys/proc.h>
18 #include <sys/lock.h>
19 #include <sys/mutex.h>
20 #include <sys/sem.h>
21 #include <sys/syscall.h>
22 #include <sys/sysent.h>
23 #include <sys/sysctl.h>
24 #include <sys/malloc.h>
25 #include <sys/jail.h>
26 
27 static MALLOC_DEFINE(M_SEM, "sem", "SVID compatible semaphores");
28 
29 #ifdef SEM_DEBUG
30 #define DPRINTF(a)	printf a
31 #else
32 #define DPRINTF(a)
33 #endif
34 
35 static void seminit(void);
36 static int sysvsem_modload(struct module *, int, void *);
37 static int semunload(void);
38 static void semexit_myhook(struct proc *p);
39 static int sysctl_sema(SYSCTL_HANDLER_ARGS);
40 
41 #ifndef _SYS_SYSPROTO_H_
42 struct __semctl_args;
43 int __semctl(struct thread *td, struct __semctl_args *uap);
44 struct semget_args;
45 int semget(struct thread *td, struct semget_args *uap);
46 struct semop_args;
47 int semop(struct thread *td, struct semop_args *uap);
48 #endif
49 
50 static struct sem_undo *semu_alloc(struct thread *td);
51 static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
52 		int semid, int semnum, int adjval);
53 static void semundo_clear(int semid, int semnum);
54 
55 /* XXX casting to (sy_call_t *) is bogus, as usual. */
56 static sy_call_t *semcalls[] = {
57 	(sy_call_t *)__semctl, (sy_call_t *)semget,
58 	(sy_call_t *)semop
59 };
60 
61 static int	semtot = 0;
62 static struct semid_ds *sema;	/* semaphore id pool */
63 static struct sem *sem;		/* semaphore pool */
64 static struct sem_undo *semu_list; /* list of active undo structures */
65 static int	*semu;		/* undo structure pool */
66 
67 struct sem {
68 	u_short	semval;		/* semaphore value */
69 	pid_t	sempid;		/* pid of last operation */
70 	u_short	semncnt;	/* # awaiting semval > cval */
71 	u_short	semzcnt;	/* # awaiting semval = 0 */
72 };
73 
74 /*
75  * Undo structure (one per process)
76  */
77 struct sem_undo {
78 	struct	sem_undo *un_next;	/* ptr to next active undo structure */
79 	struct	proc *un_proc;		/* owner of this structure */
80 	short	un_cnt;			/* # of active entries */
81 	struct undo {
82 		short	un_adjval;	/* adjust on exit values */
83 		short	un_num;		/* semaphore # */
84 		int	un_id;		/* semid */
85 	} un_ent[1];			/* undo entries */
86 };
87 
88 /*
89  * Configuration parameters
90  */
91 #ifndef SEMMNI
92 #define SEMMNI	10		/* # of semaphore identifiers */
93 #endif
94 #ifndef SEMMNS
95 #define SEMMNS	60		/* # of semaphores in system */
96 #endif
97 #ifndef SEMUME
98 #define SEMUME	10		/* max # of undo entries per process */
99 #endif
100 #ifndef SEMMNU
101 #define SEMMNU	30		/* # of undo structures in system */
102 #endif
103 
104 /* shouldn't need tuning */
105 #ifndef SEMMAP
106 #define SEMMAP	30		/* # of entries in semaphore map */
107 #endif
108 #ifndef SEMMSL
109 #define SEMMSL	SEMMNS		/* max # of semaphores per id */
110 #endif
111 #ifndef SEMOPM
112 #define SEMOPM	100		/* max # of operations per semop call */
113 #endif
114 
115 #define SEMVMX	32767		/* semaphore maximum value */
116 #define SEMAEM	16384		/* adjust on exit max value */
117 
118 /*
119  * Due to the way semaphore memory is allocated, we have to ensure that
120  * SEMUSZ is properly aligned.
121  */
122 
123 #define SEM_ALIGN(bytes) (((bytes) + (sizeof(long) - 1)) & ~(sizeof(long) - 1))
124 
125 /* actual size of an undo structure */
126 #define SEMUSZ	SEM_ALIGN(offsetof(struct sem_undo, un_ent[SEMUME]))
127 
128 /*
129  * Macro to find a particular sem_undo vector
130  */
131 #define SEMU(ix)	((struct sem_undo *)(((intptr_t)semu)+ix * seminfo.semusz))
132 
133 /*
134  * semaphore info struct
135  */
136 struct seminfo seminfo = {
137                 SEMMAP,         /* # of entries in semaphore map */
138                 SEMMNI,         /* # of semaphore identifiers */
139                 SEMMNS,         /* # of semaphores in system */
140                 SEMMNU,         /* # of undo structures in system */
141                 SEMMSL,         /* max # of semaphores per id */
142                 SEMOPM,         /* max # of operations per semop call */
143                 SEMUME,         /* max # of undo entries per process */
144                 SEMUSZ,         /* size in bytes of undo structure */
145                 SEMVMX,         /* semaphore maximum value */
146                 SEMAEM          /* adjust on exit max value */
147 };
148 
149 SYSCTL_DECL(_kern_ipc);
150 SYSCTL_INT(_kern_ipc, OID_AUTO, semmap, CTLFLAG_RW, &seminfo.semmap, 0, "");
151 SYSCTL_INT(_kern_ipc, OID_AUTO, semmni, CTLFLAG_RD, &seminfo.semmni, 0, "");
152 SYSCTL_INT(_kern_ipc, OID_AUTO, semmns, CTLFLAG_RD, &seminfo.semmns, 0, "");
153 SYSCTL_INT(_kern_ipc, OID_AUTO, semmnu, CTLFLAG_RD, &seminfo.semmnu, 0, "");
154 SYSCTL_INT(_kern_ipc, OID_AUTO, semmsl, CTLFLAG_RW, &seminfo.semmsl, 0, "");
155 SYSCTL_INT(_kern_ipc, OID_AUTO, semopm, CTLFLAG_RD, &seminfo.semopm, 0, "");
156 SYSCTL_INT(_kern_ipc, OID_AUTO, semume, CTLFLAG_RD, &seminfo.semume, 0, "");
157 SYSCTL_INT(_kern_ipc, OID_AUTO, semusz, CTLFLAG_RD, &seminfo.semusz, 0, "");
158 SYSCTL_INT(_kern_ipc, OID_AUTO, semvmx, CTLFLAG_RW, &seminfo.semvmx, 0, "");
159 SYSCTL_INT(_kern_ipc, OID_AUTO, semaem, CTLFLAG_RW, &seminfo.semaem, 0, "");
160 SYSCTL_PROC(_kern_ipc, OID_AUTO, sema, CTLFLAG_RD,
161     NULL, 0, sysctl_sema, "", "");
162 
163 static void
164 seminit(void)
165 {
166 	register int i;
167 
168 	TUNABLE_INT_FETCH("kern.ipc.semmap", &seminfo.semmap);
169 	TUNABLE_INT_FETCH("kern.ipc.semmni", &seminfo.semmni);
170 	TUNABLE_INT_FETCH("kern.ipc.semmns", &seminfo.semmns);
171 	TUNABLE_INT_FETCH("kern.ipc.semmnu", &seminfo.semmnu);
172 	TUNABLE_INT_FETCH("kern.ipc.semmsl", &seminfo.semmsl);
173 	TUNABLE_INT_FETCH("kern.ipc.semopm", &seminfo.semopm);
174 	TUNABLE_INT_FETCH("kern.ipc.semume", &seminfo.semume);
175 	TUNABLE_INT_FETCH("kern.ipc.semusz", &seminfo.semusz);
176 	TUNABLE_INT_FETCH("kern.ipc.semvmx", &seminfo.semvmx);
177 	TUNABLE_INT_FETCH("kern.ipc.semaem", &seminfo.semaem);
178 
179 	sem = malloc(sizeof(struct sem) * seminfo.semmns, M_SEM, M_WAITOK);
180 	if (sem == NULL)
181 		panic("sem is NULL");
182 	sema = malloc(sizeof(struct semid_ds) * seminfo.semmni, M_SEM, M_WAITOK);
183 	if (sema == NULL)
184 		panic("sema is NULL");
185 	semu = malloc(seminfo.semmnu * seminfo.semusz, M_SEM, M_WAITOK);
186 	if (semu == NULL)
187 		panic("semu is NULL");
188 
189 	for (i = 0; i < seminfo.semmni; i++) {
190 		sema[i].sem_base = 0;
191 		sema[i].sem_perm.mode = 0;
192 	}
193 	for (i = 0; i < seminfo.semmnu; i++) {
194 		register struct sem_undo *suptr = SEMU(i);
195 		suptr->un_proc = NULL;
196 	}
197 	semu_list = NULL;
198 	at_exit(semexit_myhook);
199 }
200 
201 static int
202 semunload(void)
203 {
204 
205 	if (semtot != 0)
206 		return (EBUSY);
207 
208 	free(sem, M_SEM);
209 	free(sema, M_SEM);
210 	free(semu, M_SEM);
211 	rm_at_exit(semexit_myhook);
212 	return (0);
213 }
214 
215 static int
216 sysvsem_modload(struct module *module, int cmd, void *arg)
217 {
218 	int error = 0;
219 
220 	switch (cmd) {
221 	case MOD_LOAD:
222 		seminit();
223 		break;
224 	case MOD_UNLOAD:
225 		error = semunload();
226 		break;
227 	case MOD_SHUTDOWN:
228 		break;
229 	default:
230 		error = EINVAL;
231 		break;
232 	}
233 	return (error);
234 }
235 
236 static moduledata_t sysvsem_mod = {
237 	"sysvsem",
238 	&sysvsem_modload,
239 	NULL
240 };
241 
242 SYSCALL_MODULE_HELPER(semsys);
243 SYSCALL_MODULE_HELPER(__semctl);
244 SYSCALL_MODULE_HELPER(semget);
245 SYSCALL_MODULE_HELPER(semop);
246 
247 DECLARE_MODULE(sysvsem, sysvsem_mod,
248 	SI_SUB_SYSV_SEM, SI_ORDER_FIRST);
249 MODULE_VERSION(sysvsem, 1);
250 
251 /*
252  * Entry point for all SEM calls
253  *
254  * MPSAFE
255  */
256 int
257 semsys(td, uap)
258 	struct thread *td;
259 	/* XXX actually varargs. */
260 	struct semsys_args /* {
261 		u_int	which;
262 		int	a2;
263 		int	a3;
264 		int	a4;
265 		int	a5;
266 	} */ *uap;
267 {
268 	int error;
269 
270 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
271 		return (ENOSYS);
272 	if (uap->which >= sizeof(semcalls)/sizeof(semcalls[0]))
273 		return (EINVAL);
274 	mtx_lock(&Giant);
275 	error = (*semcalls[uap->which])(td, &uap->a2);
276 	mtx_unlock(&Giant);
277 	return (error);
278 }
279 
280 /*
281  * Allocate a new sem_undo structure for a process
282  * (returns ptr to structure or NULL if no more room)
283  */
284 
285 static struct sem_undo *
286 semu_alloc(td)
287 	struct thread *td;
288 {
289 	register int i;
290 	register struct sem_undo *suptr;
291 	register struct sem_undo **supptr;
292 	int attempt;
293 
294 	/*
295 	 * Try twice to allocate something.
296 	 * (we'll purge any empty structures after the first pass so
297 	 * two passes are always enough)
298 	 */
299 
300 	for (attempt = 0; attempt < 2; attempt++) {
301 		/*
302 		 * Look for a free structure.
303 		 * Fill it in and return it if we find one.
304 		 */
305 
306 		for (i = 0; i < seminfo.semmnu; i++) {
307 			suptr = SEMU(i);
308 			if (suptr->un_proc == NULL) {
309 				suptr->un_next = semu_list;
310 				semu_list = suptr;
311 				suptr->un_cnt = 0;
312 				suptr->un_proc = td->td_proc;
313 				return(suptr);
314 			}
315 		}
316 
317 		/*
318 		 * We didn't find a free one, if this is the first attempt
319 		 * then try to free some structures.
320 		 */
321 
322 		if (attempt == 0) {
323 			/* All the structures are in use - try to free some */
324 			int did_something = 0;
325 
326 			supptr = &semu_list;
327 			while ((suptr = *supptr) != NULL) {
328 				if (suptr->un_cnt == 0)  {
329 					suptr->un_proc = NULL;
330 					*supptr = suptr->un_next;
331 					did_something = 1;
332 				} else
333 					supptr = &(suptr->un_next);
334 			}
335 
336 			/* If we didn't free anything then just give-up */
337 			if (!did_something)
338 				return(NULL);
339 		} else {
340 			/*
341 			 * The second pass failed even though we freed
342 			 * something after the first pass!
343 			 * This is IMPOSSIBLE!
344 			 */
345 			panic("semu_alloc - second attempt failed");
346 		}
347 	}
348 	return (NULL);
349 }
350 
351 /*
352  * Adjust a particular entry for a particular proc
353  */
354 
355 static int
356 semundo_adjust(td, supptr, semid, semnum, adjval)
357 	register struct thread *td;
358 	struct sem_undo **supptr;
359 	int semid, semnum;
360 	int adjval;
361 {
362 	struct proc *p = td->td_proc;
363 	register struct sem_undo *suptr;
364 	register struct undo *sunptr;
365 	int i;
366 
367 	/* Look for and remember the sem_undo if the caller doesn't provide
368 	   it */
369 
370 	suptr = *supptr;
371 	if (suptr == NULL) {
372 		for (suptr = semu_list; suptr != NULL;
373 		    suptr = suptr->un_next) {
374 			if (suptr->un_proc == p) {
375 				*supptr = suptr;
376 				break;
377 			}
378 		}
379 		if (suptr == NULL) {
380 			if (adjval == 0)
381 				return(0);
382 			suptr = semu_alloc(td);
383 			if (suptr == NULL)
384 				return(ENOSPC);
385 			*supptr = suptr;
386 		}
387 	}
388 
389 	/*
390 	 * Look for the requested entry and adjust it (delete if adjval becomes
391 	 * 0).
392 	 */
393 	sunptr = &suptr->un_ent[0];
394 	for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
395 		if (sunptr->un_id != semid || sunptr->un_num != semnum)
396 			continue;
397 		if (adjval != 0) {
398 			adjval += sunptr->un_adjval;
399 			if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
400 				return (ERANGE);
401 		}
402 		sunptr->un_adjval = adjval;
403 		if (sunptr->un_adjval == 0) {
404 			suptr->un_cnt--;
405 			if (i < suptr->un_cnt)
406 				suptr->un_ent[i] =
407 				    suptr->un_ent[suptr->un_cnt];
408 		}
409 		return(0);
410 	}
411 
412 	/* Didn't find the right entry - create it */
413 	if (adjval == 0)
414 		return(0);
415 	if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
416 		return (ERANGE);
417 	if (suptr->un_cnt != seminfo.semume) {
418 		sunptr = &suptr->un_ent[suptr->un_cnt];
419 		suptr->un_cnt++;
420 		sunptr->un_adjval = adjval;
421 		sunptr->un_id = semid; sunptr->un_num = semnum;
422 	} else
423 		return(EINVAL);
424 	return(0);
425 }
426 
427 static void
428 semundo_clear(semid, semnum)
429 	int semid, semnum;
430 {
431 	register struct sem_undo *suptr;
432 
433 	for (suptr = semu_list; suptr != NULL; suptr = suptr->un_next) {
434 		register struct undo *sunptr = &suptr->un_ent[0];
435 		register int i = 0;
436 
437 		while (i < suptr->un_cnt) {
438 			if (sunptr->un_id == semid) {
439 				if (semnum == -1 || sunptr->un_num == semnum) {
440 					suptr->un_cnt--;
441 					if (i < suptr->un_cnt) {
442 						suptr->un_ent[i] =
443 						  suptr->un_ent[suptr->un_cnt];
444 						continue;
445 					}
446 				}
447 				if (semnum != -1)
448 					break;
449 			}
450 			i++, sunptr++;
451 		}
452 	}
453 }
454 
455 /*
456  * Note that the user-mode half of this passes a union, not a pointer
457  */
458 #ifndef _SYS_SYSPROTO_H_
459 struct __semctl_args {
460 	int	semid;
461 	int	semnum;
462 	int	cmd;
463 	union	semun *arg;
464 };
465 #endif
466 
467 /*
468  * MPSAFE
469  */
470 int
471 __semctl(td, uap)
472 	struct thread *td;
473 	register struct __semctl_args *uap;
474 {
475 	int semid = uap->semid;
476 	int semnum = uap->semnum;
477 	int cmd = uap->cmd;
478 	union semun *arg = uap->arg;
479 	union semun real_arg;
480 	struct ucred *cred = td->td_ucred;
481 	int i, rval, error;
482 	struct semid_ds sbuf;
483 	register struct semid_ds *semaptr;
484 	u_short usval;
485 
486 	DPRINTF(("call to semctl(%d, %d, %d, 0x%x)\n",
487 	    semid, semnum, cmd, arg));
488 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
489 		return (ENOSYS);
490 
491 	mtx_lock(&Giant);
492 	switch(cmd) {
493 	case SEM_STAT:
494 		if (semid < 0 || semid >= seminfo.semmni)
495 			UGAR(EINVAL);
496 		semaptr = &sema[semid];
497 		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 )
498 			UGAR(EINVAL);
499 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
500 			UGAR(error);
501 		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
502 			UGAR(error);
503 		error = copyout(semaptr, real_arg.buf, sizeof(struct semid_ds));
504 		rval = IXSEQ_TO_IPCID(semid,semaptr->sem_perm);
505 		if (error == 0)
506 			td->td_retval[0] = rval;
507 		goto done2;
508 	}
509 
510 	semid = IPCID_TO_IX(semid);
511 	if (semid < 0 || semid >= seminfo.semmni) {
512 		error = EINVAL;
513 		goto done2;
514 	}
515 
516 	semaptr = &sema[semid];
517 	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
518 	    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
519 		error = EINVAL;
520 		goto done2;
521 	}
522 
523 	error = 0;
524 	rval = 0;
525 
526 	switch (cmd) {
527 	case IPC_RMID:
528 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
529 			goto done2;
530 		semaptr->sem_perm.cuid = cred->cr_uid;
531 		semaptr->sem_perm.uid = cred->cr_uid;
532 		semtot -= semaptr->sem_nsems;
533 		for (i = semaptr->sem_base - sem; i < semtot; i++)
534 			sem[i] = sem[i + semaptr->sem_nsems];
535 		for (i = 0; i < seminfo.semmni; i++) {
536 			if ((sema[i].sem_perm.mode & SEM_ALLOC) &&
537 			    sema[i].sem_base > semaptr->sem_base)
538 				sema[i].sem_base -= semaptr->sem_nsems;
539 		}
540 		semaptr->sem_perm.mode = 0;
541 		semundo_clear(semid, -1);
542 		wakeup(semaptr);
543 		break;
544 
545 	case IPC_SET:
546 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_M)))
547 			goto done2;
548 		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
549 			goto done2;
550 		if ((error = copyin(real_arg.buf, &sbuf, sizeof(sbuf))) != 0) {
551 			goto done2;
552 		}
553 		semaptr->sem_perm.uid = sbuf.sem_perm.uid;
554 		semaptr->sem_perm.gid = sbuf.sem_perm.gid;
555 		semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
556 		    (sbuf.sem_perm.mode & 0777);
557 		semaptr->sem_ctime = time_second;
558 		break;
559 
560 	case IPC_STAT:
561 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
562 			goto done2;
563 		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
564 			goto done2;
565 		error = copyout(semaptr, real_arg.buf,
566 				sizeof(struct semid_ds));
567 		break;
568 
569 	case GETNCNT:
570 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
571 			goto done2;
572 		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
573 			error = EINVAL;
574 			goto done2;
575 		}
576 		rval = semaptr->sem_base[semnum].semncnt;
577 		break;
578 
579 	case GETPID:
580 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
581 			goto done2;
582 		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
583 			error = EINVAL;
584 			goto done2;
585 		}
586 		rval = semaptr->sem_base[semnum].sempid;
587 		break;
588 
589 	case GETVAL:
590 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
591 			goto done2;
592 		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
593 			error = EINVAL;
594 			goto done2;
595 		}
596 		rval = semaptr->sem_base[semnum].semval;
597 		break;
598 
599 	case GETALL:
600 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
601 			goto done2;
602 		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
603 			goto done2;
604 		for (i = 0; i < semaptr->sem_nsems; i++) {
605 			error = copyout(&semaptr->sem_base[i].semval,
606 			    &real_arg.array[i], sizeof(real_arg.array[0]));
607 			if (error != 0)
608 				break;
609 		}
610 		break;
611 
612 	case GETZCNT:
613 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_R)))
614 			goto done2;
615 		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
616 			error = EINVAL;
617 			goto done2;
618 		}
619 		rval = semaptr->sem_base[semnum].semzcnt;
620 		break;
621 
622 	case SETVAL:
623 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
624 			goto done2;
625 		if (semnum < 0 || semnum >= semaptr->sem_nsems) {
626 			error = EINVAL;
627 			goto done2;
628 		}
629 		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
630 			goto done2;
631 		if (real_arg.val < 0 || real_arg.val > seminfo.semvmx) {
632 			error = ERANGE;
633 			goto done2;
634 		}
635 		semaptr->sem_base[semnum].semval = real_arg.val;
636 		semundo_clear(semid, semnum);
637 		wakeup(semaptr);
638 		break;
639 
640 	case SETALL:
641 		if ((error = ipcperm(td, &semaptr->sem_perm, IPC_W)))
642 			goto done2;
643 		if ((error = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
644 			goto done2;
645 		for (i = 0; i < semaptr->sem_nsems; i++) {
646 			error = copyin(&real_arg.array[i],
647 			    &usval, sizeof(real_arg.array[0]));
648 			if (error != 0)
649 				break;
650 			if (usval > seminfo.semvmx) {
651 				error = ERANGE;
652 				break;
653 			}
654 			semaptr->sem_base[i].semval = usval;
655 		}
656 		semundo_clear(semid, -1);
657 		wakeup(semaptr);
658 		break;
659 
660 	default:
661 		error = EINVAL;
662 		break;
663 	}
664 
665 	if (error == 0)
666 		td->td_retval[0] = rval;
667 done2:
668 	mtx_unlock(&Giant);
669 	return(error);
670 }
671 
672 #ifndef _SYS_SYSPROTO_H_
673 struct semget_args {
674 	key_t	key;
675 	int	nsems;
676 	int	semflg;
677 };
678 #endif
679 
680 /*
681  * MPSAFE
682  */
683 int
684 semget(td, uap)
685 	struct thread *td;
686 	register struct semget_args *uap;
687 {
688 	int semid, error = 0;
689 	int key = uap->key;
690 	int nsems = uap->nsems;
691 	int semflg = uap->semflg;
692 	struct ucred *cred = td->td_ucred;
693 
694 	DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
695 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
696 		return (ENOSYS);
697 
698 	mtx_lock(&Giant);
699 	if (key != IPC_PRIVATE) {
700 		for (semid = 0; semid < seminfo.semmni; semid++) {
701 			if ((sema[semid].sem_perm.mode & SEM_ALLOC) &&
702 			    sema[semid].sem_perm.key == key)
703 				break;
704 		}
705 		if (semid < seminfo.semmni) {
706 			DPRINTF(("found public key\n"));
707 			if ((error = ipcperm(td, &sema[semid].sem_perm,
708 			    semflg & 0700))) {
709 				goto done2;
710 			}
711 			if (nsems > 0 && sema[semid].sem_nsems < nsems) {
712 				DPRINTF(("too small\n"));
713 				error = EINVAL;
714 				goto done2;
715 			}
716 			if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
717 				DPRINTF(("not exclusive\n"));
718 				error = EEXIST;
719 				goto done2;
720 			}
721 			goto found;
722 		}
723 	}
724 
725 	DPRINTF(("need to allocate the semid_ds\n"));
726 	if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
727 		if (nsems <= 0 || nsems > seminfo.semmsl) {
728 			DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
729 			    seminfo.semmsl));
730 			error = EINVAL;
731 			goto done2;
732 		}
733 		if (nsems > seminfo.semmns - semtot) {
734 			DPRINTF((
735 			    "not enough semaphores left (need %d, got %d)\n",
736 			    nsems, seminfo.semmns - semtot));
737 			error = ENOSPC;
738 			goto done2;
739 		}
740 		for (semid = 0; semid < seminfo.semmni; semid++) {
741 			if ((sema[semid].sem_perm.mode & SEM_ALLOC) == 0)
742 				break;
743 		}
744 		if (semid == seminfo.semmni) {
745 			DPRINTF(("no more semid_ds's available\n"));
746 			error = ENOSPC;
747 			goto done2;
748 		}
749 		DPRINTF(("semid %d is available\n", semid));
750 		sema[semid].sem_perm.key = key;
751 		sema[semid].sem_perm.cuid = cred->cr_uid;
752 		sema[semid].sem_perm.uid = cred->cr_uid;
753 		sema[semid].sem_perm.cgid = cred->cr_gid;
754 		sema[semid].sem_perm.gid = cred->cr_gid;
755 		sema[semid].sem_perm.mode = (semflg & 0777) | SEM_ALLOC;
756 		sema[semid].sem_perm.seq =
757 		    (sema[semid].sem_perm.seq + 1) & 0x7fff;
758 		sema[semid].sem_nsems = nsems;
759 		sema[semid].sem_otime = 0;
760 		sema[semid].sem_ctime = time_second;
761 		sema[semid].sem_base = &sem[semtot];
762 		semtot += nsems;
763 		bzero(sema[semid].sem_base,
764 		    sizeof(sema[semid].sem_base[0])*nsems);
765 		DPRINTF(("sembase = 0x%x, next = 0x%x\n", sema[semid].sem_base,
766 		    &sem[semtot]));
767 	} else {
768 		DPRINTF(("didn't find it and wasn't asked to create it\n"));
769 		error = ENOENT;
770 		goto done2;
771 	}
772 
773 found:
774 	td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].sem_perm);
775 done2:
776 	mtx_unlock(&Giant);
777 	return (error);
778 }
779 
780 #ifndef _SYS_SYSPROTO_H_
781 struct semop_args {
782 	int	semid;
783 	struct	sembuf *sops;
784 	u_int	nsops;
785 };
786 #endif
787 
788 /*
789  * MPSAFE
790  */
791 int
792 semop(td, uap)
793 	struct thread *td;
794 	register struct semop_args *uap;
795 {
796 	int semid = uap->semid;
797 	u_int nsops = uap->nsops;
798 	struct sembuf *sops = NULL;
799 	register struct semid_ds *semaptr;
800 	register struct sembuf *sopptr = 0;
801 	register struct sem *semptr = 0;
802 	struct sem_undo *suptr;
803 	int i, j, error;
804 	int do_wakeup, do_undos;
805 
806 	DPRINTF(("call to semop(%d, 0x%x, %u)\n", semid, sops, nsops));
807 
808 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
809 		return (ENOSYS);
810 
811 	mtx_lock(&Giant);
812 	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
813 
814 	if (semid < 0 || semid >= seminfo.semmni) {
815 		error = EINVAL;
816 		goto done2;
817 	}
818 
819 	semaptr = &sema[semid];
820 	if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0) {
821 		error = EINVAL;
822 		goto done2;
823 	}
824 	if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
825 		error = EINVAL;
826 		goto done2;
827 	}
828 	if (nsops > seminfo.semopm) {
829 		DPRINTF(("too many sops (max=%d, nsops=%d)\n", seminfo.semopm,
830 		    nsops));
831 		error = E2BIG;
832 		goto done2;
833 	}
834 
835 	/* Allocate memory for sem_ops */
836 	sops = malloc(nsops * sizeof(sops[0]), M_SEM, M_WAITOK);
837 	if (!sops)
838 		panic("Failed to allocate %d sem_ops", nsops);
839 
840 	if ((error = copyin(uap->sops, sops, nsops * sizeof(sops[0]))) != 0) {
841 		DPRINTF(("error = %d from copyin(%08x, %08x, %d)\n", error,
842 		    uap->sops, sops, nsops * sizeof(sops[0])));
843 		goto done2;
844 	}
845 
846 	/*
847 	 * Initial pass thru sops to see what permissions are needed.
848 	 * Also perform any checks that don't need repeating on each
849 	 * attempt to satisfy the request vector.
850 	 */
851 	j = 0;		/* permission needed */
852 	do_undos = 0;
853 	for (i = 0; i < nsops; i++) {
854 		sopptr = &sops[i];
855 		if (sopptr->sem_num >= semaptr->sem_nsems) {
856 			error = EFBIG;
857 			goto done2;
858 		}
859 		if (sopptr->sem_flg & SEM_UNDO && sopptr->sem_op != 0)
860 			do_undos = 1;
861 		j |= (sopptr->sem_op == 0) ? SEM_R : SEM_A;
862 	}
863 
864 	if ((error = ipcperm(td, &semaptr->sem_perm, j))) {
865 		DPRINTF(("error = %d from ipaccess\n", error));
866 		goto done2;
867 	}
868 
869 	/*
870 	 * Loop trying to satisfy the vector of requests.
871 	 * If we reach a point where we must wait, any requests already
872 	 * performed are rolled back and we go to sleep until some other
873 	 * process wakes us up.  At this point, we start all over again.
874 	 *
875 	 * This ensures that from the perspective of other tasks, a set
876 	 * of requests is atomic (never partially satisfied).
877 	 */
878 	for (;;) {
879 		do_wakeup = 0;
880 		error = 0;	/* error return if necessary */
881 
882 		for (i = 0; i < nsops; i++) {
883 			sopptr = &sops[i];
884 			semptr = &semaptr->sem_base[sopptr->sem_num];
885 
886 			DPRINTF((
887 			    "semop:  semaptr=%x, sem_base=%x, "
888 			    "semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
889 			    semaptr, semaptr->sem_base, semptr,
890 			    sopptr->sem_num, semptr->semval, sopptr->sem_op,
891 			    (sopptr->sem_flg & IPC_NOWAIT) ?
892 			    "nowait" : "wait"));
893 
894 			if (sopptr->sem_op < 0) {
895 				if (semptr->semval + sopptr->sem_op < 0) {
896 					DPRINTF(("semop:  can't do it now\n"));
897 					break;
898 				} else {
899 					semptr->semval += sopptr->sem_op;
900 					if (semptr->semval == 0 &&
901 					    semptr->semzcnt > 0)
902 						do_wakeup = 1;
903 				}
904 			} else if (sopptr->sem_op == 0) {
905 				if (semptr->semval != 0) {
906 					DPRINTF(("semop:  not zero now\n"));
907 					break;
908 				}
909 			} else if (semptr->semval + sopptr->sem_op >
910 			    seminfo.semvmx) {
911 				error = ERANGE;
912 				break;
913 			} else {
914 				if (semptr->semncnt > 0)
915 					do_wakeup = 1;
916 				semptr->semval += sopptr->sem_op;
917 			}
918 		}
919 
920 		/*
921 		 * Did we get through the entire vector?
922 		 */
923 		if (i >= nsops)
924 			goto done;
925 
926 		/*
927 		 * No ... rollback anything that we've already done
928 		 */
929 		DPRINTF(("semop:  rollback 0 through %d\n", i-1));
930 		for (j = 0; j < i; j++)
931 			semaptr->sem_base[sops[j].sem_num].semval -=
932 			    sops[j].sem_op;
933 
934 		/* If we detected an error, return it */
935 		if (error != 0)
936 			goto done2;
937 
938 		/*
939 		 * If the request that we couldn't satisfy has the
940 		 * NOWAIT flag set then return with EAGAIN.
941 		 */
942 		if (sopptr->sem_flg & IPC_NOWAIT) {
943 			error = EAGAIN;
944 			goto done2;
945 		}
946 
947 		if (sopptr->sem_op == 0)
948 			semptr->semzcnt++;
949 		else
950 			semptr->semncnt++;
951 
952 		DPRINTF(("semop:  good night!\n"));
953 		error = tsleep(semaptr, (PZERO - 4) | PCATCH, "semwait", 0);
954 		DPRINTF(("semop:  good morning (error=%d)!\n", error));
955 
956 		if (error != 0) {
957 			error = EINTR;
958 			goto done2;
959 		}
960 		DPRINTF(("semop:  good morning!\n"));
961 
962 		/*
963 		 * Make sure that the semaphore still exists
964 		 */
965 		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
966 		    semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid)) {
967 			error = EIDRM;
968 			goto done2;
969 		}
970 
971 		/*
972 		 * The semaphore is still alive.  Readjust the count of
973 		 * waiting processes.
974 		 */
975 		if (sopptr->sem_op == 0)
976 			semptr->semzcnt--;
977 		else
978 			semptr->semncnt--;
979 	}
980 
981 done:
982 	/*
983 	 * Process any SEM_UNDO requests.
984 	 */
985 	if (do_undos) {
986 		suptr = NULL;
987 		for (i = 0; i < nsops; i++) {
988 			/*
989 			 * We only need to deal with SEM_UNDO's for non-zero
990 			 * op's.
991 			 */
992 			int adjval;
993 
994 			if ((sops[i].sem_flg & SEM_UNDO) == 0)
995 				continue;
996 			adjval = sops[i].sem_op;
997 			if (adjval == 0)
998 				continue;
999 			error = semundo_adjust(td, &suptr, semid,
1000 			    sops[i].sem_num, -adjval);
1001 			if (error == 0)
1002 				continue;
1003 
1004 			/*
1005 			 * Oh-Oh!  We ran out of either sem_undo's or undo's.
1006 			 * Rollback the adjustments to this point and then
1007 			 * rollback the semaphore ups and down so we can return
1008 			 * with an error with all structures restored.  We
1009 			 * rollback the undo's in the exact reverse order that
1010 			 * we applied them.  This guarantees that we won't run
1011 			 * out of space as we roll things back out.
1012 			 */
1013 			for (j = i - 1; j >= 0; j--) {
1014 				if ((sops[j].sem_flg & SEM_UNDO) == 0)
1015 					continue;
1016 				adjval = sops[j].sem_op;
1017 				if (adjval == 0)
1018 					continue;
1019 				if (semundo_adjust(td, &suptr, semid,
1020 				    sops[j].sem_num, adjval) != 0)
1021 					panic("semop - can't undo undos");
1022 			}
1023 
1024 			for (j = 0; j < nsops; j++)
1025 				semaptr->sem_base[sops[j].sem_num].semval -=
1026 				    sops[j].sem_op;
1027 
1028 			DPRINTF(("error = %d from semundo_adjust\n", error));
1029 			goto done2;
1030 		} /* loop through the sops */
1031 	} /* if (do_undos) */
1032 
1033 	/* We're definitely done - set the sempid's and time */
1034 	for (i = 0; i < nsops; i++) {
1035 		sopptr = &sops[i];
1036 		semptr = &semaptr->sem_base[sopptr->sem_num];
1037 		semptr->sempid = td->td_proc->p_pid;
1038 	}
1039 	semaptr->sem_otime = time_second;
1040 
1041 	/*
1042 	 * Do a wakeup if any semaphore was up'd whilst something was
1043 	 * sleeping on it.
1044 	 */
1045 	if (do_wakeup) {
1046 		DPRINTF(("semop:  doing wakeup\n"));
1047 		wakeup(semaptr);
1048 		DPRINTF(("semop:  back from wakeup\n"));
1049 	}
1050 	DPRINTF(("semop:  done\n"));
1051 	td->td_retval[0] = 0;
1052 done2:
1053 	if (sops)
1054 	    free(sops, M_SEM);
1055 	mtx_unlock(&Giant);
1056 	return (error);
1057 }
1058 
1059 /*
1060  * Go through the undo structures for this process and apply the adjustments to
1061  * semaphores.
1062  */
1063 static void
1064 semexit_myhook(p)
1065 	struct proc *p;
1066 {
1067 	register struct sem_undo *suptr;
1068 	register struct sem_undo **supptr;
1069 
1070 	/*
1071 	 * Go through the chain of undo vectors looking for one
1072 	 * associated with this process.
1073 	 */
1074 
1075 	for (supptr = &semu_list; (suptr = *supptr) != NULL;
1076 	    supptr = &suptr->un_next) {
1077 		if (suptr->un_proc == p)
1078 			break;
1079 	}
1080 
1081 	if (suptr == NULL)
1082 		return;
1083 
1084 	DPRINTF(("proc @%08x has undo structure with %d entries\n", p,
1085 	    suptr->un_cnt));
1086 
1087 	/*
1088 	 * If there are any active undo elements then process them.
1089 	 */
1090 	if (suptr->un_cnt > 0) {
1091 		int ix;
1092 
1093 		for (ix = 0; ix < suptr->un_cnt; ix++) {
1094 			int semid = suptr->un_ent[ix].un_id;
1095 			int semnum = suptr->un_ent[ix].un_num;
1096 			int adjval = suptr->un_ent[ix].un_adjval;
1097 			struct semid_ds *semaptr;
1098 
1099 			semaptr = &sema[semid];
1100 			if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0)
1101 				panic("semexit - semid not allocated");
1102 			if (semnum >= semaptr->sem_nsems)
1103 				panic("semexit - semnum out of range");
1104 
1105 			DPRINTF((
1106 			    "semexit:  %08x id=%d num=%d(adj=%d) ; sem=%d\n",
1107 			    suptr->un_proc, suptr->un_ent[ix].un_id,
1108 			    suptr->un_ent[ix].un_num,
1109 			    suptr->un_ent[ix].un_adjval,
1110 			    semaptr->sem_base[semnum].semval));
1111 
1112 			if (adjval < 0) {
1113 				if (semaptr->sem_base[semnum].semval < -adjval)
1114 					semaptr->sem_base[semnum].semval = 0;
1115 				else
1116 					semaptr->sem_base[semnum].semval +=
1117 					    adjval;
1118 			} else
1119 				semaptr->sem_base[semnum].semval += adjval;
1120 
1121 			wakeup(semaptr);
1122 			DPRINTF(("semexit:  back from wakeup\n"));
1123 		}
1124 	}
1125 
1126 	/*
1127 	 * Deallocate the undo vector.
1128 	 */
1129 	DPRINTF(("removing vector\n"));
1130 	suptr->un_proc = NULL;
1131 	*supptr = suptr->un_next;
1132 }
1133 
1134 static int
1135 sysctl_sema(SYSCTL_HANDLER_ARGS)
1136 {
1137 
1138 	return (SYSCTL_OUT(req, sema,
1139 	    sizeof(struct semid_ds) * seminfo.semmni));
1140 }
1141