This source file includes following definitions.
- SLIST_HEAD
- semu_alloc
- semundo_adjust
- semundo_clear
- sys___semctl
- semctl1
- sys_semget
- sys_semop
- semexit
- sysctl_sysvsem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
34 #include <sys/proc.h>
35 #include <sys/sem.h>
36 #include <sys/sysctl.h>
37 #include <sys/malloc.h>
38 #include <sys/pool.h>
39
40 #include <sys/mount.h>
41 #include <sys/syscallargs.h>
42
43
44 #ifndef EIDRM
45 #define EIDRM EINVAL
46 #endif
47
48 #ifdef SEM_DEBUG
49 #define DPRINTF(x) printf x
50 #else
51 #define DPRINTF(x)
52 #endif
53
54 int semtot = 0;
55 int semutot = 0;
56 struct semid_ds **sema;
57 SLIST_HEAD(, sem_undo) semu_list;
58 struct pool sema_pool;
59 struct pool semu_pool;
60 unsigned short *semseqs;
61
62 struct sem_undo *semu_alloc(struct proc *);
63 int semundo_adjust(struct proc *, struct sem_undo **, int, int, int);
64 void semundo_clear(int, int);
65
66 void
67 seminit(void)
68 {
69
70 pool_init(&sema_pool, sizeof(struct semid_ds), 0, 0, 0, "semapl",
71 &pool_allocator_nointr);
72 pool_init(&semu_pool, SEMUSZ, 0, 0, 0, "semupl",
73 &pool_allocator_nointr);
74 sema = malloc(seminfo.semmni * sizeof(struct semid_ds *),
75 M_SEM, M_WAITOK);
76 bzero(sema, seminfo.semmni * sizeof(struct semid_ds *));
77 semseqs = malloc(seminfo.semmni * sizeof(unsigned short),
78 M_SEM, M_WAITOK);
79 bzero(semseqs, seminfo.semmni * sizeof(unsigned short));
80 SLIST_INIT(&semu_list);
81 }
82
83
84
85
86
87 struct sem_undo *
88 semu_alloc(struct proc *p)
89 {
90 struct sem_undo *suptr, *sutmp;
91
92 if (semutot == seminfo.semmnu)
93 return (NULL);
94
95
96
97
98
99
100 semutot++;
101 if ((suptr = pool_get(&semu_pool, 0)) == NULL) {
102 sutmp = pool_get(&semu_pool, PR_WAITOK);
103 SLIST_FOREACH(suptr, &semu_list, un_next) {
104 if (suptr->un_proc == p) {
105 pool_put(&semu_pool, sutmp);
106 semutot--;
107 return (suptr);
108 }
109 }
110 suptr = sutmp;
111 }
112 suptr->un_cnt = 0;
113 suptr->un_proc = p;
114 SLIST_INSERT_HEAD(&semu_list, suptr, un_next);
115 return (suptr);
116 }
117
118
119
120
121 int
122 semundo_adjust(struct proc *p, struct sem_undo **supptr, int semid, int semnum,
123 int adjval)
124 {
125 struct sem_undo *suptr;
126 struct undo *sunptr;
127 int i;
128
129
130
131
132 suptr = *supptr;
133 if (suptr == NULL) {
134 SLIST_FOREACH(suptr, &semu_list, un_next) {
135 if (suptr->un_proc == p) {
136 *supptr = suptr;
137 break;
138 }
139 }
140 if (suptr == NULL) {
141 if (adjval == 0)
142 return (0);
143 suptr = semu_alloc(p);
144 if (suptr == NULL)
145 return (ENOSPC);
146 *supptr = suptr;
147 }
148 }
149
150
151
152
153
154 sunptr = &suptr->un_ent[0];
155 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
156 if (sunptr->un_id != semid || sunptr->un_num != semnum)
157 continue;
158 if (adjval == 0)
159 sunptr->un_adjval = 0;
160 else
161 sunptr->un_adjval += adjval;
162 if (sunptr->un_adjval != 0)
163 return (0);
164
165 if (--suptr->un_cnt == 0) {
166 SLIST_REMOVE(&semu_list, suptr, sem_undo, un_next);
167 pool_put(&semu_pool, suptr);
168 semutot--;
169 } else if (i < suptr->un_cnt)
170 suptr->un_ent[i] =
171 suptr->un_ent[suptr->un_cnt];
172 return (0);
173 }
174
175
176 if (adjval == 0)
177 return (0);
178 if (suptr->un_cnt == SEMUME)
179 return (EINVAL);
180
181 sunptr = &suptr->un_ent[suptr->un_cnt];
182 suptr->un_cnt++;
183 sunptr->un_adjval = adjval;
184 sunptr->un_id = semid;
185 sunptr->un_num = semnum;
186 return (0);
187 }
188
189 void
190 semundo_clear(int semid, int semnum)
191 {
192 struct sem_undo *suptr = SLIST_FIRST(&semu_list);
193 struct sem_undo *suprev = SLIST_END(&semu_list);
194 struct undo *sunptr;
195 int i;
196
197 while (suptr != SLIST_END(&semu_list)) {
198 sunptr = &suptr->un_ent[0];
199 for (i = 0; i < suptr->un_cnt; i++, sunptr++) {
200 if (sunptr->un_id == semid) {
201 if (semnum == -1 || sunptr->un_num == semnum) {
202 suptr->un_cnt--;
203 if (i < suptr->un_cnt) {
204 suptr->un_ent[i] =
205 suptr->un_ent[suptr->un_cnt];
206 i--, sunptr--;
207 }
208 }
209 if (semnum != -1)
210 break;
211 }
212 }
213 if (suptr->un_cnt == 0) {
214 struct sem_undo *sutmp = suptr;
215
216 if (suptr == SLIST_FIRST(&semu_list))
217 SLIST_REMOVE_HEAD(&semu_list, un_next);
218 else
219 SLIST_REMOVE_NEXT(&semu_list, suprev, un_next);
220 suptr = SLIST_NEXT(suptr, un_next);
221 pool_put(&semu_pool, sutmp);
222 semutot--;
223 } else {
224 suprev = suptr;
225 suptr = SLIST_NEXT(suptr, un_next);
226 }
227 }
228 }
229
230 int
231 sys___semctl(struct proc *p, void *v, register_t *retval)
232 {
233 struct sys___semctl_args
234
235
236
237
238 *uap = v;
239 union semun arg;
240 int error = 0, cmd = SCARG(uap, cmd);
241
242 switch (cmd) {
243 case IPC_SET:
244 case IPC_STAT:
245 case GETALL:
246 case SETVAL:
247 case SETALL:
248 error = copyin(SCARG(uap, arg), &arg, sizeof(arg));
249 break;
250 }
251 if (error == 0) {
252 error = semctl1(p, SCARG(uap, semid), SCARG(uap, semnum),
253 cmd, &arg, retval, copyin, copyout);
254 }
255 return (error);
256 }
257
258 int
259 semctl1(struct proc *p, int semid, int semnum, int cmd, union semun *arg,
260 register_t *retval, int (*ds_copyin)(const void *, void *, size_t),
261 int (*ds_copyout)(const void *, void *, size_t))
262 {
263 struct ucred *cred = p->p_ucred;
264 int i, ix, error = 0;
265 struct semid_ds sbuf;
266 struct semid_ds *semaptr;
267
268 DPRINTF(("call to semctl(%d, %d, %d, %p)\n", semid, semnum, cmd, arg));
269
270 ix = IPCID_TO_IX(semid);
271 if (ix < 0 || ix >= seminfo.semmni)
272 return (EINVAL);
273
274 if ((semaptr = sema[ix]) == NULL ||
275 semaptr->sem_perm.seq != IPCID_TO_SEQ(semid))
276 return (EINVAL);
277
278 switch (cmd) {
279 case IPC_RMID:
280 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)) != 0)
281 return (error);
282 semaptr->sem_perm.cuid = cred->cr_uid;
283 semaptr->sem_perm.uid = cred->cr_uid;
284 semtot -= semaptr->sem_nsems;
285 free(semaptr->sem_base, M_SEM);
286 pool_put(&sema_pool, semaptr);
287 sema[ix] = NULL;
288 semundo_clear(ix, -1);
289 wakeup(&sema[ix]);
290 break;
291
292 case IPC_SET:
293 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_M)))
294 return (error);
295 if ((error = ds_copyin(arg->buf, &sbuf, sizeof(sbuf))) != 0)
296 return (error);
297 semaptr->sem_perm.uid = sbuf.sem_perm.uid;
298 semaptr->sem_perm.gid = sbuf.sem_perm.gid;
299 semaptr->sem_perm.mode = (semaptr->sem_perm.mode & ~0777) |
300 (sbuf.sem_perm.mode & 0777);
301 semaptr->sem_ctime = time_second;
302 break;
303
304 case IPC_STAT:
305 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
306 return (error);
307 error = ds_copyout(semaptr, arg->buf, sizeof(struct semid_ds));
308 break;
309
310 case GETNCNT:
311 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
312 return (error);
313 if (semnum < 0 || semnum >= semaptr->sem_nsems)
314 return (EINVAL);
315 *retval = semaptr->sem_base[semnum].semncnt;
316 break;
317
318 case GETPID:
319 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
320 return (error);
321 if (semnum < 0 || semnum >= semaptr->sem_nsems)
322 return (EINVAL);
323 *retval = semaptr->sem_base[semnum].sempid;
324 break;
325
326 case GETVAL:
327 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
328 return (error);
329 if (semnum < 0 || semnum >= semaptr->sem_nsems)
330 return (EINVAL);
331 *retval = semaptr->sem_base[semnum].semval;
332 break;
333
334 case GETALL:
335 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
336 return (error);
337 for (i = 0; i < semaptr->sem_nsems; i++) {
338 error = ds_copyout(&semaptr->sem_base[i].semval,
339 &arg->array[i], sizeof(arg->array[0]));
340 if (error != 0)
341 break;
342 }
343 break;
344
345 case GETZCNT:
346 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
347 return (error);
348 if (semnum < 0 || semnum >= semaptr->sem_nsems)
349 return (EINVAL);
350 *retval = semaptr->sem_base[semnum].semzcnt;
351 break;
352
353 case SETVAL:
354 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
355 return (error);
356 if (semnum < 0 || semnum >= semaptr->sem_nsems)
357 return (EINVAL);
358 semaptr->sem_base[semnum].semval = arg->val;
359 semundo_clear(ix, semnum);
360 wakeup(&sema[ix]);
361 break;
362
363 case SETALL:
364 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
365 return (error);
366 for (i = 0; i < semaptr->sem_nsems; i++) {
367 error = ds_copyin(&arg->array[i],
368 &semaptr->sem_base[i].semval,
369 sizeof(arg->array[0]));
370 if (error != 0)
371 break;
372 }
373 semundo_clear(ix, -1);
374 wakeup(&sema[ix]);
375 break;
376
377 default:
378 return (EINVAL);
379 }
380
381 return (error);
382 }
383
384 int
385 sys_semget(struct proc *p, void *v, register_t *retval)
386 {
387 struct sys_semget_args
388
389
390
391 *uap = v;
392 int semid, error;
393 int key = SCARG(uap, key);
394 int nsems = SCARG(uap, nsems);
395 int semflg = SCARG(uap, semflg);
396 struct semid_ds *semaptr, *semaptr_new = NULL;
397 struct ucred *cred = p->p_ucred;
398
399 DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
400
401
402
403
404
405
406 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
407 if (nsems <= 0 || nsems > seminfo.semmsl) {
408 DPRINTF(("nsems out of range (0<%d<=%d)\n", nsems,
409 seminfo.semmsl));
410 return (EINVAL);
411 }
412 if (nsems > seminfo.semmns - semtot) {
413 DPRINTF(("not enough semaphores left (need %d, got %d)\n",
414 nsems, seminfo.semmns - semtot));
415 return (ENOSPC);
416 }
417 semaptr_new = pool_get(&sema_pool, PR_WAITOK);
418 semaptr_new->sem_base = malloc(nsems * sizeof(struct sem),
419 M_SEM, M_WAITOK);
420 bzero(semaptr_new->sem_base, nsems * sizeof(struct sem));
421 }
422
423 if (key != IPC_PRIVATE) {
424 for (semid = 0, semaptr = NULL; semid < seminfo.semmni; semid++) {
425 if ((semaptr = sema[semid]) != NULL &&
426 semaptr->sem_perm.key == key) {
427 DPRINTF(("found public key\n"));
428 if ((error = ipcperm(cred, &semaptr->sem_perm,
429 semflg & 0700)))
430 goto error;
431 if (nsems > 0 && semaptr->sem_nsems < nsems) {
432 DPRINTF(("too small\n"));
433 error = EINVAL;
434 goto error;
435 }
436 if ((semflg & IPC_CREAT) && (semflg & IPC_EXCL)) {
437 DPRINTF(("not exclusive\n"));
438 error = EEXIST;
439 goto error;
440 }
441 goto found;
442 }
443 }
444 }
445
446 DPRINTF(("need to allocate the semid_ds\n"));
447 if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) {
448 for (semid = 0; semid < seminfo.semmni; semid++) {
449 if ((semaptr = sema[semid]) == NULL)
450 break;
451 }
452 if (semid == seminfo.semmni) {
453 DPRINTF(("no more semid_ds's available\n"));
454 error = ENOSPC;
455 goto error;
456 }
457 DPRINTF(("semid %d is available\n", semid));
458 semaptr_new->sem_perm.key = key;
459 semaptr_new->sem_perm.cuid = cred->cr_uid;
460 semaptr_new->sem_perm.uid = cred->cr_uid;
461 semaptr_new->sem_perm.cgid = cred->cr_gid;
462 semaptr_new->sem_perm.gid = cred->cr_gid;
463 semaptr_new->sem_perm.mode = (semflg & 0777);
464 semaptr_new->sem_perm.seq = semseqs[semid] =
465 (semseqs[semid] + 1) & 0x7fff;
466 semaptr_new->sem_nsems = nsems;
467 semaptr_new->sem_otime = 0;
468 semaptr_new->sem_ctime = time_second;
469 sema[semid] = semaptr_new;
470 semtot += nsems;
471 } else {
472 DPRINTF(("didn't find it and wasn't asked to create it\n"));
473 return (ENOENT);
474 }
475
476 found:
477 *retval = IXSEQ_TO_IPCID(semid, sema[semid]->sem_perm);
478 return (0);
479 error:
480 if (semaptr_new != NULL) {
481 free(semaptr_new->sem_base, M_SEM);
482 pool_put(&sema_pool, semaptr_new);
483 }
484 return (error);
485 }
486
487 int
488 sys_semop(struct proc *p, void *v, register_t *retval)
489 {
490 struct sys_semop_args
491
492
493
494 *uap = v;
495 #define NSOPS 8
496 struct sembuf sopbuf[NSOPS];
497 int semid = SCARG(uap, semid);
498 size_t nsops = SCARG(uap, nsops);
499 struct sembuf *sops;
500 struct semid_ds *semaptr;
501 struct sembuf *sopptr = NULL;
502 struct sem *semptr = NULL;
503 struct sem_undo *suptr = NULL;
504 struct ucred *cred = p->p_ucred;
505 size_t i, j;
506 int do_wakeup, do_undos, error;
507
508 DPRINTF(("call to semop(%d, %p, %lu)\n", semid, SCARG(uap, sops),
509 (u_long)nsops));
510
511 semid = IPCID_TO_IX(semid);
512
513 if (semid < 0 || semid >= seminfo.semmni)
514 return (EINVAL);
515
516 if ((semaptr = sema[semid]) == NULL ||
517 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid)))
518 return (EINVAL);
519
520 if ((error = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
521 DPRINTF(("error = %d from ipaccess\n", error));
522 return (error);
523 }
524
525 if (nsops == 0) {
526 *retval = 0;
527 return (0);
528 } else if (nsops > (size_t)seminfo.semopm) {
529 DPRINTF(("too many sops (max=%d, nsops=%lu)\n", seminfo.semopm,
530 (u_long)nsops));
531 return (E2BIG);
532 }
533
534 if (nsops <= NSOPS)
535 sops = sopbuf;
536 else
537 sops = malloc(nsops * sizeof(struct sembuf), M_SEM, M_WAITOK);
538 error = copyin(SCARG(uap, sops), sops, nsops * sizeof(struct sembuf));
539 if (error != 0) {
540 DPRINTF(("error = %d from copyin(%p, %p, %u)\n", error,
541 SCARG(uap, sops), &sops, nsops * sizeof(struct sembuf)));
542 goto done2;
543 }
544
545
546
547
548
549
550
551
552
553
554 do_undos = 0;
555
556 for (;;) {
557 do_wakeup = 0;
558
559 for (i = 0; i < nsops; i++) {
560 sopptr = &sops[i];
561
562 if (sopptr->sem_num >= semaptr->sem_nsems) {
563 error = EFBIG;
564 goto done2;
565 }
566
567 semptr = &semaptr->sem_base[sopptr->sem_num];
568
569 DPRINTF(("semop: semaptr=%x, sem_base=%x, semptr=%x, sem[%d]=%d : op=%d, flag=%s\n",
570 semaptr, semaptr->sem_base, semptr,
571 sopptr->sem_num, semptr->semval, sopptr->sem_op,
572 (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"));
573
574 if (sopptr->sem_op < 0) {
575 if ((int)(semptr->semval +
576 sopptr->sem_op) < 0) {
577 DPRINTF(("semop: can't do it now\n"));
578 break;
579 } else {
580 semptr->semval += sopptr->sem_op;
581 if (semptr->semval == 0 &&
582 semptr->semzcnt > 0)
583 do_wakeup = 1;
584 }
585 if (sopptr->sem_flg & SEM_UNDO)
586 do_undos = 1;
587 } else if (sopptr->sem_op == 0) {
588 if (semptr->semval > 0) {
589 DPRINTF(("semop: not zero now\n"));
590 break;
591 }
592 } else {
593 if (semptr->semncnt > 0)
594 do_wakeup = 1;
595 semptr->semval += sopptr->sem_op;
596 if (sopptr->sem_flg & SEM_UNDO)
597 do_undos = 1;
598 }
599 }
600
601
602
603
604 if (i >= nsops)
605 goto done;
606
607
608
609
610 DPRINTF(("semop: rollback 0 through %d\n", i - 1));
611 for (j = 0; j < i; j++)
612 semaptr->sem_base[sops[j].sem_num].semval -=
613 sops[j].sem_op;
614
615
616
617
618
619 if (sopptr->sem_flg & IPC_NOWAIT) {
620 error = EAGAIN;
621 goto done2;
622 }
623
624 if (sopptr->sem_op == 0)
625 semptr->semzcnt++;
626 else
627 semptr->semncnt++;
628
629 DPRINTF(("semop: good night!\n"));
630 error = tsleep(&sema[semid], PLOCK | PCATCH,
631 "semwait", 0);
632 DPRINTF(("semop: good morning (error=%d)!\n", error));
633
634 suptr = NULL;
635
636
637
638
639 if (sema[semid] == NULL ||
640 semaptr->sem_perm.seq != IPCID_TO_SEQ(SCARG(uap, semid))) {
641 error = EIDRM;
642 goto done2;
643 }
644
645
646
647
648
649 if (sopptr->sem_op == 0)
650 semptr->semzcnt--;
651 else
652 semptr->semncnt--;
653
654
655
656
657
658
659 if (error != 0) {
660 error = EINTR;
661 goto done2;
662 }
663 DPRINTF(("semop: good morning!\n"));
664 }
665
666 done:
667
668
669
670 if (do_undos) {
671 for (i = 0; i < nsops; i++) {
672
673
674
675
676 int adjval;
677
678 if ((sops[i].sem_flg & SEM_UNDO) == 0)
679 continue;
680 adjval = sops[i].sem_op;
681 if (adjval == 0)
682 continue;
683 error = semundo_adjust(p, &suptr, semid,
684 sops[i].sem_num, -adjval);
685 if (error == 0)
686 continue;
687
688
689
690
691
692
693
694
695
696
697 if (i != 0) {
698 for (j = i - 1; j >= 0; j--) {
699 if ((sops[j].sem_flg & SEM_UNDO) == 0)
700 continue;
701 adjval = sops[j].sem_op;
702 if (adjval == 0)
703 continue;
704 if (semundo_adjust(p, &suptr, semid,
705 sops[j].sem_num, adjval) != 0)
706 panic("semop - can't undo undos");
707 }
708 }
709
710 for (j = 0; j < nsops; j++)
711 semaptr->sem_base[sops[j].sem_num].semval -=
712 sops[j].sem_op;
713
714 DPRINTF(("error = %d from semundo_adjust\n", error));
715 goto done2;
716 }
717 }
718
719
720 for (i = 0; i < nsops; i++) {
721 sopptr = &sops[i];
722 semptr = &semaptr->sem_base[sopptr->sem_num];
723 semptr->sempid = p->p_pid;
724 }
725
726
727 if (do_wakeup) {
728 DPRINTF(("semop: doing wakeup\n"));
729 wakeup(&sema[semid]);
730 DPRINTF(("semop: back from wakeup\n"));
731 }
732 DPRINTF(("semop: done\n"));
733 *retval = 0;
734 done2:
735 if (sops != sopbuf)
736 free(sops, M_SEM);
737 return (error);
738 }
739
740
741
742
743
744 void
745 semexit(struct proc *p)
746 {
747 struct sem_undo *suptr;
748 struct sem_undo **supptr;
749
750
751
752
753
754 SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) {
755 if (suptr->un_proc == p)
756 break;
757 }
758
759
760
761
762 if (suptr == NULL)
763 return;
764
765
766
767
768 DPRINTF(("proc @%p has undo structure with %d entries\n", p,
769 suptr->un_cnt));
770
771
772
773
774 if (suptr->un_cnt > 0) {
775 int ix;
776
777 for (ix = 0; ix < suptr->un_cnt; ix++) {
778 int semid = suptr->un_ent[ix].un_id;
779 int semnum = suptr->un_ent[ix].un_num;
780 int adjval = suptr->un_ent[ix].un_adjval;
781 struct semid_ds *semaptr;
782
783 if ((semaptr = sema[semid]) == NULL)
784 panic("semexit - semid not allocated");
785 if (semnum >= semaptr->sem_nsems)
786 panic("semexit - semnum out of range");
787
788 DPRINTF(("semexit: %p id=%d num=%d(adj=%d) ; sem=%d\n",
789 suptr->un_proc, suptr->un_ent[ix].un_id,
790 suptr->un_ent[ix].un_num,
791 suptr->un_ent[ix].un_adjval,
792 semaptr->sem_base[semnum].semval));
793
794 if (adjval < 0 &&
795 semaptr->sem_base[semnum].semval < -adjval)
796 semaptr->sem_base[semnum].semval = 0;
797 else
798 semaptr->sem_base[semnum].semval += adjval;
799
800 wakeup(&sema[semid]);
801 DPRINTF(("semexit: back from wakeup\n"));
802 }
803 }
804
805
806
807
808 DPRINTF(("removing vector\n"));
809 *supptr = SLIST_NEXT(suptr, un_next);
810 pool_put(&semu_pool, suptr);
811 semutot--;
812 }
813
814
815
816
817 int
818 sysctl_sysvsem(int *name, u_int namelen, void *oldp, size_t *oldlenp,
819 void *newp, size_t newlen)
820 {
821 int error, val;
822 struct semid_ds **sema_new;
823 unsigned short *newseqs;
824
825 if (namelen != 2) {
826 switch (name[0]) {
827 case KERN_SEMINFO_SEMMNI:
828 case KERN_SEMINFO_SEMMNS:
829 case KERN_SEMINFO_SEMMNU:
830 case KERN_SEMINFO_SEMMSL:
831 case KERN_SEMINFO_SEMOPM:
832 case KERN_SEMINFO_SEMUME:
833 case KERN_SEMINFO_SEMUSZ:
834 case KERN_SEMINFO_SEMVMX:
835 case KERN_SEMINFO_SEMAEM:
836 break;
837 default:
838 return (ENOTDIR);
839 }
840 }
841
842 switch (name[0]) {
843 case KERN_SEMINFO_SEMMNI:
844 val = seminfo.semmni;
845 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
846 val == seminfo.semmni)
847 return (error);
848
849 if (val < seminfo.semmni || val > 0xffff)
850 return (EINVAL);
851
852
853 sema_new = malloc(val * sizeof(struct semid_ds *),
854 M_SEM, M_WAITOK);
855 bcopy(sema, sema_new,
856 seminfo.semmni * sizeof(struct semid_ds *));
857 bzero(sema_new + seminfo.semmni,
858 (val - seminfo.semmni) * sizeof(struct semid_ds *));
859 newseqs = malloc(val * sizeof(unsigned short), M_SEM, M_WAITOK);
860 bcopy(semseqs, newseqs,
861 seminfo.semmni * sizeof(unsigned short));
862 bzero(newseqs + seminfo.semmni,
863 (val - seminfo.semmni) * sizeof(unsigned short));
864 free(sema, M_SEM);
865 free(semseqs, M_SEM);
866 sema = sema_new;
867 semseqs = newseqs;
868 seminfo.semmni = val;
869 return (0);
870 case KERN_SEMINFO_SEMMNS:
871 val = seminfo.semmns;
872 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
873 val == seminfo.semmns)
874 return (error);
875 if (val < seminfo.semmns || val > 0xffff)
876 return (EINVAL);
877 seminfo.semmns = val;
878 return (0);
879 case KERN_SEMINFO_SEMMNU:
880 val = seminfo.semmnu;
881 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
882 val == seminfo.semmnu)
883 return (error);
884 if (val < seminfo.semmnu)
885 return (EINVAL);
886 seminfo.semmnu = val;
887 return (0);
888 case KERN_SEMINFO_SEMMSL:
889 val = seminfo.semmsl;
890 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
891 val == seminfo.semmsl)
892 return (error);
893 if (val < seminfo.semmsl || val > 0xffff)
894 return (EINVAL);
895 seminfo.semmsl = val;
896 return (0);
897 case KERN_SEMINFO_SEMOPM:
898 val = seminfo.semopm;
899 if ((error = sysctl_int(oldp, oldlenp, newp, newlen, &val)) ||
900 val == seminfo.semopm)
901 return (error);
902 if (val <= 0)
903 return (EINVAL);
904 seminfo.semopm = val;
905 return (0);
906 case KERN_SEMINFO_SEMUME:
907 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semume));
908 case KERN_SEMINFO_SEMUSZ:
909 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semusz));
910 case KERN_SEMINFO_SEMVMX:
911 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semvmx));
912 case KERN_SEMINFO_SEMAEM:
913 return (sysctl_rdint(oldp, oldlenp, newp, seminfo.semaem));
914 default:
915 return (EOPNOTSUPP);
916 }
917
918 }