1 /* $NetBSD: sysv_msg.c,v 1.76 2019/10/04 23:20:22 kamil Exp $ */
2
3 /*-
4 * Copyright (c) 1999, 2006, 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center, and by Andrew Doran.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Implementation of SVID messages
35 *
36 * Author: Daniel Boulet
37 *
38 * Copyright 1993 Daniel Boulet and RTMX Inc.
39 *
40 * This system call was implemented by Daniel Boulet under contract from RTMX.
41 *
42 * Redistribution and use in source forms, with and without modification,
43 * are permitted provided that this entire comment appears intact.
44 *
45 * Redistribution in binary form may occur without any restrictions.
46 * Obviously, it would be nice if you gave credit where credit is due
47 * but requiring it would be too onerous.
48 *
49 * This software is provided ``AS IS'' without any warranties of any kind.
50 */
51
52 #include <sys/cdefs.h>
53 __KERNEL_RCSID(0, "$NetBSD: sysv_msg.c,v 1.76 2019/10/04 23:20:22 kamil Exp $");
54
55 #ifdef _KERNEL_OPT
56 #include "opt_sysv.h"
57 #endif
58
59 #include <sys/param.h>
60 #include <sys/kernel.h>
61 #include <sys/msg.h>
62 #include <sys/sysctl.h>
63 #include <sys/mount.h> /* XXX for <sys/syscallargs.h> */
64 #include <sys/syscallargs.h>
65 #include <sys/kauth.h>
66
67 #define MSG_DEBUG
68 #undef MSG_DEBUG_OK
69
70 #ifdef MSG_DEBUG_OK
71 #define MSG_PRINTF(a) printf a
72 #else
73 #define MSG_PRINTF(a)
74 #endif
75
76 static int nfree_msgmaps; /* # of free map entries */
77 static short free_msgmaps; /* head of linked list of free map entries */
78 static struct __msg *free_msghdrs; /* list of free msg headers */
79 static char *msgpool; /* MSGMAX byte long msg buffer pool */
80 static struct msgmap *msgmaps; /* MSGSEG msgmap structures */
81 static struct __msg *msghdrs; /* MSGTQL msg headers */
82
83 kmsq_t *msqs; /* MSGMNI msqid_ds struct's */
84 kmutex_t msgmutex; /* subsystem lock */
85
86 static u_int msg_waiters = 0; /* total number of msgrcv waiters */
87 static bool msg_realloc_state;
88 static kcondvar_t msg_realloc_cv;
89
90 static void msg_freehdr(struct __msg *);
91
92 extern int kern_has_sysvmsg;
93
94 SYSCTL_SETUP_PROTO(sysctl_ipc_msg_setup);
95
96 int
msginit(void)97 msginit(void)
98 {
99 int i, sz;
100 vaddr_t v;
101
102 /*
103 * msginfo.msgssz should be a power of two for efficiency reasons.
104 * It is also pretty silly if msginfo.msgssz is less than 8
105 * or greater than about 256 so ...
106 */
107
108 i = 8;
109 while (i < 1024 && i != msginfo.msgssz)
110 i <<= 1;
111 if (i != msginfo.msgssz) {
112 printf("msginfo.msgssz = %d, not a small power of 2",
113 msginfo.msgssz);
114 return EINVAL;
115 }
116
117 if (msginfo.msgseg > 32767) {
118 printf("msginfo.msgseg = %d > 32767", msginfo.msgseg);
119 return EINVAL;
120 }
121
122 /* Allocate the wired memory for our structures */
123 sz = ALIGN(msginfo.msgmax) +
124 ALIGN(msginfo.msgseg * sizeof(struct msgmap)) +
125 ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
126 ALIGN(msginfo.msgmni * sizeof(kmsq_t));
127 sz = round_page(sz);
128 v = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
129 if (v == 0) {
130 printf("sysv_msg: cannot allocate memory");
131 return ENOMEM;
132 }
133 msgpool = (void *)v;
134 msgmaps = (void *)((uintptr_t)msgpool + ALIGN(msginfo.msgmax));
135 msghdrs = (void *)((uintptr_t)msgmaps +
136 ALIGN(msginfo.msgseg * sizeof(struct msgmap)));
137 msqs = (void *)((uintptr_t)msghdrs +
138 ALIGN(msginfo.msgtql * sizeof(struct __msg)));
139
140 for (i = 0; i < (msginfo.msgseg - 1); i++)
141 msgmaps[i].next = i + 1;
142 msgmaps[msginfo.msgseg - 1].next = -1;
143
144 free_msgmaps = 0;
145 nfree_msgmaps = msginfo.msgseg;
146
147 for (i = 0; i < (msginfo.msgtql - 1); i++) {
148 msghdrs[i].msg_type = 0;
149 msghdrs[i].msg_next = &msghdrs[i + 1];
150 }
151 i = msginfo.msgtql - 1;
152 msghdrs[i].msg_type = 0;
153 msghdrs[i].msg_next = NULL;
154 free_msghdrs = &msghdrs[0];
155
156 for (i = 0; i < msginfo.msgmni; i++) {
157 cv_init(&msqs[i].msq_cv, "msgwait");
158 /* Implies entry is available */
159 msqs[i].msq_u.msg_qbytes = 0;
160 /* Reset to a known value */
161 msqs[i].msq_u.msg_perm._seq = 0;
162 }
163
164 mutex_init(&msgmutex, MUTEX_DEFAULT, IPL_NONE);
165 cv_init(&msg_realloc_cv, "msgrealc");
166 msg_realloc_state = false;
167
168 kern_has_sysvmsg = 1;
169
170 return 0;
171 }
172
173 int
msgfini(void)174 msgfini(void)
175 {
176 int i, sz;
177 vaddr_t v = (vaddr_t)msgpool;
178
179 mutex_enter(&msgmutex);
180 for (i = 0; i < msginfo.msgmni; i++) {
181 if (msqs[i].msq_u.msg_qbytes != 0) {
182 mutex_exit(&msgmutex);
183 return 1; /* queue not available, prevent unload! */
184 }
185 }
186 /*
187 * Destroy all condvars and free the memory we're using
188 */
189 for (i = 0; i < msginfo.msgmni; i++) {
190 cv_destroy(&msqs[i].msq_cv);
191 }
192 sz = ALIGN(msginfo.msgmax) +
193 ALIGN(msginfo.msgseg * sizeof(struct msgmap)) +
194 ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
195 ALIGN(msginfo.msgmni * sizeof(kmsq_t));
196 sz = round_page(sz);
197 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED);
198
199 cv_destroy(&msg_realloc_cv);
200 mutex_exit(&msgmutex);
201 mutex_destroy(&msgmutex);
202
203 kern_has_sysvmsg = 0;
204
205 return 0;
206 }
207
208 static int
msgrealloc(int newmsgmni,int newmsgseg)209 msgrealloc(int newmsgmni, int newmsgseg)
210 {
211 struct msgmap *new_msgmaps;
212 struct __msg *new_msghdrs, *new_free_msghdrs;
213 char *old_msgpool, *new_msgpool;
214 kmsq_t *new_msqs;
215 vaddr_t v;
216 int i, sz, msqid, newmsgmax, new_nfree_msgmaps;
217 short new_free_msgmaps;
218
219 if (newmsgmni < 1 || newmsgseg < 1)
220 return EINVAL;
221
222 /* Allocate the wired memory for our structures */
223 newmsgmax = msginfo.msgssz * newmsgseg;
224 sz = ALIGN(newmsgmax) +
225 ALIGN(newmsgseg * sizeof(struct msgmap)) +
226 ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
227 ALIGN(newmsgmni * sizeof(kmsq_t));
228 sz = round_page(sz);
229 v = uvm_km_alloc(kernel_map, sz, 0, UVM_KMF_WIRED|UVM_KMF_ZERO);
230 if (v == 0)
231 return ENOMEM;
232
233 mutex_enter(&msgmutex);
234 if (msg_realloc_state) {
235 mutex_exit(&msgmutex);
236 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED);
237 return EBUSY;
238 }
239 msg_realloc_state = true;
240 if (msg_waiters) {
241 /*
242 * Mark reallocation state, wake-up all waiters,
243 * and wait while they will all exit.
244 */
245 for (i = 0; i < msginfo.msgmni; i++)
246 cv_broadcast(&msqs[i].msq_cv);
247 while (msg_waiters)
248 cv_wait(&msg_realloc_cv, &msgmutex);
249 }
250 old_msgpool = msgpool;
251
252 /* We cannot reallocate less memory than we use */
253 i = 0;
254 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
255 struct msqid_ds *mptr;
256 kmsq_t *msq;
257
258 msq = &msqs[msqid];
259 mptr = &msq->msq_u;
260 if (mptr->msg_qbytes || (mptr->msg_perm.mode & MSG_LOCKED))
261 i = msqid;
262 }
263 if (i >= newmsgmni || (msginfo.msgseg - nfree_msgmaps) > newmsgseg) {
264 mutex_exit(&msgmutex);
265 uvm_km_free(kernel_map, v, sz, UVM_KMF_WIRED);
266 return EBUSY;
267 }
268
269 new_msgpool = (void *)v;
270 new_msgmaps = (void *)((uintptr_t)new_msgpool + ALIGN(newmsgmax));
271 new_msghdrs = (void *)((uintptr_t)new_msgmaps +
272 ALIGN(newmsgseg * sizeof(struct msgmap)));
273 new_msqs = (void *)((uintptr_t)new_msghdrs +
274 ALIGN(msginfo.msgtql * sizeof(struct __msg)));
275
276 /* Initialize the structures */
277 for (i = 0; i < (newmsgseg - 1); i++)
278 new_msgmaps[i].next = i + 1;
279 new_msgmaps[newmsgseg - 1].next = -1;
280 new_free_msgmaps = 0;
281 new_nfree_msgmaps = newmsgseg;
282
283 for (i = 0; i < (msginfo.msgtql - 1); i++) {
284 new_msghdrs[i].msg_type = 0;
285 new_msghdrs[i].msg_next = &new_msghdrs[i + 1];
286 }
287 i = msginfo.msgtql - 1;
288 new_msghdrs[i].msg_type = 0;
289 new_msghdrs[i].msg_next = NULL;
290 new_free_msghdrs = &new_msghdrs[0];
291
292 for (i = 0; i < newmsgmni; i++) {
293 new_msqs[i].msq_u.msg_qbytes = 0;
294 new_msqs[i].msq_u.msg_perm._seq = 0;
295 cv_init(&new_msqs[i].msq_cv, "msgwait");
296 }
297
298 /*
299 * Copy all message queue identifiers, message headers and buffer
300 * pools to the new memory location.
301 */
302 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
303 struct __msg *nmsghdr, *msghdr, *pmsghdr;
304 struct msqid_ds *nmptr, *mptr;
305 kmsq_t *nmsq, *msq;
306
307 msq = &msqs[msqid];
308 mptr = &msq->msq_u;
309
310 if (mptr->msg_qbytes == 0 &&
311 (mptr->msg_perm.mode & MSG_LOCKED) == 0)
312 continue;
313
314 nmsq = &new_msqs[msqid];
315 nmptr = &nmsq->msq_u;
316 memcpy(nmptr, mptr, sizeof(struct msqid_ds));
317
318 /*
319 * Go through the message headers, and copy each one
320 * by taking the new ones, and thus defragmenting.
321 */
322 nmsghdr = pmsghdr = NULL;
323 msghdr = mptr->_msg_first;
324 while (msghdr) {
325 short nnext = 0, next;
326 u_short msgsz, segcnt;
327
328 /* Take an entry from the new list of free msghdrs */
329 nmsghdr = new_free_msghdrs;
330 KASSERT(nmsghdr != NULL);
331 new_free_msghdrs = nmsghdr->msg_next;
332
333 nmsghdr->msg_next = NULL;
334 if (pmsghdr) {
335 pmsghdr->msg_next = nmsghdr;
336 } else {
337 nmptr->_msg_first = nmsghdr;
338 pmsghdr = nmsghdr;
339 }
340 nmsghdr->msg_ts = msghdr->msg_ts;
341 nmsghdr->msg_spot = -1;
342
343 /* Compute the amount of segments and reserve them */
344 msgsz = msghdr->msg_ts;
345 segcnt = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
346 if (segcnt == 0)
347 continue;
348 while (segcnt--) {
349 nnext = new_free_msgmaps;
350 new_free_msgmaps = new_msgmaps[nnext].next;
351 new_nfree_msgmaps--;
352 new_msgmaps[nnext].next = nmsghdr->msg_spot;
353 nmsghdr->msg_spot = nnext;
354 }
355
356 /* Copy all segments */
357 KASSERT(nnext == nmsghdr->msg_spot);
358 next = msghdr->msg_spot;
359 while (msgsz > 0) {
360 size_t tlen;
361
362 if (msgsz >= msginfo.msgssz) {
363 tlen = msginfo.msgssz;
364 msgsz -= msginfo.msgssz;
365 } else {
366 tlen = msgsz;
367 msgsz = 0;
368 }
369
370 /* Copy the message buffer */
371 memcpy(&new_msgpool[nnext * msginfo.msgssz],
372 &msgpool[next * msginfo.msgssz], tlen);
373
374 /* Next entry of the map */
375 nnext = msgmaps[nnext].next;
376 next = msgmaps[next].next;
377 }
378
379 /* Next message header */
380 msghdr = msghdr->msg_next;
381 }
382 nmptr->_msg_last = nmsghdr;
383 }
384 KASSERT((msginfo.msgseg - nfree_msgmaps) ==
385 (newmsgseg - new_nfree_msgmaps));
386
387 sz = ALIGN(msginfo.msgmax) +
388 ALIGN(msginfo.msgseg * sizeof(struct msgmap)) +
389 ALIGN(msginfo.msgtql * sizeof(struct __msg)) +
390 ALIGN(msginfo.msgmni * sizeof(kmsq_t));
391 sz = round_page(sz);
392
393 for (i = 0; i < msginfo.msgmni; i++)
394 cv_destroy(&msqs[i].msq_cv);
395
396 /* Set the pointers and update the new values */
397 msgpool = new_msgpool;
398 msgmaps = new_msgmaps;
399 msghdrs = new_msghdrs;
400 msqs = new_msqs;
401
402 free_msghdrs = new_free_msghdrs;
403 free_msgmaps = new_free_msgmaps;
404 nfree_msgmaps = new_nfree_msgmaps;
405 msginfo.msgmni = newmsgmni;
406 msginfo.msgseg = newmsgseg;
407 msginfo.msgmax = newmsgmax;
408
409 /* Reallocation completed - notify all waiters, if any */
410 msg_realloc_state = false;
411 cv_broadcast(&msg_realloc_cv);
412 mutex_exit(&msgmutex);
413
414 uvm_km_free(kernel_map, (vaddr_t)old_msgpool, sz, UVM_KMF_WIRED);
415 return 0;
416 }
417
418 static void
msg_freehdr(struct __msg * msghdr)419 msg_freehdr(struct __msg *msghdr)
420 {
421
422 KASSERT(mutex_owned(&msgmutex));
423
424 while (msghdr->msg_ts > 0) {
425 short next;
426 KASSERT(msghdr->msg_spot >= 0);
427 KASSERT(msghdr->msg_spot < msginfo.msgseg);
428
429 next = msgmaps[msghdr->msg_spot].next;
430 msgmaps[msghdr->msg_spot].next = free_msgmaps;
431 free_msgmaps = msghdr->msg_spot;
432 nfree_msgmaps++;
433 msghdr->msg_spot = next;
434 if (msghdr->msg_ts >= msginfo.msgssz)
435 msghdr->msg_ts -= msginfo.msgssz;
436 else
437 msghdr->msg_ts = 0;
438 }
439 KASSERT(msghdr->msg_spot == -1);
440 msghdr->msg_next = free_msghdrs;
441 free_msghdrs = msghdr;
442 }
443
444 int
sys___msgctl50(struct lwp * l,const struct sys___msgctl50_args * uap,register_t * retval)445 sys___msgctl50(struct lwp *l, const struct sys___msgctl50_args *uap,
446 register_t *retval)
447 {
448 /* {
449 syscallarg(int) msqid;
450 syscallarg(int) cmd;
451 syscallarg(struct msqid_ds *) buf;
452 } */
453 struct msqid_ds msqbuf;
454 int cmd, error;
455
456 cmd = SCARG(uap, cmd);
457
458 if (cmd == IPC_SET) {
459 error = copyin(SCARG(uap, buf), &msqbuf, sizeof(msqbuf));
460 if (error)
461 return (error);
462 }
463
464 error = msgctl1(l, SCARG(uap, msqid), cmd,
465 (cmd == IPC_SET || cmd == IPC_STAT) ? &msqbuf : NULL);
466
467 if (error == 0 && cmd == IPC_STAT)
468 error = copyout(&msqbuf, SCARG(uap, buf), sizeof(msqbuf));
469
470 return (error);
471 }
472
473 int
msgctl1(struct lwp * l,int msqid,int cmd,struct msqid_ds * msqbuf)474 msgctl1(struct lwp *l, int msqid, int cmd, struct msqid_ds *msqbuf)
475 {
476 kauth_cred_t cred = l->l_cred;
477 struct msqid_ds *msqptr;
478 kmsq_t *msq;
479 int error = 0, ix;
480
481 MSG_PRINTF(("call to msgctl1(%d, %d)\n", msqid, cmd));
482
483 ix = IPCID_TO_IX(msqid);
484
485 mutex_enter(&msgmutex);
486
487 if (ix < 0 || ix >= msginfo.msgmni) {
488 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", ix,
489 msginfo.msgmni));
490 error = EINVAL;
491 goto unlock;
492 }
493
494 msq = &msqs[ix];
495 msqptr = &msq->msq_u;
496
497 if (msqptr->msg_qbytes == 0) {
498 MSG_PRINTF(("no such msqid\n"));
499 error = EINVAL;
500 goto unlock;
501 }
502 if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqid)) {
503 MSG_PRINTF(("wrong sequence number\n"));
504 error = EINVAL;
505 goto unlock;
506 }
507
508 switch (cmd) {
509 case IPC_RMID:
510 {
511 struct __msg *msghdr;
512 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)) != 0)
513 break;
514 /* Free the message headers */
515 msghdr = msqptr->_msg_first;
516 while (msghdr != NULL) {
517 struct __msg *msghdr_tmp;
518
519 /* Free the segments of each message */
520 msqptr->_msg_cbytes -= msghdr->msg_ts;
521 msqptr->msg_qnum--;
522 msghdr_tmp = msghdr;
523 msghdr = msghdr->msg_next;
524 msg_freehdr(msghdr_tmp);
525 }
526 KASSERT(msqptr->_msg_cbytes == 0);
527 KASSERT(msqptr->msg_qnum == 0);
528
529 /* Mark it as free */
530 msqptr->msg_qbytes = 0;
531 cv_broadcast(&msq->msq_cv);
532 }
533 break;
534
535 case IPC_SET:
536 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_M)))
537 break;
538 if (msqbuf->msg_qbytes > msqptr->msg_qbytes &&
539 kauth_authorize_system(cred, KAUTH_SYSTEM_SYSVIPC,
540 KAUTH_REQ_SYSTEM_SYSVIPC_MSGQ_OVERSIZE,
541 KAUTH_ARG(msqbuf->msg_qbytes),
542 KAUTH_ARG(msqptr->msg_qbytes), NULL) != 0) {
543 error = EPERM;
544 break;
545 }
546 if (msqbuf->msg_qbytes > msginfo.msgmnb) {
547 MSG_PRINTF(("can't increase msg_qbytes beyond %d "
548 "(truncating)\n", msginfo.msgmnb));
549 /* silently restrict qbytes to system limit */
550 msqbuf->msg_qbytes = msginfo.msgmnb;
551 }
552 if (msqbuf->msg_qbytes == 0) {
553 MSG_PRINTF(("can't reduce msg_qbytes to 0\n"));
554 error = EINVAL; /* XXX non-standard errno! */
555 break;
556 }
557 msqptr->msg_perm.uid = msqbuf->msg_perm.uid;
558 msqptr->msg_perm.gid = msqbuf->msg_perm.gid;
559 msqptr->msg_perm.mode = (msqptr->msg_perm.mode & ~0777) |
560 (msqbuf->msg_perm.mode & 0777);
561 msqptr->msg_qbytes = msqbuf->msg_qbytes;
562 msqptr->msg_ctime = time_second;
563 break;
564
565 case IPC_STAT:
566 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
567 MSG_PRINTF(("requester doesn't have read access\n"));
568 break;
569 }
570 memset(msqbuf, 0, sizeof *msqbuf);
571 msqbuf->msg_perm = msqptr->msg_perm;
572 msqbuf->msg_perm.mode &= 0777;
573 msqbuf->msg_qnum = msqptr->msg_qnum;
574 msqbuf->msg_qbytes = msqptr->msg_qbytes;
575 msqbuf->msg_lspid = msqptr->msg_lspid;
576 msqbuf->msg_lrpid = msqptr->msg_lrpid;
577 msqbuf->msg_stime = msqptr->msg_stime;
578 msqbuf->msg_rtime = msqptr->msg_rtime;
579 msqbuf->msg_ctime = msqptr->msg_ctime;
580 break;
581
582 default:
583 MSG_PRINTF(("invalid command %d\n", cmd));
584 error = EINVAL;
585 break;
586 }
587
588 unlock:
589 mutex_exit(&msgmutex);
590 return (error);
591 }
592
593 int
sys_msgget(struct lwp * l,const struct sys_msgget_args * uap,register_t * retval)594 sys_msgget(struct lwp *l, const struct sys_msgget_args *uap, register_t *retval)
595 {
596 /* {
597 syscallarg(key_t) key;
598 syscallarg(int) msgflg;
599 } */
600 int msqid, error = 0;
601 int key = SCARG(uap, key);
602 int msgflg = SCARG(uap, msgflg);
603 kauth_cred_t cred = l->l_cred;
604 struct msqid_ds *msqptr = NULL;
605 kmsq_t *msq;
606
607 mutex_enter(&msgmutex);
608
609 MSG_PRINTF(("msgget(0x%x, 0%o)\n", key, msgflg));
610
611 if (key != IPC_PRIVATE) {
612 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
613 msq = &msqs[msqid];
614 msqptr = &msq->msq_u;
615 if (msqptr->msg_qbytes != 0 &&
616 msqptr->msg_perm._key == key)
617 break;
618 }
619 if (msqid < msginfo.msgmni) {
620 MSG_PRINTF(("found public key\n"));
621 if ((msgflg & IPC_CREAT) && (msgflg & IPC_EXCL)) {
622 MSG_PRINTF(("not exclusive\n"));
623 error = EEXIST;
624 goto unlock;
625 }
626 if ((error = ipcperm(cred, &msqptr->msg_perm,
627 msgflg & 0700 ))) {
628 MSG_PRINTF(("requester doesn't have 0%o access\n",
629 msgflg & 0700));
630 goto unlock;
631 }
632 goto found;
633 }
634 }
635
636 MSG_PRINTF(("need to allocate the msqid_ds\n"));
637 if (key == IPC_PRIVATE || (msgflg & IPC_CREAT)) {
638 for (msqid = 0; msqid < msginfo.msgmni; msqid++) {
639 /*
640 * Look for an unallocated and unlocked msqid_ds.
641 * msqid_ds's can be locked by msgsnd or msgrcv while
642 * they are copying the message in/out. We can't
643 * re-use the entry until they release it.
644 */
645 msq = &msqs[msqid];
646 msqptr = &msq->msq_u;
647 if (msqptr->msg_qbytes == 0 &&
648 (msqptr->msg_perm.mode & MSG_LOCKED) == 0)
649 break;
650 }
651 if (msqid == msginfo.msgmni) {
652 MSG_PRINTF(("no more msqid_ds's available\n"));
653 error = ENOSPC;
654 goto unlock;
655 }
656 MSG_PRINTF(("msqid %d is available\n", msqid));
657 msqptr->msg_perm._key = key;
658 msqptr->msg_perm.cuid = kauth_cred_geteuid(cred);
659 msqptr->msg_perm.uid = kauth_cred_geteuid(cred);
660 msqptr->msg_perm.cgid = kauth_cred_getegid(cred);
661 msqptr->msg_perm.gid = kauth_cred_getegid(cred);
662 msqptr->msg_perm.mode = (msgflg & 0777);
663 /* Make sure that the returned msqid is unique */
664 msqptr->msg_perm._seq++;
665 msqptr->_msg_first = NULL;
666 msqptr->_msg_last = NULL;
667 msqptr->_msg_cbytes = 0;
668 msqptr->msg_qnum = 0;
669 msqptr->msg_qbytes = msginfo.msgmnb;
670 msqptr->msg_lspid = 0;
671 msqptr->msg_lrpid = 0;
672 msqptr->msg_stime = 0;
673 msqptr->msg_rtime = 0;
674 msqptr->msg_ctime = time_second;
675 } else {
676 MSG_PRINTF(("didn't find it and wasn't asked to create it\n"));
677 error = ENOENT;
678 goto unlock;
679 }
680
681 found:
682 /* Construct the unique msqid */
683 *retval = IXSEQ_TO_IPCID(msqid, msqptr->msg_perm);
684
685 unlock:
686 mutex_exit(&msgmutex);
687 return (error);
688 }
689
690 int
sys_msgsnd(struct lwp * l,const struct sys_msgsnd_args * uap,register_t * retval)691 sys_msgsnd(struct lwp *l, const struct sys_msgsnd_args *uap, register_t *retval)
692 {
693 /* {
694 syscallarg(int) msqid;
695 syscallarg(const void *) msgp;
696 syscallarg(size_t) msgsz;
697 syscallarg(int) msgflg;
698 } */
699
700 return msgsnd1(l, SCARG(uap, msqid), SCARG(uap, msgp),
701 SCARG(uap, msgsz), SCARG(uap, msgflg), sizeof(long), copyin);
702 }
703
704 int
msgsnd1(struct lwp * l,int msqidr,const char * user_msgp,size_t msgsz,int msgflg,size_t typesz,copyin_t fetch_type)705 msgsnd1(struct lwp *l, int msqidr, const char *user_msgp, size_t msgsz,
706 int msgflg, size_t typesz, copyin_t fetch_type)
707 {
708 int segs_needed, error = 0, msqid;
709 kauth_cred_t cred = l->l_cred;
710 struct msqid_ds *msqptr;
711 struct __msg *msghdr;
712 kmsq_t *msq;
713 short next;
714
715 MSG_PRINTF(("call to msgsnd(%d, %p, %lld, %d)\n", msqidr,
716 user_msgp, (long long)msgsz, msgflg));
717
718 if ((ssize_t)msgsz < 0)
719 return EINVAL;
720
721 restart:
722 msqid = IPCID_TO_IX(msqidr);
723
724 mutex_enter(&msgmutex);
725 /* In case of reallocation, we will wait for completion */
726 while (__predict_false(msg_realloc_state))
727 cv_wait(&msg_realloc_cv, &msgmutex);
728
729 if (msqid < 0 || msqid >= msginfo.msgmni) {
730 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
731 msginfo.msgmni));
732 error = EINVAL;
733 goto unlock;
734 }
735
736 msq = &msqs[msqid];
737 msqptr = &msq->msq_u;
738
739 if (msqptr->msg_qbytes == 0) {
740 MSG_PRINTF(("no such message queue id\n"));
741 error = EINVAL;
742 goto unlock;
743 }
744 if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
745 MSG_PRINTF(("wrong sequence number\n"));
746 error = EINVAL;
747 goto unlock;
748 }
749
750 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
751 MSG_PRINTF(("requester doesn't have write access\n"));
752 goto unlock;
753 }
754
755 segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz;
756 MSG_PRINTF(("msgsz=%lld, msgssz=%d, segs_needed=%d\n",
757 (long long)msgsz, msginfo.msgssz, segs_needed));
758 for (;;) {
759 int need_more_resources = 0;
760
761 /*
762 * check msgsz [cannot be negative since it is unsigned]
763 * (inside this loop in case msg_qbytes changes while we sleep)
764 */
765
766 if (msgsz > msqptr->msg_qbytes) {
767 MSG_PRINTF(("msgsz > msqptr->msg_qbytes\n"));
768 error = EINVAL;
769 goto unlock;
770 }
771
772 if (msqptr->msg_perm.mode & MSG_LOCKED) {
773 MSG_PRINTF(("msqid is locked\n"));
774 need_more_resources = 1;
775 }
776 if (msgsz + msqptr->_msg_cbytes > msqptr->msg_qbytes) {
777 MSG_PRINTF(("msgsz + msg_cbytes > msg_qbytes\n"));
778 need_more_resources = 1;
779 }
780 if (segs_needed > nfree_msgmaps) {
781 MSG_PRINTF(("segs_needed > nfree_msgmaps\n"));
782 need_more_resources = 1;
783 }
784 if (free_msghdrs == NULL) {
785 MSG_PRINTF(("no more msghdrs\n"));
786 need_more_resources = 1;
787 }
788
789 if (need_more_resources) {
790 int we_own_it;
791
792 if ((msgflg & IPC_NOWAIT) != 0) {
793 MSG_PRINTF(("need more resources but caller "
794 "doesn't want to wait\n"));
795 error = EAGAIN;
796 goto unlock;
797 }
798
799 if ((msqptr->msg_perm.mode & MSG_LOCKED) != 0) {
800 MSG_PRINTF(("we don't own the msqid_ds\n"));
801 we_own_it = 0;
802 } else {
803 /* Force later arrivals to wait for our
804 request */
805 MSG_PRINTF(("we own the msqid_ds\n"));
806 msqptr->msg_perm.mode |= MSG_LOCKED;
807 we_own_it = 1;
808 }
809
810 msg_waiters++;
811 MSG_PRINTF(("goodnight\n"));
812 error = cv_wait_sig(&msq->msq_cv, &msgmutex);
813 MSG_PRINTF(("good morning, error=%d\n", error));
814 msg_waiters--;
815
816 if (we_own_it)
817 msqptr->msg_perm.mode &= ~MSG_LOCKED;
818
819 /*
820 * In case of such state, notify reallocator and
821 * restart the call.
822 */
823 if (msg_realloc_state) {
824 cv_broadcast(&msg_realloc_cv);
825 mutex_exit(&msgmutex);
826 goto restart;
827 }
828
829 if (error != 0) {
830 MSG_PRINTF(("msgsnd: interrupted system "
831 "call\n"));
832 error = EINTR;
833 goto unlock;
834 }
835
836 /*
837 * Make sure that the msq queue still exists
838 */
839
840 if (msqptr->msg_qbytes == 0) {
841 MSG_PRINTF(("msqid deleted\n"));
842 error = EIDRM;
843 goto unlock;
844 }
845 } else {
846 MSG_PRINTF(("got all the resources that we need\n"));
847 break;
848 }
849 }
850
851 /*
852 * We have the resources that we need.
853 * Make sure!
854 */
855
856 KASSERT((msqptr->msg_perm.mode & MSG_LOCKED) == 0);
857 KASSERT(segs_needed <= nfree_msgmaps);
858 KASSERT(msgsz + msqptr->_msg_cbytes <= msqptr->msg_qbytes);
859 KASSERT(free_msghdrs != NULL);
860
861 /*
862 * Re-lock the msqid_ds in case we page-fault when copying in the
863 * message
864 */
865
866 KASSERT((msqptr->msg_perm.mode & MSG_LOCKED) == 0);
867 msqptr->msg_perm.mode |= MSG_LOCKED;
868
869 /*
870 * Allocate a message header
871 */
872
873 msghdr = free_msghdrs;
874 free_msghdrs = msghdr->msg_next;
875 msghdr->msg_spot = -1;
876 msghdr->msg_ts = msgsz;
877
878 /*
879 * Allocate space for the message
880 */
881
882 while (segs_needed > 0) {
883 KASSERT(nfree_msgmaps > 0);
884 KASSERT(free_msgmaps != -1);
885 KASSERT(free_msgmaps < msginfo.msgseg);
886
887 next = free_msgmaps;
888 MSG_PRINTF(("allocating segment %d to message\n", next));
889 free_msgmaps = msgmaps[next].next;
890 nfree_msgmaps--;
891 msgmaps[next].next = msghdr->msg_spot;
892 msghdr->msg_spot = next;
893 segs_needed--;
894 }
895
896 /*
897 * Copy in the message type
898 */
899 mutex_exit(&msgmutex);
900 error = (*fetch_type)(user_msgp, &msghdr->msg_type, typesz);
901 mutex_enter(&msgmutex);
902 if (error != 0) {
903 MSG_PRINTF(("error %d copying the message type\n", error));
904 msg_freehdr(msghdr);
905 msqptr->msg_perm.mode &= ~MSG_LOCKED;
906 cv_broadcast(&msq->msq_cv);
907 goto unlock;
908 }
909 user_msgp += typesz;
910
911 /*
912 * Validate the message type
913 */
914
915 if (msghdr->msg_type < 1) {
916 msg_freehdr(msghdr);
917 msqptr->msg_perm.mode &= ~MSG_LOCKED;
918 cv_broadcast(&msq->msq_cv);
919 MSG_PRINTF(("mtype (%ld) < 1\n", msghdr->msg_type));
920 error = EINVAL;
921 goto unlock;
922 }
923
924 /*
925 * Copy in the message body
926 */
927
928 next = msghdr->msg_spot;
929 while (msgsz > 0) {
930 size_t tlen;
931 KASSERT(next > -1);
932 KASSERT(next < msginfo.msgseg);
933
934 if (msgsz > msginfo.msgssz)
935 tlen = msginfo.msgssz;
936 else
937 tlen = msgsz;
938 mutex_exit(&msgmutex);
939 error = copyin(user_msgp, &msgpool[next * msginfo.msgssz], tlen);
940 mutex_enter(&msgmutex);
941 if (error != 0) {
942 MSG_PRINTF(("error %d copying in message segment\n",
943 error));
944 msg_freehdr(msghdr);
945 msqptr->msg_perm.mode &= ~MSG_LOCKED;
946 cv_broadcast(&msq->msq_cv);
947 goto unlock;
948 }
949 msgsz -= tlen;
950 user_msgp += tlen;
951 next = msgmaps[next].next;
952 }
953 KASSERT(next == -1);
954
955 /*
956 * We've got the message. Unlock the msqid_ds.
957 */
958
959 msqptr->msg_perm.mode &= ~MSG_LOCKED;
960
961 /*
962 * Make sure that the msqid_ds is still allocated.
963 */
964
965 if (msqptr->msg_qbytes == 0) {
966 msg_freehdr(msghdr);
967 cv_broadcast(&msq->msq_cv);
968 error = EIDRM;
969 goto unlock;
970 }
971
972 /*
973 * Put the message into the queue
974 */
975
976 if (msqptr->_msg_first == NULL) {
977 msqptr->_msg_first = msghdr;
978 msqptr->_msg_last = msghdr;
979 } else {
980 msqptr->_msg_last->msg_next = msghdr;
981 msqptr->_msg_last = msghdr;
982 }
983 msqptr->_msg_last->msg_next = NULL;
984
985 msqptr->_msg_cbytes += msghdr->msg_ts;
986 msqptr->msg_qnum++;
987 msqptr->msg_lspid = l->l_proc->p_pid;
988 msqptr->msg_stime = time_second;
989
990 cv_broadcast(&msq->msq_cv);
991
992 unlock:
993 mutex_exit(&msgmutex);
994 return error;
995 }
996
997 int
sys_msgrcv(struct lwp * l,const struct sys_msgrcv_args * uap,register_t * retval)998 sys_msgrcv(struct lwp *l, const struct sys_msgrcv_args *uap, register_t *retval)
999 {
1000 /* {
1001 syscallarg(int) msqid;
1002 syscallarg(void *) msgp;
1003 syscallarg(size_t) msgsz;
1004 syscallarg(long) msgtyp;
1005 syscallarg(int) msgflg;
1006 } */
1007
1008 return msgrcv1(l, SCARG(uap, msqid), SCARG(uap, msgp),
1009 SCARG(uap, msgsz), SCARG(uap, msgtyp), SCARG(uap, msgflg),
1010 sizeof(long), copyout, retval);
1011 }
1012
1013 int
msgrcv1(struct lwp * l,int msqidr,char * user_msgp,size_t msgsz,long msgtyp,int msgflg,size_t typesz,copyout_t put_type,register_t * retval)1014 msgrcv1(struct lwp *l, int msqidr, char *user_msgp, size_t msgsz, long msgtyp,
1015 int msgflg, size_t typesz, copyout_t put_type, register_t *retval)
1016 {
1017 size_t len;
1018 kauth_cred_t cred = l->l_cred;
1019 struct msqid_ds *msqptr;
1020 struct __msg *msghdr;
1021 int error = 0, msqid;
1022 kmsq_t *msq;
1023 short next;
1024
1025 MSG_PRINTF(("call to msgrcv(%d, %p, %lld, %ld, %d)\n", msqidr,
1026 user_msgp, (long long)msgsz, msgtyp, msgflg));
1027
1028 if ((ssize_t)msgsz < 0)
1029 return EINVAL;
1030
1031 restart:
1032 msqid = IPCID_TO_IX(msqidr);
1033
1034 mutex_enter(&msgmutex);
1035 /* In case of reallocation, we will wait for completion */
1036 while (__predict_false(msg_realloc_state))
1037 cv_wait(&msg_realloc_cv, &msgmutex);
1038
1039 if (msqid < 0 || msqid >= msginfo.msgmni) {
1040 MSG_PRINTF(("msqid (%d) out of range (0<=msqid<%d)\n", msqid,
1041 msginfo.msgmni));
1042 error = EINVAL;
1043 goto unlock;
1044 }
1045
1046 msq = &msqs[msqid];
1047 msqptr = &msq->msq_u;
1048
1049 if (msqptr->msg_qbytes == 0) {
1050 MSG_PRINTF(("no such message queue id\n"));
1051 error = EINVAL;
1052 goto unlock;
1053 }
1054 if (msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
1055 MSG_PRINTF(("wrong sequence number\n"));
1056 error = EINVAL;
1057 goto unlock;
1058 }
1059
1060 if ((error = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
1061 MSG_PRINTF(("requester doesn't have read access\n"));
1062 goto unlock;
1063 }
1064
1065 msghdr = NULL;
1066 while (msghdr == NULL) {
1067 if (msgtyp == 0) {
1068 msghdr = msqptr->_msg_first;
1069 if (msghdr != NULL) {
1070 if (msgsz < msghdr->msg_ts &&
1071 (msgflg & MSG_NOERROR) == 0) {
1072 MSG_PRINTF(("first msg on the queue "
1073 "is too big (want %lld, got %d)\n",
1074 (long long)msgsz, msghdr->msg_ts));
1075 error = E2BIG;
1076 goto unlock;
1077 }
1078 if (msqptr->_msg_first == msqptr->_msg_last) {
1079 msqptr->_msg_first = NULL;
1080 msqptr->_msg_last = NULL;
1081 } else {
1082 msqptr->_msg_first = msghdr->msg_next;
1083 KASSERT(msqptr->_msg_first != NULL);
1084 }
1085 }
1086 } else {
1087 struct __msg *previous;
1088 struct __msg **prev;
1089
1090 for (previous = NULL, prev = &msqptr->_msg_first;
1091 (msghdr = *prev) != NULL;
1092 previous = msghdr, prev = &msghdr->msg_next) {
1093 /*
1094 * Is this message's type an exact match or is
1095 * this message's type less than or equal to
1096 * the absolute value of a negative msgtyp?
1097 * Note that the second half of this test can
1098 * NEVER be true if msgtyp is positive since
1099 * msg_type is always positive!
1100 */
1101
1102 if (msgtyp != msghdr->msg_type &&
1103 msgtyp != LONG_MIN &&
1104 msghdr->msg_type > -msgtyp)
1105 continue;
1106
1107 MSG_PRINTF(("found message type %ld, requested %ld\n",
1108 msghdr->msg_type, msgtyp));
1109 if (msgsz < msghdr->msg_ts &&
1110 (msgflg & MSG_NOERROR) == 0) {
1111 MSG_PRINTF(("requested message on the queue "
1112 "is too big (want %lld, got %d)\n",
1113 (long long)msgsz, msghdr->msg_ts));
1114 error = E2BIG;
1115 goto unlock;
1116 }
1117 *prev = msghdr->msg_next;
1118 if (msghdr != msqptr->_msg_last)
1119 break;
1120 if (previous == NULL) {
1121 KASSERT(prev == &msqptr->_msg_first);
1122 msqptr->_msg_first = NULL;
1123 msqptr->_msg_last = NULL;
1124 } else {
1125 KASSERT(prev != &msqptr->_msg_first);
1126 msqptr->_msg_last = previous;
1127 }
1128 break;
1129 }
1130 }
1131
1132 /*
1133 * We've either extracted the msghdr for the appropriate
1134 * message or there isn't one.
1135 * If there is one then bail out of this loop.
1136 */
1137 if (msghdr != NULL)
1138 break;
1139
1140 /*
1141 * Hmph! No message found. Does the user want to wait?
1142 */
1143
1144 if ((msgflg & IPC_NOWAIT) != 0) {
1145 MSG_PRINTF(("no appropriate message found (msgtyp=%ld)\n",
1146 msgtyp));
1147 error = ENOMSG;
1148 goto unlock;
1149 }
1150
1151 /*
1152 * Wait for something to happen
1153 */
1154
1155 msg_waiters++;
1156 MSG_PRINTF(("msgrcv: goodnight\n"));
1157 error = cv_wait_sig(&msq->msq_cv, &msgmutex);
1158 MSG_PRINTF(("msgrcv: good morning (error=%d)\n", error));
1159 msg_waiters--;
1160
1161 /*
1162 * In case of such state, notify reallocator and
1163 * restart the call.
1164 */
1165 if (msg_realloc_state) {
1166 cv_broadcast(&msg_realloc_cv);
1167 mutex_exit(&msgmutex);
1168 goto restart;
1169 }
1170
1171 if (error != 0) {
1172 MSG_PRINTF(("msgsnd: interrupted system call\n"));
1173 error = EINTR;
1174 goto unlock;
1175 }
1176
1177 /*
1178 * Make sure that the msq queue still exists
1179 */
1180
1181 if (msqptr->msg_qbytes == 0 ||
1182 msqptr->msg_perm._seq != IPCID_TO_SEQ(msqidr)) {
1183 MSG_PRINTF(("msqid deleted\n"));
1184 error = EIDRM;
1185 goto unlock;
1186 }
1187 }
1188
1189 /*
1190 * Return the message to the user.
1191 *
1192 * First, do the bookkeeping (before we risk being interrupted).
1193 */
1194
1195 msqptr->_msg_cbytes -= msghdr->msg_ts;
1196 msqptr->msg_qnum--;
1197 msqptr->msg_lrpid = l->l_proc->p_pid;
1198 msqptr->msg_rtime = time_second;
1199
1200 /*
1201 * Make msgsz the actual amount that we'll be returning.
1202 * Note that this effectively truncates the message if it is too long
1203 * (since msgsz is never increased).
1204 */
1205
1206 MSG_PRINTF(("found a message, msgsz=%lld, msg_ts=%d\n",
1207 (long long)msgsz, msghdr->msg_ts));
1208 if (msgsz > msghdr->msg_ts)
1209 msgsz = msghdr->msg_ts;
1210
1211 /*
1212 * Return the type to the user.
1213 */
1214 mutex_exit(&msgmutex);
1215 error = (*put_type)(&msghdr->msg_type, user_msgp, typesz);
1216 mutex_enter(&msgmutex);
1217 if (error != 0) {
1218 MSG_PRINTF(("error (%d) copying out message type\n", error));
1219 msg_freehdr(msghdr);
1220 cv_broadcast(&msq->msq_cv);
1221 goto unlock;
1222 }
1223 user_msgp += typesz;
1224
1225 /*
1226 * Return the segments to the user
1227 */
1228
1229 next = msghdr->msg_spot;
1230 for (len = 0; len < msgsz; len += msginfo.msgssz) {
1231 size_t tlen;
1232 KASSERT(next > -1);
1233 KASSERT(next < msginfo.msgseg);
1234
1235 if (msgsz - len > msginfo.msgssz)
1236 tlen = msginfo.msgssz;
1237 else
1238 tlen = msgsz - len;
1239 mutex_exit(&msgmutex);
1240 error = copyout(&msgpool[next * msginfo.msgssz],
1241 user_msgp, tlen);
1242 mutex_enter(&msgmutex);
1243 if (error != 0) {
1244 MSG_PRINTF(("error (%d) copying out message segment\n",
1245 error));
1246 msg_freehdr(msghdr);
1247 cv_broadcast(&msq->msq_cv);
1248 goto unlock;
1249 }
1250 user_msgp += tlen;
1251 next = msgmaps[next].next;
1252 }
1253
1254 /*
1255 * Done, return the actual number of bytes copied out.
1256 */
1257
1258 msg_freehdr(msghdr);
1259 cv_broadcast(&msq->msq_cv);
1260 *retval = msgsz;
1261
1262 unlock:
1263 mutex_exit(&msgmutex);
1264 return error;
1265 }
1266
1267 /*
1268 * Sysctl initialization and nodes.
1269 */
1270
1271 static int
sysctl_ipc_msgmni(SYSCTLFN_ARGS)1272 sysctl_ipc_msgmni(SYSCTLFN_ARGS)
1273 {
1274 int newsize, error;
1275 struct sysctlnode node;
1276 node = *rnode;
1277 node.sysctl_data = &newsize;
1278
1279 newsize = msginfo.msgmni;
1280 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1281 if (error || newp == NULL)
1282 return error;
1283
1284 sysctl_unlock();
1285 error = msgrealloc(newsize, msginfo.msgseg);
1286 sysctl_relock();
1287 return error;
1288 }
1289
1290 static int
sysctl_ipc_msgseg(SYSCTLFN_ARGS)1291 sysctl_ipc_msgseg(SYSCTLFN_ARGS)
1292 {
1293 int newsize, error;
1294 struct sysctlnode node;
1295 node = *rnode;
1296 node.sysctl_data = &newsize;
1297
1298 newsize = msginfo.msgseg;
1299 error = sysctl_lookup(SYSCTLFN_CALL(&node));
1300 if (error || newp == NULL)
1301 return error;
1302
1303 sysctl_unlock();
1304 error = msgrealloc(msginfo.msgmni, newsize);
1305 sysctl_relock();
1306 return error;
1307 }
1308
1309 SYSCTL_SETUP(sysctl_ipc_msg_setup, "sysctl kern.ipc subtree setup")
1310 {
1311 const struct sysctlnode *node = NULL;
1312
1313 sysctl_createv(clog, 0, NULL, &node,
1314 CTLFLAG_PERMANENT,
1315 CTLTYPE_NODE, "ipc",
1316 SYSCTL_DESCR("SysV IPC options"),
1317 NULL, 0, NULL, 0,
1318 CTL_KERN, KERN_SYSVIPC, CTL_EOL);
1319
1320 if (node == NULL)
1321 return;
1322
1323 sysctl_createv(clog, 0, &node, NULL,
1324 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1325 CTLTYPE_INT, "msgmni",
1326 SYSCTL_DESCR("Max number of message queue identifiers"),
1327 sysctl_ipc_msgmni, 0, &msginfo.msgmni, 0,
1328 CTL_CREATE, CTL_EOL);
1329 sysctl_createv(clog, 0, &node, NULL,
1330 CTLFLAG_PERMANENT | CTLFLAG_READWRITE,
1331 CTLTYPE_INT, "msgseg",
1332 SYSCTL_DESCR("Max number of number of message segments"),
1333 sysctl_ipc_msgseg, 0, &msginfo.msgseg, 0,
1334 CTL_CREATE, CTL_EOL);
1335 }
1336