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