1 /* $NetBSD: linux_ipc.c,v 1.57 2019/08/23 10:22:15 maxv Exp $ */ 2 3 /*- 4 * Copyright (c) 1995, 1998 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank van der Linden and Eric Haszlakiewicz. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: linux_ipc.c,v 1.57 2019/08/23 10:22:15 maxv Exp $"); 34 35 #if defined(_KERNEL_OPT) 36 #include "opt_sysv.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/shm.h> 41 #include <sys/sem.h> 42 #include <sys/msg.h> 43 #include <sys/proc.h> 44 #include <sys/systm.h> 45 #include <sys/vnode.h> 46 47 #include <sys/mount.h> 48 #include <sys/syscallargs.h> 49 50 #include <compat/linux/common/linux_types.h> 51 #include <compat/linux/common/linux_signal.h> 52 #include <compat/linux/common/linux_util.h> 53 #include <compat/linux/common/linux_ipc.h> 54 #include <compat/linux/common/linux_msg.h> 55 #include <compat/linux/common/linux_shm.h> 56 #include <compat/linux/common/linux_sem.h> 57 58 #include <compat/linux/linux_syscallargs.h> 59 #include <compat/linux/linux_syscall.h> 60 61 #include <compat/linux/common/linux_ipccall.h> 62 #include <compat/linux/common/linux_machdep.h> 63 64 /* 65 * Note: Not all linux architechtures have explicit versions 66 * of the SYSV* syscalls. On the ones that don't 67 * we pretend that they are defined anyway. *_args and 68 * prototypes are defined in individual headers; 69 * syscalls.master lists those syscalls as NOARGS. 70 * 71 * The functions in multiarch are the ones that just need 72 * the arguments shuffled around and then use the 73 * normal NetBSD syscall. 74 * 75 * Function in multiarch: 76 * linux_sys_ipc : linux_ipccall.c 77 * linux_semop : linux_ipccall.c 78 * linux_semget : linux_ipccall.c 79 * linux_msgsnd : linux_ipccall.c 80 * linux_msgrcv : linux_ipccall.c 81 * linux_msgget : linux_ipccall.c 82 * linux_shmdt : linux_ipccall.c 83 * linux_shmget : linux_ipccall.c 84 */ 85 86 #if defined (SYSVSEM) || defined(SYSVSHM) || defined(SYSVMSG) 87 /* 88 * Convert between Linux and NetBSD ipc_perm structures. Only the 89 * order of the fields is different. 90 */ 91 void 92 linux_to_bsd_ipc_perm(struct linux_ipc_perm *lpp, struct ipc_perm *bpp) 93 { 94 95 bpp->_key = lpp->l_key; 96 bpp->uid = lpp->l_uid; 97 bpp->gid = lpp->l_gid; 98 bpp->cuid = lpp->l_cuid; 99 bpp->cgid = lpp->l_cgid; 100 bpp->mode = lpp->l_mode; 101 bpp->_seq = lpp->l_seq; 102 } 103 104 void 105 linux_to_bsd_ipc64_perm(struct linux_ipc64_perm *lpp, struct ipc_perm *bpp) 106 { 107 bpp->_key = lpp->l_key; 108 bpp->uid = lpp->l_uid; 109 bpp->gid = lpp->l_gid; 110 bpp->cuid = lpp->l_cuid; 111 bpp->cgid = lpp->l_cgid; 112 bpp->mode = lpp->l_mode; 113 bpp->_seq = lpp->l_seq; 114 } 115 116 void 117 bsd_to_linux_ipc_perm(struct ipc_perm *bpp, struct linux_ipc_perm *lpp) 118 { 119 120 memset(lpp, 0, sizeof *lpp); 121 lpp->l_key = bpp->_key; 122 lpp->l_uid = bpp->uid; 123 lpp->l_gid = bpp->gid; 124 lpp->l_cuid = bpp->cuid; 125 lpp->l_cgid = bpp->cgid; 126 lpp->l_mode = bpp->mode; 127 lpp->l_seq = bpp->_seq; 128 } 129 130 void 131 bsd_to_linux_ipc64_perm(struct ipc_perm *bpp, struct linux_ipc64_perm *lpp) 132 { 133 134 memset(lpp, 0, sizeof *lpp); 135 lpp->l_key = bpp->_key; 136 lpp->l_uid = bpp->uid; 137 lpp->l_gid = bpp->gid; 138 lpp->l_cuid = bpp->cuid; 139 lpp->l_cgid = bpp->cgid; 140 lpp->l_mode = bpp->mode; 141 lpp->l_seq = bpp->_seq; 142 } 143 144 #endif 145 146 #ifdef SYSVSEM 147 /* 148 * Semaphore operations. Most constants and structures are the same on 149 * both systems. Only semctl() needs some extra work. 150 */ 151 152 /* 153 * Convert between Linux and NetBSD semid_ds structures. 154 */ 155 void 156 bsd_to_linux_semid_ds(struct semid_ds *bs, struct linux_semid_ds *ls) 157 { 158 159 memset(ls, 0, sizeof *ls); 160 bsd_to_linux_ipc_perm(&bs->sem_perm, &ls->l_sem_perm); 161 ls->l_sem_otime = bs->sem_otime; 162 ls->l_sem_ctime = bs->sem_ctime; 163 ls->l_sem_nsems = bs->sem_nsems; 164 } 165 166 void 167 bsd_to_linux_semid64_ds(struct semid_ds *bs, struct linux_semid64_ds *ls) 168 { 169 170 memset(ls, 0, sizeof *ls); 171 bsd_to_linux_ipc64_perm(&bs->sem_perm, &ls->l_sem_perm); 172 ls->l_sem_otime = bs->sem_otime; 173 ls->l_sem_ctime = bs->sem_ctime; 174 ls->l_sem_nsems = bs->sem_nsems; 175 } 176 177 void 178 linux_to_bsd_semid_ds(struct linux_semid_ds *ls, struct semid_ds *bs) 179 { 180 181 linux_to_bsd_ipc_perm(&ls->l_sem_perm, &bs->sem_perm); 182 bs->sem_otime = ls->l_sem_otime; 183 bs->sem_ctime = ls->l_sem_ctime; 184 bs->sem_nsems = ls->l_sem_nsems; 185 } 186 187 void 188 linux_to_bsd_semid64_ds(struct linux_semid64_ds *ls, struct semid_ds *bs) 189 { 190 191 linux_to_bsd_ipc64_perm(&ls->l_sem_perm, &bs->sem_perm); 192 bs->sem_otime = ls->l_sem_otime; 193 bs->sem_ctime = ls->l_sem_ctime; 194 bs->sem_nsems = ls->l_sem_nsems; 195 } 196 197 /* 198 * Most of this can be handled by directly passing the arguments on; we 199 * just need to frob the `cmd' and convert the semid_ds and semun. 200 */ 201 int 202 linux_sys_semctl(struct lwp *l, const struct linux_sys_semctl_args *uap, register_t *retval) 203 { 204 /* { 205 syscallarg(int) semid; 206 syscallarg(int) semnum; 207 syscallarg(int) cmd; 208 syscallarg(union linux_semun) arg; 209 } */ 210 struct semid_ds sembuf; 211 struct linux_semid_ds lsembuf; 212 struct linux_semid64_ds lsembuf64; 213 union __semun semun; 214 int cmd, lcmd, error; 215 void *pass_arg = NULL; 216 217 lcmd = SCARG(uap, cmd); 218 #ifdef LINUX_IPC_FORCE64 219 lcmd |= LINUX_IPC_64; 220 #endif 221 222 switch (lcmd & ~LINUX_IPC_64) { 223 case LINUX_IPC_SET: 224 if (lcmd & LINUX_IPC_64) { 225 error = copyin(SCARG(uap, arg).l_buf, &lsembuf64, 226 sizeof(lsembuf64)); 227 linux_to_bsd_semid64_ds(&lsembuf64, &sembuf); 228 } else { 229 error = copyin(SCARG(uap, arg).l_buf, &lsembuf, 230 sizeof(lsembuf)); 231 linux_to_bsd_semid_ds(&lsembuf, &sembuf); 232 } 233 if (error) 234 return (error); 235 pass_arg = &sembuf; 236 cmd = IPC_SET; 237 break; 238 239 case LINUX_IPC_STAT: 240 pass_arg = &sembuf; 241 cmd = IPC_STAT; 242 break; 243 244 case LINUX_IPC_RMID: 245 cmd = IPC_RMID; 246 break; 247 248 case LINUX_GETVAL: 249 cmd = GETVAL; 250 break; 251 252 case LINUX_GETPID: 253 cmd = GETPID; 254 break; 255 256 case LINUX_GETNCNT: 257 cmd = GETNCNT; 258 break; 259 260 case LINUX_GETZCNT: 261 cmd = GETZCNT; 262 break; 263 264 case LINUX_GETALL: 265 pass_arg = &semun; 266 semun.array = SCARG(uap, arg).l_array; 267 cmd = GETALL; 268 break; 269 270 case LINUX_SETVAL: 271 pass_arg = &semun; 272 semun.val = SCARG(uap, arg).l_val; 273 cmd = SETVAL; 274 break; 275 276 case LINUX_SETALL: 277 pass_arg = &semun; 278 semun.array = SCARG(uap, arg).l_array; 279 cmd = SETALL; 280 break; 281 282 default: 283 return (EINVAL); 284 } 285 286 error = semctl1(l, SCARG(uap, semid), SCARG(uap, semnum), cmd, 287 pass_arg, retval); 288 if (error) 289 return error; 290 291 switch (lcmd) { 292 case LINUX_IPC_STAT: 293 bsd_to_linux_semid_ds(&sembuf, &lsembuf); 294 error = copyout(&lsembuf, SCARG(uap, arg).l_buf, 295 sizeof(lsembuf)); 296 break; 297 case LINUX_IPC_STAT | LINUX_IPC_64: 298 bsd_to_linux_semid64_ds(&sembuf, &lsembuf64); 299 error = copyout(&lsembuf64, SCARG(uap, arg).l_buf, 300 sizeof(lsembuf64)); 301 break; 302 default: 303 break; 304 } 305 306 return (error); 307 } 308 #endif /* SYSVSEM */ 309 310 #ifdef SYSVMSG 311 312 void 313 linux_to_bsd_msqid_ds(struct linux_msqid_ds *lmp, struct msqid_ds *bmp) 314 { 315 316 memset(bmp, 0, sizeof(*bmp)); 317 linux_to_bsd_ipc_perm(&lmp->l_msg_perm, &bmp->msg_perm); 318 bmp->_msg_cbytes = lmp->l_msg_cbytes; 319 bmp->msg_qnum = lmp->l_msg_qnum; 320 bmp->msg_qbytes = lmp->l_msg_qbytes; 321 bmp->msg_lspid = lmp->l_msg_lspid; 322 bmp->msg_lrpid = lmp->l_msg_lrpid; 323 bmp->msg_stime = lmp->l_msg_stime; 324 bmp->msg_rtime = lmp->l_msg_rtime; 325 bmp->msg_ctime = lmp->l_msg_ctime; 326 } 327 328 void 329 linux_to_bsd_msqid64_ds(struct linux_msqid64_ds *lmp, struct msqid_ds *bmp) 330 { 331 332 memset(bmp, 0, sizeof(*bmp)); 333 linux_to_bsd_ipc64_perm(&lmp->l_msg_perm, &bmp->msg_perm); 334 bmp->_msg_cbytes = lmp->l_msg_cbytes; 335 bmp->msg_stime = lmp->l_msg_stime; 336 bmp->msg_rtime = lmp->l_msg_rtime; 337 bmp->msg_ctime = lmp->l_msg_ctime; 338 bmp->msg_qnum = lmp->l_msg_qnum; 339 bmp->msg_qbytes = lmp->l_msg_qbytes; 340 bmp->msg_lspid = lmp->l_msg_lspid; 341 bmp->msg_lrpid = lmp->l_msg_lrpid; 342 } 343 344 void 345 bsd_to_linux_msqid_ds(struct msqid_ds *bmp, struct linux_msqid_ds *lmp) 346 { 347 348 memset(lmp, 0, sizeof(*lmp)); 349 bsd_to_linux_ipc_perm(&bmp->msg_perm, &lmp->l_msg_perm); 350 lmp->l_msg_cbytes = bmp->_msg_cbytes; 351 lmp->l_msg_qnum = bmp->msg_qnum; 352 lmp->l_msg_qbytes = bmp->msg_qbytes; 353 lmp->l_msg_lspid = bmp->msg_lspid; 354 lmp->l_msg_lrpid = bmp->msg_lrpid; 355 lmp->l_msg_stime = bmp->msg_stime; 356 lmp->l_msg_rtime = bmp->msg_rtime; 357 lmp->l_msg_ctime = bmp->msg_ctime; 358 } 359 360 void 361 bsd_to_linux_msqid64_ds(struct msqid_ds *bmp, struct linux_msqid64_ds *lmp) 362 { 363 364 memset(lmp, 0, sizeof(*lmp)); 365 bsd_to_linux_ipc64_perm(&bmp->msg_perm, &lmp->l_msg_perm); 366 lmp->l_msg_cbytes = bmp->_msg_cbytes; 367 lmp->l_msg_stime = bmp->msg_stime; 368 lmp->l_msg_rtime = bmp->msg_rtime; 369 lmp->l_msg_ctime = bmp->msg_ctime; 370 lmp->l_msg_cbytes = bmp->_msg_cbytes; 371 lmp->l_msg_qnum = bmp->msg_qnum; 372 lmp->l_msg_qbytes = bmp->msg_qbytes; 373 lmp->l_msg_lspid = bmp->msg_lspid; 374 lmp->l_msg_lrpid = bmp->msg_lrpid; 375 } 376 377 int 378 linux_sys_msgctl(struct lwp *l, const struct linux_sys_msgctl_args *uap, register_t *retval) 379 { 380 /* { 381 syscallarg(int) msqid; 382 syscallarg(int) cmd; 383 syscallarg(struct linux_msqid_ds *) buf; 384 } */ 385 struct msqid_ds bm, *bmp = NULL; 386 struct linux_msqid_ds lm; 387 struct linux_msqid64_ds lm64; 388 int cmd, lcmd, error; 389 390 lcmd = SCARG(uap, cmd); 391 #ifdef LINUX_IPC_FORCE64 392 lcmd |= LINUX_IPC_64; 393 #endif 394 395 switch (lcmd & ~LINUX_IPC_64) { 396 case LINUX_IPC_STAT: 397 cmd = IPC_STAT; 398 bmp = &bm; 399 break; 400 case LINUX_IPC_SET: 401 if (lcmd & LINUX_IPC_64) { 402 error = copyin(SCARG(uap, buf), &lm64, sizeof lm64); 403 linux_to_bsd_msqid64_ds(&lm64, &bm); 404 } else { 405 error = copyin(SCARG(uap, buf), &lm, sizeof lm); 406 linux_to_bsd_msqid_ds(&lm, &bm); 407 } 408 if (error) 409 return error; 410 cmd = IPC_SET; 411 bmp = &bm; 412 break; 413 case LINUX_IPC_RMID: 414 cmd = IPC_RMID; 415 break; 416 default: 417 return EINVAL; 418 } 419 420 if ((error = msgctl1(l, SCARG(uap, msqid), cmd, bmp))) 421 return error; 422 423 switch (lcmd) { 424 case LINUX_IPC_STAT: 425 bsd_to_linux_msqid_ds(&bm, &lm); 426 error = copyout(&lm, SCARG(uap, buf), sizeof lm); 427 break; 428 case LINUX_IPC_STAT|LINUX_IPC_64: 429 bsd_to_linux_msqid64_ds(&bm, &lm64); 430 error = copyout(&lm64, SCARG(uap, buf), sizeof lm64); 431 break; 432 default: 433 break; 434 } 435 436 return error; 437 } 438 #endif /* SYSVMSG */ 439 440 #ifdef SYSVSHM 441 /* 442 * shmget(2). Just make sure the Linux-compatible shmat() semantics 443 * is enabled for the segment, so that shmat() succeeds even when 444 * the segment would be removed. 445 */ 446 int 447 linux_sys_shmget(struct lwp *l, const struct linux_sys_shmget_args *uap, register_t *retval) 448 { 449 /* { 450 syscallarg(key_t) key; 451 syscallarg(size_t) size; 452 syscallarg(int) shmflg; 453 } */ 454 struct sys_shmget_args bsd_ua; 455 456 SCARG(&bsd_ua, key) = SCARG(uap, key); 457 SCARG(&bsd_ua, size) = SCARG(uap, size); 458 SCARG(&bsd_ua, shmflg) = SCARG(uap, shmflg) | _SHM_RMLINGER; 459 460 return sys_shmget(l, &bsd_ua, retval); 461 } 462 463 /* 464 * shmat(2). Very straightforward, except that Linux passes a pointer 465 * in which the return value is to be passed. This is subsequently 466 * handled by libc, apparently. 467 */ 468 #ifndef __amd64__ 469 int 470 linux_sys_shmat(struct lwp *l, const struct linux_sys_shmat_args *uap, register_t *retval) 471 { 472 /* { 473 syscallarg(int) shmid; 474 syscallarg(void *) shmaddr; 475 syscallarg(int) shmflg; 476 syscallarg(u_long *) raddr; 477 } */ 478 int error; 479 480 if ((error = sys_shmat(l, (const void *)uap, retval))) 481 return error; 482 483 if ((error = copyout(&retval[0], SCARG(uap, raddr), sizeof retval[0]))) 484 return error; 485 486 retval[0] = 0; 487 return 0; 488 } 489 #endif /* __amd64__ */ 490 491 /* 492 * Convert between Linux and NetBSD shmid_ds structures. 493 * The order of the fields is once again the difference, and 494 * we also need a place to store the internal data pointer 495 * in, which is unfortunately stored in this structure. 496 * 497 * We abuse a Linux internal field for that. 498 */ 499 void 500 linux_to_bsd_shmid_ds(struct linux_shmid_ds *lsp, struct shmid_ds *bsp) 501 { 502 503 linux_to_bsd_ipc_perm(&lsp->l_shm_perm, &bsp->shm_perm); 504 bsp->shm_segsz = lsp->l_shm_segsz; 505 bsp->shm_lpid = lsp->l_shm_lpid; 506 bsp->shm_cpid = lsp->l_shm_cpid; 507 bsp->shm_nattch = lsp->l_shm_nattch; 508 bsp->shm_atime = lsp->l_shm_atime; 509 bsp->shm_dtime = lsp->l_shm_dtime; 510 bsp->shm_ctime = lsp->l_shm_ctime; 511 } 512 513 void 514 linux_to_bsd_shmid64_ds(struct linux_shmid64_ds *lsp, struct shmid_ds *bsp) 515 { 516 517 linux_to_bsd_ipc64_perm(&lsp->l_shm_perm, &bsp->shm_perm); 518 bsp->shm_segsz = lsp->l_shm_segsz; 519 bsp->shm_lpid = lsp->l_shm_lpid; 520 bsp->shm_cpid = lsp->l_shm_cpid; 521 bsp->shm_nattch = lsp->l_shm_nattch; 522 bsp->shm_atime = lsp->l_shm_atime; 523 bsp->shm_dtime = lsp->l_shm_dtime; 524 bsp->shm_ctime = lsp->l_shm_ctime; 525 } 526 527 void 528 bsd_to_linux_shmid_ds(struct shmid_ds *bsp, struct linux_shmid_ds *lsp) 529 { 530 531 memset(lsp, 0, sizeof *lsp); 532 bsd_to_linux_ipc_perm(&bsp->shm_perm, &lsp->l_shm_perm); 533 lsp->l_shm_segsz = bsp->shm_segsz; 534 lsp->l_shm_lpid = bsp->shm_lpid; 535 lsp->l_shm_cpid = bsp->shm_cpid; 536 lsp->l_shm_nattch = bsp->shm_nattch; 537 lsp->l_shm_atime = bsp->shm_atime; 538 lsp->l_shm_dtime = bsp->shm_dtime; 539 lsp->l_shm_ctime = bsp->shm_ctime; 540 } 541 542 void 543 bsd_to_linux_shmid64_ds(struct shmid_ds *bsp, struct linux_shmid64_ds *lsp) 544 { 545 546 memset(lsp, 0, sizeof *lsp); 547 bsd_to_linux_ipc64_perm(&bsp->shm_perm, &lsp->l_shm_perm); 548 lsp->l_shm_segsz = bsp->shm_segsz; 549 lsp->l_shm_lpid = bsp->shm_lpid; 550 lsp->l_shm_cpid = bsp->shm_cpid; 551 lsp->l_shm_nattch = bsp->shm_nattch; 552 lsp->l_shm_atime = bsp->shm_atime; 553 lsp->l_shm_dtime = bsp->shm_dtime; 554 lsp->l_shm_ctime = bsp->shm_ctime; 555 } 556 557 /* 558 * shmctl. 559 * 560 * The usual structure conversion and massaging is done. 561 */ 562 int 563 linux_sys_shmctl(struct lwp *l, const struct linux_sys_shmctl_args *uap, register_t *retval) 564 { 565 /* { 566 syscallarg(int) shmid; 567 syscallarg(int) cmd; 568 syscallarg(struct linux_shmid_ds *) buf; 569 } */ 570 struct shmid_ds bs; 571 struct ipc_perm perm; 572 struct linux_shmid_ds ls; 573 struct linux_shmid64_ds ls64; 574 struct linux_shminfo64 lsi64; 575 struct linux_shm_info lsi; 576 int error, i, cmd, shmid; 577 578 shmid = SCARG(uap, shmid); 579 cmd = SCARG(uap, cmd); 580 #ifdef LINUX_IPC_FORCE64 581 cmd |= LINUX_IPC_64; 582 #endif 583 584 switch (cmd & ~LINUX_IPC_64) { 585 case LINUX_SHM_STAT: 586 error = shm_find_segment_perm_by_index(shmid, &perm); 587 if (error) 588 return error; 589 shmid = IXSEQ_TO_IPCID(shmid, perm); 590 retval[0] = shmid; 591 /*FALLTHROUGH*/ 592 593 case LINUX_IPC_STAT: 594 error = shmctl1(l, shmid, IPC_STAT, &bs); 595 if (error != 0) 596 return error; 597 if (cmd & LINUX_IPC_64) { 598 bsd_to_linux_shmid64_ds(&bs, &ls64); 599 error = copyout(&ls64, SCARG(uap, buf), sizeof ls64); 600 } else { 601 bsd_to_linux_shmid_ds(&bs, &ls); 602 error = copyout(&ls, SCARG(uap, buf), sizeof ls); 603 } 604 return error; 605 606 case LINUX_IPC_SET: 607 if (cmd & LINUX_IPC_64) { 608 error = copyin(SCARG(uap, buf), &ls64, sizeof ls64); 609 linux_to_bsd_shmid64_ds(&ls64, &bs); 610 } else { 611 error = copyin(SCARG(uap, buf), &ls, sizeof ls); 612 linux_to_bsd_shmid_ds(&ls, &bs); 613 } 614 if (error != 0) 615 return error; 616 return shmctl1(l, shmid, IPC_SET, &bs); 617 618 case LINUX_IPC_RMID: 619 return shmctl1(l, shmid, IPC_RMID, NULL); 620 621 case LINUX_SHM_LOCK: 622 return shmctl1(l, shmid, SHM_LOCK, NULL); 623 624 case LINUX_SHM_UNLOCK: 625 return shmctl1(l, shmid, SHM_UNLOCK, NULL); 626 627 case LINUX_IPC_INFO: 628 memset(&lsi64, 0, sizeof lsi64); 629 lsi64.l_shmmax = shminfo.shmmax; 630 lsi64.l_shmmin = shminfo.shmmin; 631 lsi64.l_shmmni = shminfo.shmmni; 632 lsi64.l_shmseg = shminfo.shmseg; 633 lsi64.l_shmall = shminfo.shmall; 634 for (i = shminfo.shmmni - 1; i > 0; i--) 635 if (shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) 636 break; 637 retval[0] = i; 638 return copyout(&lsi64, SCARG(uap, buf), sizeof lsi64); 639 640 case LINUX_SHM_INFO: 641 (void)memset(&lsi, 0, sizeof lsi); 642 lsi.l_used_ids = shm_nused; 643 for (i = 0; i < shminfo.shmmni; i++) 644 if (shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) 645 lsi.l_shm_tot += 646 round_page(shmsegs[i].shm_segsz) / 647 uvmexp.pagesize; 648 lsi.l_shm_rss = 0; 649 lsi.l_shm_swp = 0; 650 lsi.l_swap_attempts = 0; 651 lsi.l_swap_successes = 0; 652 for (i = shminfo.shmmni - 1; i > 0; i--) 653 if (shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) 654 break; 655 retval[0] = i; 656 return copyout(&lsi, SCARG(uap, buf), sizeof lsi); 657 658 default: 659 #ifdef DEBUG 660 printf("linux_sys_shmctl cmd %d\n", SCARG(uap, cmd)); 661 #endif 662 return EINVAL; 663 } 664 } 665 #endif /* SYSVSHM */ 666