1 /* 2 * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. All advertising materials mentioning features or use of this software 13 * must display the following acknowledgement: 14 * This product includes software developed by Adam Glass and Charles 15 * Hannum. 16 * 4. The names of the authors may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "opt_compat.h" 32 #include "opt_sysvipc.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/sysproto.h> 37 #include <sys/kernel.h> 38 #include <sys/sysctl.h> 39 #include <sys/shm.h> 40 #include <sys/proc.h> 41 #include <sys/malloc.h> 42 #include <sys/mman.h> 43 #include <sys/stat.h> 44 #include <sys/sysent.h> 45 #include <sys/jail.h> 46 47 #include <sys/mplock2.h> 48 49 #include <vm/vm.h> 50 #include <vm/vm_param.h> 51 #include <sys/lock.h> 52 #include <vm/pmap.h> 53 #include <vm/vm_object.h> 54 #include <vm/vm_map.h> 55 #include <vm/vm_page.h> 56 #include <vm/vm_pager.h> 57 58 static MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments"); 59 60 struct oshmctl_args; 61 static int sys_oshmctl (struct proc *p, struct oshmctl_args *uap); 62 63 static int shmget_allocate_segment (struct proc *p, struct shmget_args *uap, int mode); 64 static int shmget_existing (struct proc *p, struct shmget_args *uap, int mode, int segnum); 65 66 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 67 static sy_call_t *shmcalls[] = { 68 (sy_call_t *)sys_shmat, (sy_call_t *)sys_oshmctl, 69 (sy_call_t *)sys_shmdt, (sy_call_t *)sys_shmget, 70 (sy_call_t *)sys_shmctl 71 }; 72 73 #define SHMSEG_FREE 0x0200 74 #define SHMSEG_REMOVED 0x0400 75 #define SHMSEG_ALLOCATED 0x0800 76 #define SHMSEG_WANTED 0x1000 77 78 static int shm_last_free, shm_committed, shmalloced; 79 int shm_nused; 80 static struct shmid_ds *shmsegs; 81 82 struct shm_handle { 83 /* vm_offset_t kva; */ 84 vm_object_t shm_object; 85 }; 86 87 struct shmmap_state { 88 vm_offset_t va; 89 int shmid; 90 }; 91 92 static void shm_deallocate_segment (struct shmid_ds *); 93 static int shm_find_segment_by_key (key_t); 94 static struct shmid_ds *shm_find_segment_by_shmid (int); 95 static int shm_delete_mapping (struct vmspace *vm, struct shmmap_state *); 96 static void shmrealloc (void); 97 static void shminit (void *); 98 99 /* 100 * Tuneable values 101 */ 102 #ifndef SHMMIN 103 #define SHMMIN 1 104 #endif 105 #ifndef SHMMNI 106 #define SHMMNI 512 107 #endif 108 #ifndef SHMSEG 109 #define SHMSEG 1024 110 #endif 111 112 struct shminfo shminfo = { 113 0, 114 SHMMIN, 115 SHMMNI, 116 SHMSEG, 117 0 118 }; 119 120 static int shm_use_phys; 121 122 TUNABLE_LONG("kern.ipc.shmmin", &shminfo.shmmin); 123 TUNABLE_LONG("kern.ipc.shmmni", &shminfo.shmmni); 124 TUNABLE_LONG("kern.ipc.shmseg", &shminfo.shmseg); 125 TUNABLE_LONG("kern.ipc.shmmaxpgs", &shminfo.shmall); 126 TUNABLE_INT("kern.ipc.shm_use_phys", &shm_use_phys); 127 128 SYSCTL_LONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0, 129 "Max shared memory segment size"); 130 SYSCTL_LONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0, 131 "Min shared memory segment size"); 132 SYSCTL_LONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RD, &shminfo.shmmni, 0, 133 "Max number of shared memory identifiers"); 134 SYSCTL_LONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RW, &shminfo.shmseg, 0, 135 "Max shared memory segments per process"); 136 SYSCTL_LONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0, 137 "Max pages of shared memory"); 138 SYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW, &shm_use_phys, 0, 139 "Use phys pager allocation instead of swap pager allocation"); 140 141 static int 142 shm_find_segment_by_key(key_t key) 143 { 144 int i; 145 146 for (i = 0; i < shmalloced; i++) { 147 if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) && 148 shmsegs[i].shm_perm.key == key) 149 return i; 150 } 151 return -1; 152 } 153 154 static struct shmid_ds * 155 shm_find_segment_by_shmid(int shmid) 156 { 157 int segnum; 158 struct shmid_ds *shmseg; 159 160 segnum = IPCID_TO_IX(shmid); 161 if (segnum < 0 || segnum >= shmalloced) 162 return NULL; 163 shmseg = &shmsegs[segnum]; 164 if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED)) 165 != SHMSEG_ALLOCATED || 166 shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid)) { 167 return NULL; 168 } 169 return shmseg; 170 } 171 172 static void 173 shm_deallocate_segment(struct shmid_ds *shmseg) 174 { 175 struct shm_handle *shm_handle; 176 size_t size; 177 178 shm_handle = shmseg->shm_internal; 179 vm_object_deallocate(shm_handle->shm_object); 180 kfree((caddr_t)shm_handle, M_SHM); 181 shmseg->shm_internal = NULL; 182 size = round_page(shmseg->shm_segsz); 183 shm_committed -= btoc(size); 184 shm_nused--; 185 shmseg->shm_perm.mode = SHMSEG_FREE; 186 } 187 188 static int 189 shm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) 190 { 191 struct shmid_ds *shmseg; 192 int segnum, result; 193 size_t size; 194 195 segnum = IPCID_TO_IX(shmmap_s->shmid); 196 shmseg = &shmsegs[segnum]; 197 size = round_page(shmseg->shm_segsz); 198 result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size); 199 if (result != KERN_SUCCESS) 200 return EINVAL; 201 shmmap_s->shmid = -1; 202 shmseg->shm_dtime = time_second; 203 if ((--shmseg->shm_nattch <= 0) && 204 (shmseg->shm_perm.mode & SHMSEG_REMOVED)) { 205 shm_deallocate_segment(shmseg); 206 shm_last_free = segnum; 207 } 208 return 0; 209 } 210 211 /* 212 * MPALMOSTSAFE 213 */ 214 int 215 sys_shmdt(struct shmdt_args *uap) 216 { 217 struct thread *td = curthread; 218 struct proc *p = td->td_proc; 219 struct shmmap_state *shmmap_s; 220 long i; 221 int error; 222 223 if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 224 return (ENOSYS); 225 226 get_mplock(); 227 shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; 228 if (shmmap_s == NULL) { 229 error = EINVAL; 230 goto done; 231 } 232 for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { 233 if (shmmap_s->shmid != -1 && 234 shmmap_s->va == (vm_offset_t)uap->shmaddr) 235 break; 236 } 237 if (i == shminfo.shmseg) 238 error = EINVAL; 239 else 240 error = shm_delete_mapping(p->p_vmspace, shmmap_s); 241 done: 242 rel_mplock(); 243 return (error); 244 } 245 246 /* 247 * MPALMOSTSAFE 248 */ 249 int 250 sys_shmat(struct shmat_args *uap) 251 { 252 struct thread *td = curthread; 253 struct proc *p = td->td_proc; 254 int error, flags; 255 long i; 256 struct shmid_ds *shmseg; 257 struct shmmap_state *shmmap_s = NULL; 258 struct shm_handle *shm_handle; 259 vm_offset_t attach_va; 260 vm_prot_t prot; 261 vm_size_t size; 262 int rv; 263 264 if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 265 return (ENOSYS); 266 267 get_mplock(); 268 again: 269 shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm; 270 if (shmmap_s == NULL) { 271 size = shminfo.shmseg * sizeof(struct shmmap_state); 272 shmmap_s = kmalloc(size, M_SHM, M_WAITOK); 273 for (i = 0; i < shminfo.shmseg; i++) 274 shmmap_s[i].shmid = -1; 275 if (p->p_vmspace->vm_shm != NULL) { 276 kfree(shmmap_s, M_SHM); 277 goto again; 278 } 279 p->p_vmspace->vm_shm = (caddr_t)shmmap_s; 280 } 281 shmseg = shm_find_segment_by_shmid(uap->shmid); 282 if (shmseg == NULL) { 283 error = EINVAL; 284 goto done; 285 } 286 error = ipcperm(p, &shmseg->shm_perm, 287 (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); 288 if (error) 289 goto done; 290 for (i = 0; i < shminfo.shmseg; i++) { 291 if (shmmap_s->shmid == -1) 292 break; 293 shmmap_s++; 294 } 295 if (i >= shminfo.shmseg) { 296 error = EMFILE; 297 goto done; 298 } 299 size = round_page(shmseg->shm_segsz); 300 #ifdef VM_PROT_READ_IS_EXEC 301 prot = VM_PROT_READ | VM_PROT_EXECUTE; 302 #else 303 prot = VM_PROT_READ; 304 #endif 305 if ((uap->shmflg & SHM_RDONLY) == 0) 306 prot |= VM_PROT_WRITE; 307 flags = MAP_ANON | MAP_SHARED; 308 if (uap->shmaddr) { 309 flags |= MAP_FIXED; 310 if (uap->shmflg & SHM_RND) { 311 attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1); 312 } else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0) { 313 attach_va = (vm_offset_t)uap->shmaddr; 314 } else { 315 error = EINVAL; 316 goto done; 317 } 318 } else { 319 /* 320 * This is just a hint to vm_map_find() about where to put it. 321 */ 322 attach_va = round_page((vm_offset_t)p->p_vmspace->vm_taddr + maxtsiz + maxdsiz); 323 } 324 325 shm_handle = shmseg->shm_internal; 326 vm_object_hold(shm_handle->shm_object); 327 vm_object_reference_locked(shm_handle->shm_object); 328 rv = vm_map_find(&p->p_vmspace->vm_map, 329 shm_handle->shm_object, 0, 330 &attach_va, 331 size, PAGE_SIZE, 332 ((flags & MAP_FIXED) ? 0 : 1), 333 VM_MAPTYPE_NORMAL, 334 prot, prot, 335 0); 336 vm_object_drop(shm_handle->shm_object); 337 if (rv != KERN_SUCCESS) { 338 vm_object_deallocate(shm_handle->shm_object); 339 error = ENOMEM; 340 goto done; 341 } 342 vm_map_inherit(&p->p_vmspace->vm_map, 343 attach_va, attach_va + size, VM_INHERIT_SHARE); 344 345 KKASSERT(shmmap_s->shmid == -1); 346 shmmap_s->va = attach_va; 347 shmmap_s->shmid = uap->shmid; 348 shmseg->shm_lpid = p->p_pid; 349 shmseg->shm_atime = time_second; 350 shmseg->shm_nattch++; 351 uap->sysmsg_resultp = (void *)attach_va; 352 error = 0; 353 done: 354 rel_mplock(); 355 return error; 356 } 357 358 struct oshmid_ds { 359 struct ipc_perm shm_perm; /* operation perms */ 360 int shm_segsz; /* size of segment (bytes) */ 361 ushort shm_cpid; /* pid, creator */ 362 ushort shm_lpid; /* pid, last operation */ 363 short shm_nattch; /* no. of current attaches */ 364 time_t shm_atime; /* last attach time */ 365 time_t shm_dtime; /* last detach time */ 366 time_t shm_ctime; /* last change time */ 367 void *shm_handle; /* internal handle for shm segment */ 368 }; 369 370 struct oshmctl_args { 371 struct sysmsg sysmsg; 372 int shmid; 373 int cmd; 374 struct oshmid_ds *ubuf; 375 }; 376 377 /* 378 * MPALMOSTSAFE 379 */ 380 static int 381 sys_oshmctl(struct proc *p, struct oshmctl_args *uap) 382 { 383 #ifdef COMPAT_43 384 struct thread *td = curthread; 385 struct shmid_ds *shmseg; 386 struct oshmid_ds outbuf; 387 int error; 388 389 if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 390 return (ENOSYS); 391 392 get_mplock(); 393 shmseg = shm_find_segment_by_shmid(uap->shmid); 394 if (shmseg == NULL) { 395 error = EINVAL; 396 goto done; 397 } 398 399 switch (uap->cmd) { 400 case IPC_STAT: 401 error = ipcperm(p, &shmseg->shm_perm, IPC_R); 402 if (error) 403 break; 404 outbuf.shm_perm = shmseg->shm_perm; 405 outbuf.shm_segsz = shmseg->shm_segsz; 406 outbuf.shm_cpid = shmseg->shm_cpid; 407 outbuf.shm_lpid = shmseg->shm_lpid; 408 outbuf.shm_nattch = shmseg->shm_nattch; 409 outbuf.shm_atime = shmseg->shm_atime; 410 outbuf.shm_dtime = shmseg->shm_dtime; 411 outbuf.shm_ctime = shmseg->shm_ctime; 412 outbuf.shm_handle = shmseg->shm_internal; 413 error = copyout((caddr_t)&outbuf, uap->ubuf, sizeof(outbuf)); 414 break; 415 default: 416 /* XXX casting to (sy_call_t *) is bogus, as usual. */ 417 error = sys_shmctl((struct shmctl_args *)uap); 418 } 419 done: 420 rel_mplock(); 421 return error; 422 #else 423 return EINVAL; 424 #endif 425 } 426 427 /* 428 * MPALMOSTSAFE 429 */ 430 int 431 sys_shmctl(struct shmctl_args *uap) 432 { 433 struct thread *td = curthread; 434 struct proc *p = td->td_proc; 435 int error; 436 struct shmid_ds inbuf; 437 struct shmid_ds *shmseg; 438 439 if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 440 return (ENOSYS); 441 442 get_mplock(); 443 shmseg = shm_find_segment_by_shmid(uap->shmid); 444 if (shmseg == NULL) { 445 error = EINVAL; 446 goto done; 447 } 448 449 switch (uap->cmd) { 450 case IPC_STAT: 451 error = ipcperm(p, &shmseg->shm_perm, IPC_R); 452 if (error == 0) 453 error = copyout(shmseg, uap->buf, sizeof(inbuf)); 454 break; 455 case IPC_SET: 456 error = ipcperm(p, &shmseg->shm_perm, IPC_M); 457 if (error == 0) 458 error = copyin(uap->buf, &inbuf, sizeof(inbuf)); 459 if (error == 0) { 460 shmseg->shm_perm.uid = inbuf.shm_perm.uid; 461 shmseg->shm_perm.gid = inbuf.shm_perm.gid; 462 shmseg->shm_perm.mode = 463 (shmseg->shm_perm.mode & ~ACCESSPERMS) | 464 (inbuf.shm_perm.mode & ACCESSPERMS); 465 shmseg->shm_ctime = time_second; 466 } 467 break; 468 case IPC_RMID: 469 error = ipcperm(p, &shmseg->shm_perm, IPC_M); 470 if (error == 0) { 471 shmseg->shm_perm.key = IPC_PRIVATE; 472 shmseg->shm_perm.mode |= SHMSEG_REMOVED; 473 if (shmseg->shm_nattch <= 0) { 474 shm_deallocate_segment(shmseg); 475 shm_last_free = IPCID_TO_IX(uap->shmid); 476 } 477 } 478 break; 479 #if 0 480 case SHM_LOCK: 481 case SHM_UNLOCK: 482 #endif 483 default: 484 error = EINVAL; 485 break; 486 } 487 done: 488 rel_mplock(); 489 return error; 490 } 491 492 static int 493 shmget_existing(struct proc *p, struct shmget_args *uap, int mode, int segnum) 494 { 495 struct shmid_ds *shmseg; 496 int error; 497 498 shmseg = &shmsegs[segnum]; 499 if (shmseg->shm_perm.mode & SHMSEG_REMOVED) { 500 /* 501 * This segment is in the process of being allocated. Wait 502 * until it's done, and look the key up again (in case the 503 * allocation failed or it was freed). 504 */ 505 shmseg->shm_perm.mode |= SHMSEG_WANTED; 506 error = tsleep((caddr_t)shmseg, PCATCH, "shmget", 0); 507 if (error) 508 return error; 509 return EAGAIN; 510 } 511 if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) 512 return EEXIST; 513 error = ipcperm(p, &shmseg->shm_perm, mode); 514 if (error) 515 return error; 516 if (uap->size && uap->size > shmseg->shm_segsz) 517 return EINVAL; 518 uap->sysmsg_result = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm); 519 return 0; 520 } 521 522 static int 523 shmget_allocate_segment(struct proc *p, struct shmget_args *uap, int mode) 524 { 525 int i, segnum, shmid; 526 size_t size; 527 struct ucred *cred = p->p_ucred; 528 struct shmid_ds *shmseg; 529 struct shm_handle *shm_handle; 530 531 if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) 532 return EINVAL; 533 if (shm_nused >= shminfo.shmmni) /* any shmids left? */ 534 return ENOSPC; 535 size = round_page(uap->size); 536 if (shm_committed + btoc(size) > shminfo.shmall) 537 return ENOMEM; 538 if (shm_last_free < 0) { 539 shmrealloc(); /* maybe expand the shmsegs[] array */ 540 for (i = 0; i < shmalloced; i++) { 541 if (shmsegs[i].shm_perm.mode & SHMSEG_FREE) 542 break; 543 } 544 if (i == shmalloced) 545 return ENOSPC; 546 segnum = i; 547 } else { 548 segnum = shm_last_free; 549 shm_last_free = -1; 550 } 551 shmseg = &shmsegs[segnum]; 552 /* 553 * In case we sleep in malloc(), mark the segment present but deleted 554 * so that noone else tries to create the same key. 555 */ 556 shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED; 557 shmseg->shm_perm.key = uap->key; 558 shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff; 559 shm_handle = kmalloc(sizeof(struct shm_handle), M_SHM, M_WAITOK); 560 shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm); 561 562 /* 563 * We make sure that we have allocated a pager before we need 564 * to. 565 */ 566 if (shm_use_phys) { 567 shm_handle->shm_object = 568 phys_pager_alloc(NULL, size, VM_PROT_DEFAULT, 0); 569 } else { 570 shm_handle->shm_object = 571 swap_pager_alloc(NULL, size, VM_PROT_DEFAULT, 0); 572 } 573 vm_object_clear_flag(shm_handle->shm_object, OBJ_ONEMAPPING); 574 vm_object_set_flag(shm_handle->shm_object, OBJ_NOSPLIT); 575 576 shmseg->shm_internal = shm_handle; 577 shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid; 578 shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid; 579 shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) | 580 (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; 581 shmseg->shm_segsz = uap->size; 582 shmseg->shm_cpid = p->p_pid; 583 shmseg->shm_lpid = shmseg->shm_nattch = 0; 584 shmseg->shm_atime = shmseg->shm_dtime = 0; 585 shmseg->shm_ctime = time_second; 586 shm_committed += btoc(size); 587 shm_nused++; 588 589 /* 590 * If a physical mapping is desired and we have a ton of free pages 591 * we pre-allocate the pages here in order to avoid on-the-fly 592 * allocation later. This has a big effect on database warm-up 593 * times since DFly supports concurrent page faults coming from the 594 * same VM object for pages which already exist. 595 * 596 * This can hang the kernel for a while so only do it if shm_use_phys 597 * is set to 2 or higher. 598 */ 599 if (shm_use_phys > 1) { 600 vm_pindex_t pi, pmax; 601 vm_page_t m; 602 603 pmax = round_page(shmseg->shm_segsz) >> PAGE_SHIFT; 604 vm_object_hold(shm_handle->shm_object); 605 if (pmax > vmstats.v_free_count) 606 pmax = vmstats.v_free_count; 607 for (pi = 0; pi < pmax; ++pi) { 608 m = vm_page_grab(shm_handle->shm_object, pi, 609 VM_ALLOC_SYSTEM | VM_ALLOC_NULL_OK | 610 VM_ALLOC_ZERO); 611 if (m == NULL) 612 break; 613 vm_pager_get_page(shm_handle->shm_object, &m, 1); 614 vm_page_activate(m); 615 vm_page_wakeup(m); 616 lwkt_yield(); 617 } 618 vm_object_drop(shm_handle->shm_object); 619 } 620 621 if (shmseg->shm_perm.mode & SHMSEG_WANTED) { 622 /* 623 * Somebody else wanted this key while we were asleep. Wake 624 * them up now. 625 */ 626 shmseg->shm_perm.mode &= ~SHMSEG_WANTED; 627 wakeup((caddr_t)shmseg); 628 } 629 uap->sysmsg_result = shmid; 630 return 0; 631 } 632 633 /* 634 * MPALMOSTSAFE 635 */ 636 int 637 sys_shmget(struct shmget_args *uap) 638 { 639 struct thread *td = curthread; 640 struct proc *p = td->td_proc; 641 int segnum, mode, error; 642 643 if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 644 return (ENOSYS); 645 646 mode = uap->shmflg & ACCESSPERMS; 647 get_mplock(); 648 649 if (uap->key != IPC_PRIVATE) { 650 again: 651 segnum = shm_find_segment_by_key(uap->key); 652 if (segnum >= 0) { 653 error = shmget_existing(p, uap, mode, segnum); 654 if (error == EAGAIN) 655 goto again; 656 goto done; 657 } 658 if ((uap->shmflg & IPC_CREAT) == 0) { 659 error = ENOENT; 660 goto done; 661 } 662 } 663 error = shmget_allocate_segment(p, uap, mode); 664 done: 665 rel_mplock(); 666 return (error); 667 } 668 669 /* 670 * shmsys_args(int which, int a2, ...) (VARARGS) 671 * 672 * MPALMOSTSAFE 673 */ 674 int 675 sys_shmsys(struct shmsys_args *uap) 676 { 677 struct thread *td = curthread; 678 unsigned int which = (unsigned int)uap->which; 679 int error; 680 681 if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) 682 return (ENOSYS); 683 684 if (which >= NELEM(shmcalls)) 685 return EINVAL; 686 get_mplock(); 687 bcopy(&uap->a2, &uap->which, 688 sizeof(struct shmsys_args) - offsetof(struct shmsys_args, a2)); 689 error = ((*shmcalls[which])(uap)); 690 rel_mplock(); 691 692 return(error); 693 } 694 695 void 696 shmfork(struct proc *p1, struct proc *p2) 697 { 698 struct shmmap_state *shmmap_s; 699 size_t size; 700 int i; 701 702 get_mplock(); 703 size = shminfo.shmseg * sizeof(struct shmmap_state); 704 shmmap_s = kmalloc(size, M_SHM, M_WAITOK); 705 bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size); 706 p2->p_vmspace->vm_shm = (caddr_t)shmmap_s; 707 for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { 708 if (shmmap_s->shmid != -1) 709 shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++; 710 } 711 rel_mplock(); 712 } 713 714 void 715 shmexit(struct vmspace *vm) 716 { 717 struct shmmap_state *base, *shm; 718 int i; 719 720 if ((base = (struct shmmap_state *)vm->vm_shm) != NULL) { 721 vm->vm_shm = NULL; 722 get_mplock(); 723 for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) { 724 if (shm->shmid != -1) 725 shm_delete_mapping(vm, shm); 726 } 727 kfree(base, M_SHM); 728 rel_mplock(); 729 } 730 } 731 732 static void 733 shmrealloc(void) 734 { 735 int i; 736 struct shmid_ds *newsegs; 737 738 if (shmalloced >= shminfo.shmmni) 739 return; 740 741 newsegs = kmalloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK); 742 for (i = 0; i < shmalloced; i++) 743 bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0])); 744 for (; i < shminfo.shmmni; i++) { 745 shmsegs[i].shm_perm.mode = SHMSEG_FREE; 746 shmsegs[i].shm_perm.seq = 0; 747 } 748 kfree(shmsegs, M_SHM); 749 shmsegs = newsegs; 750 shmalloced = shminfo.shmmni; 751 } 752 753 static void 754 shminit(void *dummy) 755 { 756 int i; 757 758 /* 759 * If not overridden by a tunable set the maximum shm to 760 * 2/3 of main memory. 761 */ 762 if (shminfo.shmall == 0) 763 shminfo.shmall = (size_t)vmstats.v_page_count * 2 / 3; 764 765 shminfo.shmmax = shminfo.shmall * PAGE_SIZE; 766 shmalloced = shminfo.shmmni; 767 shmsegs = kmalloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK); 768 for (i = 0; i < shmalloced; i++) { 769 shmsegs[i].shm_perm.mode = SHMSEG_FREE; 770 shmsegs[i].shm_perm.seq = 0; 771 } 772 shm_last_free = 0; 773 shm_nused = 0; 774 shm_committed = 0; 775 } 776 SYSINIT(sysv_shm, SI_SUB_SYSV_SHM, SI_ORDER_FIRST, shminit, NULL); 777