sysv_shm.c revision 162468
190075Sobrien/* $NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $ */ 2169689Skan/*- 3132718Skan * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. 490075Sobrien * 590075Sobrien * Redistribution and use in source and binary forms, with or without 690075Sobrien * modification, are permitted provided that the following conditions 790075Sobrien * are met: 890075Sobrien * 1. Redistributions of source code must retain the above copyright 990075Sobrien * notice, this list of conditions and the following disclaimer. 1090075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1190075Sobrien * notice, this list of conditions and the following disclaimer in the 1290075Sobrien * documentation and/or other materials provided with the distribution. 1390075Sobrien * 3. All advertising materials mentioning features or use of this software 1490075Sobrien * must display the following acknowledgement: 1590075Sobrien * This product includes software developed by Adam Glass and Charles 1690075Sobrien * Hannum. 1790075Sobrien * 4. The names of the authors may not be used to endorse or promote products 1890075Sobrien * derived from this software without specific prior written permission. 19169689Skan * 20169689Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 2190075Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22132718Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2390075Sobrien * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24132718Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25132718Skan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2690075Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2790075Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2890075Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29117395Skan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3090075Sobrien */ 3190075Sobrien/*- 3290075Sobrien * Copyright (c) 2003-2005 McAfee, Inc. 3390075Sobrien * All rights reserved. 3490075Sobrien * 3590075Sobrien * This software was developed for the FreeBSD Project in part by McAfee 36117395Skan * Research, the Security Research Division of McAfee, Inc under DARPA/SPAWAR 37117395Skan * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS research 38169689Skan * program. 39169689Skan * 40169689Skan * Redistribution and use in source and binary forms, with or without 41169689Skan * modification, are permitted provided that the following conditions 42169689Skan * are met: 43169689Skan * 1. Redistributions of source code must retain the above copyright 4490075Sobrien * notice, this list of conditions and the following disclaimer. 4590075Sobrien * 2. Redistributions in binary form must reproduce the above copyright 4690075Sobrien * notice, this list of conditions and the following disclaimer in the 4790075Sobrien * documentation and/or other materials provided with the distribution. 4890075Sobrien * 4990075Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 5090075Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5190075Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5290075Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 5390075Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 54117395Skan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 55117395Skan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5690075Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5790075Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5890075Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5990075Sobrien * SUCH DAMAGE. 6090075Sobrien */ 6190075Sobrien 6290075Sobrien#include <sys/cdefs.h> 6390075Sobrien__FBSDID("$FreeBSD: head/sys/kern/sysv_shm.c 162468 2006-09-20 13:40:00Z rwatson $"); 64117395Skan 6590075Sobrien#include "opt_compat.h" 6690075Sobrien#include "opt_sysvipc.h" 67169689Skan#include "opt_mac.h" 68169689Skan 69169689Skan#include <sys/param.h> 7090075Sobrien#include <sys/systm.h> 7190075Sobrien#include <sys/kernel.h> 7290075Sobrien#include <sys/lock.h> 7390075Sobrien#include <sys/sysctl.h> 74169689Skan#include <sys/shm.h> 75169689Skan#include <sys/proc.h> 7690075Sobrien#include <sys/malloc.h> 7790075Sobrien#include <sys/mman.h> 7890075Sobrien#include <sys/module.h> 7990075Sobrien#include <sys/mutex.h> 8090075Sobrien#include <sys/resourcevar.h> 8190075Sobrien#include <sys/stat.h> 8290075Sobrien#include <sys/syscall.h> 83169689Skan#include <sys/syscallsubr.h> 84169689Skan#include <sys/sysent.h> 8590075Sobrien#include <sys/sysproto.h> 8690075Sobrien#include <sys/jail.h> 8790075Sobrien#include <sys/mac.h> 8890075Sobrien 8990075Sobrien#include <vm/vm.h> 9090075Sobrien#include <vm/vm_param.h> 9190075Sobrien#include <vm/pmap.h> 9290075Sobrien#include <vm/vm_object.h> 9390075Sobrien#include <vm/vm_map.h> 9490075Sobrien#include <vm/vm_page.h> 9590075Sobrien#include <vm/vm_pager.h> 9690075Sobrien 97117395Skanstatic MALLOC_DEFINE(M_SHM, "shm", "SVID compatible shared memory segments"); 9890075Sobrien 9990075Sobrien#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) 100117395Skanstruct oshmctl_args; 10190075Sobrienstatic int oshmctl(struct thread *td, struct oshmctl_args *uap); 102132718Skan#endif 103132718Skan 10490075Sobrienstatic int shmget_allocate_segment(struct thread *td, 105132718Skan struct shmget_args *uap, int mode); 106132718Skanstatic int shmget_existing(struct thread *td, struct shmget_args *uap, 107132718Skan int mode, int segnum); 108132718Skan 109132718Skan#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) 110132718Skan/* XXX casting to (sy_call_t *) is bogus, as usual. */ 111132718Skanstatic sy_call_t *shmcalls[] = { 112132718Skan (sy_call_t *)shmat, (sy_call_t *)oshmctl, 113132718Skan (sy_call_t *)shmdt, (sy_call_t *)shmget, 114132718Skan (sy_call_t *)shmctl 115132718Skan}; 116132718Skan#endif 117132718Skan 118132718Skan#define SHMSEG_FREE 0x0200 119132718Skan#define SHMSEG_REMOVED 0x0400 120169689Skan#define SHMSEG_ALLOCATED 0x0800 121169689Skan#define SHMSEG_WANTED 0x1000 12290075Sobrien 12390075Sobrienstatic int shm_last_free, shm_nused, shm_committed, shmalloced; 124132718Skanstatic struct shmid_kernel *shmsegs; 12590075Sobrien 126132718Skanstruct shmmap_state { 12790075Sobrien vm_offset_t va; 128132718Skan int shmid; 129132718Skan}; 13090075Sobrien 13190075Sobrienstatic void shm_deallocate_segment(struct shmid_kernel *); 13290075Sobrienstatic int shm_find_segment_by_key(key_t); 13390075Sobrienstatic struct shmid_kernel *shm_find_segment_by_shmid(int); 134132718Skanstatic struct shmid_kernel *shm_find_segment_by_shmidx(int); 13590075Sobrienstatic int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *); 13690075Sobrienstatic void shmrealloc(void); 13790075Sobrienstatic void shminit(void); 13890075Sobrienstatic int sysvshm_modload(struct module *, int, void *); 13990075Sobrienstatic int shmunload(void); 14090075Sobrienstatic void shmexit_myhook(struct vmspace *vm); 141169689Skanstatic void shmfork_myhook(struct proc *p1, struct proc *p2); 142132718Skanstatic int sysctl_shmsegs(SYSCTL_HANDLER_ARGS); 14390075Sobrien 14490075Sobrien/* 14590075Sobrien * Tuneable values. 14690075Sobrien */ 14790075Sobrien#ifndef SHMMAXPGS 14890075Sobrien#define SHMMAXPGS 8192 /* Note: sysv shared memory is swap backed. */ 14990075Sobrien#endif 150169689Skan#ifndef SHMMAX 151169689Skan#define SHMMAX (SHMMAXPGS*PAGE_SIZE) 15290075Sobrien#endif 153169689Skan#ifndef SHMMIN 154132718Skan#define SHMMIN 1 155132718Skan#endif 15690075Sobrien#ifndef SHMMNI 157169689Skan#define SHMMNI 192 15890075Sobrien#endif 159117395Skan#ifndef SHMSEG 16090075Sobrien#define SHMSEG 128 16190075Sobrien#endif 162169689Skan#ifndef SHMALL 16390075Sobrien#define SHMALL (SHMMAXPGS) 16490075Sobrien#endif 165169689Skan 16690075Sobrienstruct shminfo shminfo = { 16790075Sobrien SHMMAX, 16890075Sobrien SHMMIN, 16990075Sobrien SHMMNI, 17090075Sobrien SHMSEG, 171132718Skan SHMALL 17290075Sobrien}; 17390075Sobrien 17490075Sobrienstatic int shm_use_phys; 17590075Sobrienstatic int shm_allow_removed; 17690075Sobrien 17790075SobrienSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmax, CTLFLAG_RW, &shminfo.shmmax, 0, 17890075Sobrien "Maximum shared memory segment size"); 17990075SobrienSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmin, CTLFLAG_RW, &shminfo.shmmin, 0, 18090075Sobrien "Minimum shared memory segment size"); 18190075SobrienSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmmni, CTLFLAG_RDTUN, &shminfo.shmmni, 0, 18290075Sobrien "Number of shared memory identifiers"); 18390075SobrienSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmseg, CTLFLAG_RDTUN, &shminfo.shmseg, 0, 18490075Sobrien "Number of segments per process"); 18590075SobrienSYSCTL_ULONG(_kern_ipc, OID_AUTO, shmall, CTLFLAG_RW, &shminfo.shmall, 0, 18690075Sobrien "Maximum number of pages available for shared memory"); 18790075SobrienSYSCTL_INT(_kern_ipc, OID_AUTO, shm_use_phys, CTLFLAG_RW, 18890075Sobrien &shm_use_phys, 0, "Enable/Disable locking of shared memory pages in core"); 18990075SobrienSYSCTL_INT(_kern_ipc, OID_AUTO, shm_allow_removed, CTLFLAG_RW, 19090075Sobrien &shm_allow_removed, 0, 19190075Sobrien "Enable/Disable attachment to attached segments marked for removal"); 19290075SobrienSYSCTL_PROC(_kern_ipc, OID_AUTO, shmsegs, CTLFLAG_RD, 19390075Sobrien NULL, 0, sysctl_shmsegs, "", 19490075Sobrien "Current number of shared memory segments allocated"); 19590075Sobrien 19690075Sobrienstatic int 19790075Sobrienshm_find_segment_by_key(key) 19890075Sobrien key_t key; 19990075Sobrien{ 20090075Sobrien int i; 201132718Skan 202117395Skan for (i = 0; i < shmalloced; i++) 20390075Sobrien if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) && 204117395Skan shmsegs[i].u.shm_perm.key == key) 205132718Skan return (i); 20690075Sobrien return (-1); 20790075Sobrien} 208117395Skan 209117395Skanstatic struct shmid_kernel * 210117395Skanshm_find_segment_by_shmid(int shmid) 21190075Sobrien{ 21290075Sobrien int segnum; 213117395Skan struct shmid_kernel *shmseg; 214132718Skan 21590075Sobrien segnum = IPCID_TO_IX(shmid); 216117395Skan if (segnum < 0 || segnum >= shmalloced) 21790075Sobrien return (NULL); 218117395Skan shmseg = &shmsegs[segnum]; 219117395Skan if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || 22090075Sobrien (!shm_allow_removed && 221117395Skan (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) || 222117395Skan shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid)) 223117395Skan return (NULL); 224117395Skan return (shmseg); 225132718Skan} 226117395Skan 227117395Skanstatic struct shmid_kernel * 22890075Sobrienshm_find_segment_by_shmidx(int segnum) 22990075Sobrien{ 230117395Skan struct shmid_kernel *shmseg; 231117395Skan 232117395Skan if (segnum < 0 || segnum >= shmalloced) 233117395Skan return (NULL); 234117395Skan shmseg = &shmsegs[segnum]; 235117395Skan if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 || 236117395Skan (!shm_allow_removed && 23790075Sobrien (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0)) 238117395Skan return (NULL); 239117395Skan return (shmseg); 240117395Skan} 241117395Skan 242117395Skanstatic void 243117395Skanshm_deallocate_segment(shmseg) 24490075Sobrien struct shmid_kernel *shmseg; 245117395Skan{ 246117395Skan size_t size; 247117395Skan 248117395Skan GIANT_REQUIRED; 249117395Skan 250117395Skan vm_object_deallocate(shmseg->u.shm_internal); 251117395Skan shmseg->u.shm_internal = NULL; 25290075Sobrien size = round_page(shmseg->u.shm_segsz); 253169689Skan shm_committed -= btoc(size); 254169689Skan shm_nused--; 255169689Skan shmseg->u.shm_perm.mode = SHMSEG_FREE; 256117395Skan#ifdef MAC 257169689Skan mac_cleanup_sysv_shm(shmseg); 258169689Skan#endif 25990075Sobrien} 260117395Skan 261117395Skanstatic int 26290075Sobrienshm_delete_mapping(struct vmspace *vm, struct shmmap_state *shmmap_s) 263117395Skan{ 264117395Skan struct shmid_kernel *shmseg; 26590075Sobrien int segnum, result; 266117395Skan size_t size; 26790075Sobrien 26890075Sobrien GIANT_REQUIRED; 269132718Skan 27090075Sobrien segnum = IPCID_TO_IX(shmmap_s->shmid); 27190075Sobrien shmseg = &shmsegs[segnum]; 272132718Skan size = round_page(shmseg->u.shm_segsz); 27390075Sobrien result = vm_map_remove(&vm->vm_map, shmmap_s->va, shmmap_s->va + size); 27490075Sobrien if (result != KERN_SUCCESS) 27590075Sobrien return (EINVAL); 27690075Sobrien shmmap_s->shmid = -1; 277117395Skan shmseg->u.shm_dtime = time_second; 27890075Sobrien if ((--shmseg->u.shm_nattch <= 0) && 27990075Sobrien (shmseg->u.shm_perm.mode & SHMSEG_REMOVED)) { 28090075Sobrien shm_deallocate_segment(shmseg); 281117395Skan shm_last_free = segnum; 28290075Sobrien } 28390075Sobrien return (0); 28490075Sobrien} 285117395Skan 28690075Sobrien#ifndef _SYS_SYSPROTO_H_ 28790075Sobrienstruct shmdt_args { 288169689Skan const void *shmaddr; 289169689Skan}; 290169689Skan#endif 291169689Skan 292169689Skan/* 293169689Skan * MPSAFE 294169689Skan */ 295169689Skanint 296169689Skanshmdt(td, uap) 29790075Sobrien struct thread *td; 298117395Skan struct shmdt_args *uap; 29990075Sobrien{ 30090075Sobrien struct proc *p = td->td_proc; 30190075Sobrien struct shmmap_state *shmmap_s; 30290075Sobrien#ifdef MAC 30390075Sobrien struct shmid_kernel *shmsegptr; 30490075Sobrien#endif 30590075Sobrien int i; 30690075Sobrien int error = 0; 307169689Skan 308169689Skan if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 30990075Sobrien return (ENOSYS); 31090075Sobrien mtx_lock(&Giant); 31190075Sobrien shmmap_s = p->p_vmspace->vm_shm; 31290075Sobrien if (shmmap_s == NULL) { 31390075Sobrien error = EINVAL; 31490075Sobrien goto done2; 31590075Sobrien } 31690075Sobrien for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) { 31790075Sobrien if (shmmap_s->shmid != -1 && 31890075Sobrien shmmap_s->va == (vm_offset_t)uap->shmaddr) { 31990075Sobrien break; 32090075Sobrien } 32190075Sobrien } 32290075Sobrien if (i == shminfo.shmseg) { 32390075Sobrien error = EINVAL; 32490075Sobrien goto done2; 325169689Skan } 326169689Skan#ifdef MAC 327169689Skan shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)]; 328169689Skan error = mac_check_sysv_shmdt(td->td_ucred, shmsegptr); 32990075Sobrien if (error != 0) 33090075Sobrien goto done2; 33190075Sobrien#endif 33290075Sobrien error = shm_delete_mapping(p->p_vmspace, shmmap_s); 33390075Sobriendone2: 33490075Sobrien mtx_unlock(&Giant); 33590075Sobrien return (error); 33690075Sobrien} 33790075Sobrien 33890075Sobrien#ifndef _SYS_SYSPROTO_H_ 339169689Skanstruct shmat_args { 340169689Skan int shmid; 341169689Skan const void *shmaddr; 342169689Skan int shmflg; 343169689Skan}; 344169689Skan#endif 34590075Sobrien 34690075Sobrien/* 34790075Sobrien * MPSAFE 34890075Sobrien */ 349117395Skanint 35090075Sobrienkern_shmat(td, shmid, shmaddr, shmflg) 35190075Sobrien struct thread *td; 35290075Sobrien int shmid; 35390075Sobrien const void *shmaddr; 35490075Sobrien int shmflg; 35590075Sobrien{ 35690075Sobrien struct proc *p = td->td_proc; 35790075Sobrien int i, flags; 358132718Skan struct shmid_kernel *shmseg; 35990075Sobrien struct shmmap_state *shmmap_s = NULL; 36090075Sobrien vm_offset_t attach_va; 36190075Sobrien vm_prot_t prot; 36290075Sobrien vm_size_t size; 36390075Sobrien int rv; 36490075Sobrien int error = 0; 36590075Sobrien 36690075Sobrien if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 36790075Sobrien return (ENOSYS); 36890075Sobrien mtx_lock(&Giant); 36990075Sobrien shmmap_s = p->p_vmspace->vm_shm; 37090075Sobrien if (shmmap_s == NULL) { 37190075Sobrien size = shminfo.shmseg * sizeof(struct shmmap_state); 37290075Sobrien shmmap_s = malloc(size, M_SHM, M_WAITOK); 37390075Sobrien for (i = 0; i < shminfo.shmseg; i++) 37490075Sobrien shmmap_s[i].shmid = -1; 37590075Sobrien p->p_vmspace->vm_shm = shmmap_s; 37690075Sobrien } 37790075Sobrien shmseg = shm_find_segment_by_shmid(shmid); 37890075Sobrien if (shmseg == NULL) { 37990075Sobrien error = EINVAL; 38090075Sobrien goto done2; 38190075Sobrien } 38290075Sobrien error = ipcperm(td, &shmseg->u.shm_perm, 38390075Sobrien (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); 38490075Sobrien if (error) 38590075Sobrien goto done2; 38690075Sobrien#ifdef MAC 38790075Sobrien error = mac_check_sysv_shmat(td->td_ucred, shmseg, shmflg); 38890075Sobrien if (error != 0) 38990075Sobrien goto done2; 39090075Sobrien#endif 39190075Sobrien for (i = 0; i < shminfo.shmseg; i++) { 39290075Sobrien if (shmmap_s->shmid == -1) 39390075Sobrien break; 39490075Sobrien shmmap_s++; 39590075Sobrien } 39690075Sobrien if (i >= shminfo.shmseg) { 39790075Sobrien error = EMFILE; 39890075Sobrien goto done2; 39990075Sobrien } 40090075Sobrien size = round_page(shmseg->u.shm_segsz); 40190075Sobrien#ifdef VM_PROT_READ_IS_EXEC 40290075Sobrien prot = VM_PROT_READ | VM_PROT_EXECUTE; 40390075Sobrien#else 40490075Sobrien prot = VM_PROT_READ; 40590075Sobrien#endif 40690075Sobrien if ((shmflg & SHM_RDONLY) == 0) 40790075Sobrien prot |= VM_PROT_WRITE; 40890075Sobrien flags = MAP_ANON | MAP_SHARED; 40990075Sobrien if (shmaddr) { 410169689Skan flags |= MAP_FIXED; 41190075Sobrien if (shmflg & SHM_RND) { 41290075Sobrien attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1); 41390075Sobrien } else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) { 41490075Sobrien attach_va = (vm_offset_t)shmaddr; 41590075Sobrien } else { 41690075Sobrien error = EINVAL; 41790075Sobrien goto done2; 41890075Sobrien } 41990075Sobrien } else { 42090075Sobrien /* 42190075Sobrien * This is just a hint to vm_map_find() about where to 42290075Sobrien * put it. 42390075Sobrien */ 42490075Sobrien PROC_LOCK(p); 42590075Sobrien attach_va = round_page((vm_offset_t)p->p_vmspace->vm_daddr + 42690075Sobrien lim_max(p, RLIMIT_DATA)); 42790075Sobrien PROC_UNLOCK(p); 42890075Sobrien } 42990075Sobrien 43090075Sobrien vm_object_reference(shmseg->u.shm_internal); 43190075Sobrien rv = vm_map_find(&p->p_vmspace->vm_map, shmseg->u.shm_internal, 43290075Sobrien 0, &attach_va, size, (flags & MAP_FIXED)?0:1, prot, prot, 0); 43390075Sobrien if (rv != KERN_SUCCESS) { 43490075Sobrien vm_object_deallocate(shmseg->u.shm_internal); 43590075Sobrien error = ENOMEM; 43690075Sobrien goto done2; 43790075Sobrien } 43890075Sobrien vm_map_inherit(&p->p_vmspace->vm_map, 43990075Sobrien attach_va, attach_va + size, VM_INHERIT_SHARE); 44090075Sobrien 44190075Sobrien shmmap_s->va = attach_va; 44290075Sobrien shmmap_s->shmid = shmid; 44390075Sobrien shmseg->u.shm_lpid = p->p_pid; 44490075Sobrien shmseg->u.shm_atime = time_second; 44590075Sobrien shmseg->u.shm_nattch++; 446132718Skan td->td_retval[0] = attach_va; 44790075Sobriendone2: 44890075Sobrien mtx_unlock(&Giant); 44990075Sobrien return (error); 45090075Sobrien} 45190075Sobrien 45290075Sobrienint 45390075Sobrienshmat(td, uap) 45490075Sobrien struct thread *td; 45590075Sobrien struct shmat_args *uap; 45690075Sobrien{ 45790075Sobrien return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg); 45890075Sobrien} 45990075Sobrien 46090075Sobrien#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) 46190075Sobrienstruct oshmid_ds { 46290075Sobrien struct ipc_perm shm_perm; /* operation perms */ 46390075Sobrien int shm_segsz; /* size of segment (bytes) */ 464117395Skan u_short shm_cpid; /* pid, creator */ 46590075Sobrien u_short shm_lpid; /* pid, last operation */ 46690075Sobrien short shm_nattch; /* no. of current attaches */ 46790075Sobrien time_t shm_atime; /* last attach time */ 46890075Sobrien time_t shm_dtime; /* last detach time */ 46990075Sobrien time_t shm_ctime; /* last change time */ 47090075Sobrien void *shm_handle; /* internal handle for shm segment */ 471169689Skan}; 472169689Skan 47390075Sobrienstruct oshmctl_args { 47490075Sobrien int shmid; 47590075Sobrien int cmd; 47690075Sobrien struct oshmid_ds *ubuf; 47790075Sobrien}; 47890075Sobrien 47990075Sobrien/* 48090075Sobrien * MPSAFE 48190075Sobrien */ 48290075Sobrienstatic int 48390075Sobrienoshmctl(td, uap) 48490075Sobrien struct thread *td; 48590075Sobrien struct oshmctl_args *uap; 48690075Sobrien{ 48790075Sobrien#ifdef COMPAT_43 48890075Sobrien int error = 0; 48990075Sobrien struct shmid_kernel *shmseg; 490169689Skan struct oshmid_ds outbuf; 491169689Skan 49290075Sobrien if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 49390075Sobrien return (ENOSYS); 49490075Sobrien mtx_lock(&Giant); 49590075Sobrien shmseg = shm_find_segment_by_shmid(uap->shmid); 49690075Sobrien if (shmseg == NULL) { 49790075Sobrien error = EINVAL; 498169689Skan goto done2; 499169689Skan } 50090075Sobrien switch (uap->cmd) { 50190075Sobrien case IPC_STAT: 50290075Sobrien error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); 50390075Sobrien if (error) 50490075Sobrien goto done2; 50590075Sobrien#ifdef MAC 50690075Sobrien error = mac_check_sysv_shmctl(td->td_ucred, shmseg, uap->cmd); 50790075Sobrien if (error != 0) 50890075Sobrien goto done2; 50990075Sobrien#endif 51090075Sobrien outbuf.shm_perm = shmseg->u.shm_perm; 51190075Sobrien outbuf.shm_segsz = shmseg->u.shm_segsz; 51290075Sobrien outbuf.shm_cpid = shmseg->u.shm_cpid; 513169689Skan outbuf.shm_lpid = shmseg->u.shm_lpid; 514169689Skan outbuf.shm_nattch = shmseg->u.shm_nattch; 51590075Sobrien outbuf.shm_atime = shmseg->u.shm_atime; 51690075Sobrien outbuf.shm_dtime = shmseg->u.shm_dtime; 51790075Sobrien outbuf.shm_ctime = shmseg->u.shm_ctime; 51890075Sobrien outbuf.shm_handle = shmseg->u.shm_internal; 51990075Sobrien error = copyout(&outbuf, uap->ubuf, sizeof(outbuf)); 52090075Sobrien if (error) 521132718Skan goto done2; 52290075Sobrien break; 52390075Sobrien default: 52490075Sobrien error = shmctl(td, (struct shmctl_args *)uap); 52590075Sobrien break; 52690075Sobrien } 52790075Sobriendone2: 52890075Sobrien mtx_unlock(&Giant); 52990075Sobrien return (error); 53090075Sobrien#else 53190075Sobrien return (EINVAL); 53290075Sobrien#endif 53390075Sobrien} 53490075Sobrien#endif 53590075Sobrien 536132718Skan#ifndef _SYS_SYSPROTO_H_ 53790075Sobrienstruct shmctl_args { 53890075Sobrien int shmid; 53990075Sobrien int cmd; 54090075Sobrien struct shmid_ds *buf; 54190075Sobrien}; 54290075Sobrien#endif 54390075Sobrien 54490075Sobrien/* 54590075Sobrien * MPSAFE 54690075Sobrien */ 54790075Sobrienint 548132718Skankern_shmctl(td, shmid, cmd, buf, bufsz) 54990075Sobrien struct thread *td; 55090075Sobrien int shmid; 55190075Sobrien int cmd; 55290075Sobrien void *buf; 55390075Sobrien size_t *bufsz; 55490075Sobrien{ 55590075Sobrien int error = 0; 55690075Sobrien struct shmid_kernel *shmseg; 55790075Sobrien 55890075Sobrien if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 55990075Sobrien return (ENOSYS); 56090075Sobrien 56190075Sobrien mtx_lock(&Giant); 56290075Sobrien switch (cmd) { 56390075Sobrien case IPC_INFO: 56490075Sobrien memcpy(buf, &shminfo, sizeof(shminfo)); 56590075Sobrien if (bufsz) 56690075Sobrien *bufsz = sizeof(shminfo); 56790075Sobrien td->td_retval[0] = shmalloced; 56890075Sobrien goto done2; 56990075Sobrien case SHM_INFO: { 57090075Sobrien struct shm_info shm_info; 57190075Sobrien shm_info.used_ids = shm_nused; 57290075Sobrien shm_info.shm_rss = 0; /*XXX where to get from ? */ 57390075Sobrien shm_info.shm_tot = 0; /*XXX where to get from ? */ 57490075Sobrien shm_info.shm_swp = 0; /*XXX where to get from ? */ 575132718Skan shm_info.swap_attempts = 0; /*XXX where to get from ? */ 57690075Sobrien shm_info.swap_successes = 0; /*XXX where to get from ? */ 57790075Sobrien memcpy(buf, &shm_info, sizeof(shm_info)); 57890075Sobrien if (bufsz) 57990075Sobrien *bufsz = sizeof(shm_info); 58090075Sobrien td->td_retval[0] = shmalloced; 58190075Sobrien goto done2; 58290075Sobrien } 58390075Sobrien } 58490075Sobrien if (cmd == SHM_STAT) 585169689Skan shmseg = shm_find_segment_by_shmidx(shmid); 58690075Sobrien else 58790075Sobrien shmseg = shm_find_segment_by_shmid(shmid); 58890075Sobrien if (shmseg == NULL) { 58990075Sobrien error = EINVAL; 59090075Sobrien goto done2; 591132718Skan } 59290075Sobrien#ifdef MAC 59390075Sobrien error = mac_check_sysv_shmctl(td->td_ucred, shmseg, cmd); 59490075Sobrien if (error != 0) 59590075Sobrien goto done2; 59690075Sobrien#endif 59790075Sobrien switch (cmd) { 59890075Sobrien case SHM_STAT: 59990075Sobrien case IPC_STAT: 60090075Sobrien error = ipcperm(td, &shmseg->u.shm_perm, IPC_R); 60190075Sobrien if (error) 60290075Sobrien goto done2; 60390075Sobrien memcpy(buf, &shmseg->u, sizeof(struct shmid_ds)); 60490075Sobrien if (bufsz) 60590075Sobrien *bufsz = sizeof(struct shmid_ds); 60690075Sobrien if (cmd == SHM_STAT) 60790075Sobrien td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->u.shm_perm); 60890075Sobrien break; 60990075Sobrien case IPC_SET: { 61090075Sobrien struct shmid_ds *shmid; 61190075Sobrien 61290075Sobrien shmid = (struct shmid_ds *)buf; 61390075Sobrien error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); 61490075Sobrien if (error) 61590075Sobrien goto done2; 61690075Sobrien shmseg->u.shm_perm.uid = shmid->shm_perm.uid; 61790075Sobrien shmseg->u.shm_perm.gid = shmid->shm_perm.gid; 618169689Skan shmseg->u.shm_perm.mode = 61990075Sobrien (shmseg->u.shm_perm.mode & ~ACCESSPERMS) | 62090075Sobrien (shmid->shm_perm.mode & ACCESSPERMS); 62190075Sobrien shmseg->u.shm_ctime = time_second; 62290075Sobrien break; 62390075Sobrien } 62490075Sobrien case IPC_RMID: 62590075Sobrien error = ipcperm(td, &shmseg->u.shm_perm, IPC_M); 62690075Sobrien if (error) 62790075Sobrien goto done2; 62890075Sobrien shmseg->u.shm_perm.key = IPC_PRIVATE; 62990075Sobrien shmseg->u.shm_perm.mode |= SHMSEG_REMOVED; 630132718Skan if (shmseg->u.shm_nattch <= 0) { 63190075Sobrien shm_deallocate_segment(shmseg); 63290075Sobrien shm_last_free = IPCID_TO_IX(shmid); 63390075Sobrien } 63490075Sobrien break; 63590075Sobrien#if 0 63690075Sobrien case SHM_LOCK: 63790075Sobrien case SHM_UNLOCK: 63890075Sobrien#endif 63990075Sobrien default: 64090075Sobrien error = EINVAL; 64190075Sobrien break; 64290075Sobrien } 64390075Sobriendone2: 64490075Sobrien mtx_unlock(&Giant); 64590075Sobrien return (error); 64690075Sobrien} 64790075Sobrien 64890075Sobrienint 64990075Sobrienshmctl(td, uap) 65090075Sobrien struct thread *td; 65190075Sobrien struct shmctl_args *uap; 65290075Sobrien{ 65390075Sobrien int error = 0; 65490075Sobrien struct shmid_ds buf; 65590075Sobrien size_t bufsz; 65690075Sobrien 65790075Sobrien /* IPC_SET needs to copyin the buffer before calling kern_shmctl */ 65890075Sobrien if (uap->cmd == IPC_SET) { 65990075Sobrien if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds)))) 66090075Sobrien goto done; 66190075Sobrien } 66290075Sobrien 66390075Sobrien error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz); 66490075Sobrien if (error) 66590075Sobrien goto done; 66690075Sobrien 66790075Sobrien /* Cases in which we need to copyout */ 66890075Sobrien switch (uap->cmd) { 66990075Sobrien case IPC_INFO: 67090075Sobrien case SHM_INFO: 671169689Skan case SHM_STAT: 67290075Sobrien case IPC_STAT: 67390075Sobrien error = copyout(&buf, uap->buf, bufsz); 67490075Sobrien break; 67590075Sobrien } 67690075Sobrien 67790075Sobriendone: 67890075Sobrien if (error) { 679132718Skan /* Invalidate the return value */ 680132718Skan td->td_retval[0] = -1; 68190075Sobrien } 682169689Skan return (error); 683169689Skan} 68490075Sobrien 68590075Sobrien 686169689Skan#ifndef _SYS_SYSPROTO_H_ 68790075Sobrienstruct shmget_args { 68890075Sobrien key_t key; 68990075Sobrien size_t size; 69090075Sobrien int shmflg; 691169689Skan}; 69290075Sobrien#endif 693169689Skan 69490075Sobrienstatic int 695169689Skanshmget_existing(td, uap, mode, segnum) 696169689Skan struct thread *td; 69790075Sobrien struct shmget_args *uap; 69890075Sobrien int mode; 699169689Skan int segnum; 70090075Sobrien{ 70190075Sobrien struct shmid_kernel *shmseg; 70290075Sobrien int error; 70390075Sobrien 704169689Skan shmseg = &shmsegs[segnum]; 705169689Skan if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) { 70690075Sobrien /* 707169689Skan * This segment is in the process of being allocated. Wait 70890075Sobrien * until it's done, and look the key up again (in case the 70990075Sobrien * allocation failed or it was freed). 71090075Sobrien */ 711169689Skan shmseg->u.shm_perm.mode |= SHMSEG_WANTED; 71290075Sobrien error = tsleep(shmseg, PLOCK | PCATCH, "shmget", 0); 71390075Sobrien if (error) 71490075Sobrien return (error); 715132718Skan return (EAGAIN); 716132718Skan } 717132718Skan if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) 71890075Sobrien return (EEXIST); 71990075Sobrien#ifdef MAC 720169689Skan error = mac_check_sysv_shmget(td->td_ucred, shmseg, uap->shmflg); 72190075Sobrien if (error != 0) 72290075Sobrien return (error); 72390075Sobrien#endif 72490075Sobrien error = ipcperm(td, &shmseg->u.shm_perm, mode); 72590075Sobrien if (error) 72690075Sobrien return (error); 72790075Sobrien if (uap->size && uap->size > shmseg->u.shm_segsz) 72890075Sobrien return (EINVAL); 72990075Sobrien td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); 73090075Sobrien return (0); 73190075Sobrien} 73290075Sobrien 73390075Sobrienstatic int 73490075Sobrienshmget_allocate_segment(td, uap, mode) 73590075Sobrien struct thread *td; 73690075Sobrien struct shmget_args *uap; 73790075Sobrien int mode; 73890075Sobrien{ 73990075Sobrien int i, segnum, shmid, size; 740169689Skan struct ucred *cred = td->td_ucred; 74190075Sobrien struct shmid_kernel *shmseg; 74290075Sobrien vm_object_t shm_object; 74390075Sobrien 74490075Sobrien GIANT_REQUIRED; 74590075Sobrien 74690075Sobrien if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax) 74790075Sobrien return (EINVAL); 74890075Sobrien if (shm_nused >= shminfo.shmmni) /* Any shmids left? */ 74990075Sobrien return (ENOSPC); 75090075Sobrien size = round_page(uap->size); 75190075Sobrien if (shm_committed + btoc(size) > shminfo.shmall) 75290075Sobrien return (ENOMEM); 75390075Sobrien if (shm_last_free < 0) { 75490075Sobrien shmrealloc(); /* Maybe expand the shmsegs[] array. */ 75590075Sobrien for (i = 0; i < shmalloced; i++) 75690075Sobrien if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE) 75790075Sobrien break; 75890075Sobrien if (i == shmalloced) 75990075Sobrien return (ENOSPC); 76090075Sobrien segnum = i; 76190075Sobrien } else { 76290075Sobrien segnum = shm_last_free; 76390075Sobrien shm_last_free = -1; 764169689Skan } 76590075Sobrien shmseg = &shmsegs[segnum]; 766169689Skan /* 76790075Sobrien * In case we sleep in malloc(), mark the segment present but deleted 76890075Sobrien * so that noone else tries to create the same key. 76990075Sobrien */ 77090075Sobrien shmseg->u.shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED; 771169689Skan shmseg->u.shm_perm.key = uap->key; 77290075Sobrien shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff; 77390075Sobrien shmid = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm); 77490075Sobrien 77590075Sobrien /* 77690075Sobrien * We make sure that we have allocated a pager before we need 777132718Skan * to. 77890075Sobrien */ 77990075Sobrien if (shm_use_phys) { 78090075Sobrien shm_object = 78190075Sobrien vm_pager_allocate(OBJT_PHYS, 0, size, VM_PROT_DEFAULT, 0); 78290075Sobrien } else { 783169689Skan shm_object = 784169689Skan vm_pager_allocate(OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0); 78590075Sobrien } 78690075Sobrien VM_OBJECT_LOCK(shm_object); 78790075Sobrien vm_object_clear_flag(shm_object, OBJ_ONEMAPPING); 78890075Sobrien vm_object_set_flag(shm_object, OBJ_NOSPLIT); 78990075Sobrien VM_OBJECT_UNLOCK(shm_object); 79090075Sobrien 79190075Sobrien shmseg->u.shm_internal = shm_object; 79290075Sobrien shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid; 79390075Sobrien shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid; 79490075Sobrien shmseg->u.shm_perm.mode = (shmseg->u.shm_perm.mode & SHMSEG_WANTED) | 79590075Sobrien (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; 79690075Sobrien shmseg->u.shm_segsz = uap->size; 79790075Sobrien shmseg->u.shm_cpid = td->td_proc->p_pid; 79890075Sobrien shmseg->u.shm_lpid = shmseg->u.shm_nattch = 0; 79990075Sobrien shmseg->u.shm_atime = shmseg->u.shm_dtime = 0; 80090075Sobrien#ifdef MAC 80190075Sobrien mac_create_sysv_shm(cred, shmseg); 80290075Sobrien#endif 80390075Sobrien shmseg->u.shm_ctime = time_second; 80490075Sobrien shm_committed += btoc(size); 80590075Sobrien shm_nused++; 80690075Sobrien if (shmseg->u.shm_perm.mode & SHMSEG_WANTED) { 80790075Sobrien /* 80890075Sobrien * Somebody else wanted this key while we were asleep. Wake 80990075Sobrien * them up now. 81090075Sobrien */ 81190075Sobrien shmseg->u.shm_perm.mode &= ~SHMSEG_WANTED; 81290075Sobrien wakeup(shmseg); 81390075Sobrien } 81490075Sobrien td->td_retval[0] = shmid; 81590075Sobrien return (0); 81690075Sobrien} 81790075Sobrien 81890075Sobrien/* 81990075Sobrien * MPSAFE 82090075Sobrien */ 82190075Sobrienint 82290075Sobrienshmget(td, uap) 82390075Sobrien struct thread *td; 82490075Sobrien struct shmget_args *uap; 82590075Sobrien{ 82690075Sobrien int segnum, mode; 82790075Sobrien int error; 82890075Sobrien 82990075Sobrien if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 83090075Sobrien return (ENOSYS); 83190075Sobrien mtx_lock(&Giant); 83290075Sobrien mode = uap->shmflg & ACCESSPERMS; 83390075Sobrien if (uap->key != IPC_PRIVATE) { 83490075Sobrien again: 83590075Sobrien segnum = shm_find_segment_by_key(uap->key); 83690075Sobrien if (segnum >= 0) { 83790075Sobrien error = shmget_existing(td, uap, mode, segnum); 83890075Sobrien if (error == EAGAIN) 83990075Sobrien goto again; 84090075Sobrien goto done2; 84190075Sobrien } 84290075Sobrien if ((uap->shmflg & IPC_CREAT) == 0) { 84390075Sobrien error = ENOENT; 84490075Sobrien goto done2; 845117395Skan } 846117395Skan } 847169689Skan error = shmget_allocate_segment(td, uap, mode); 848169689Skandone2: 849169689Skan mtx_unlock(&Giant); 850169689Skan return (error); 851169689Skan} 852169689Skan 853169689Skan/* 854169689Skan * MPSAFE 855169689Skan */ 856169689Skanint 857169689Skanshmsys(td, uap) 858169689Skan struct thread *td; 859169689Skan /* XXX actually varargs. */ 860169689Skan struct shmsys_args /* { 861169689Skan int which; 862169689Skan int a2; 863169689Skan int a3; 864169689Skan int a4; 865169689Skan } */ *uap; 866169689Skan{ 867169689Skan#if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43)) 868169689Skan int error; 869169689Skan 870169689Skan if (!jail_sysvipc_allowed && jailed(td->td_ucred)) 871169689Skan return (ENOSYS); 872169689Skan if (uap->which < 0 || 873169689Skan uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) 874169689Skan return (EINVAL); 875169689Skan mtx_lock(&Giant); 876169689Skan error = (*shmcalls[uap->which])(td, &uap->a2); 877169689Skan mtx_unlock(&Giant); 878169689Skan return (error); 879169689Skan#else 880169689Skan return (nosys(td, NULL)); 88190075Sobrien#endif 88290075Sobrien} 88390075Sobrien 88490075Sobrienstatic void 88590075Sobrienshmfork_myhook(p1, p2) 88690075Sobrien struct proc *p1, *p2; 88790075Sobrien{ 888132718Skan struct shmmap_state *shmmap_s; 88990075Sobrien size_t size; 89090075Sobrien int i; 89190075Sobrien 89290075Sobrien mtx_lock(&Giant); 89390075Sobrien size = shminfo.shmseg * sizeof(struct shmmap_state); 89490075Sobrien shmmap_s = malloc(size, M_SHM, M_WAITOK); 89590075Sobrien bcopy(p1->p_vmspace->vm_shm, shmmap_s, size); 89690075Sobrien p2->p_vmspace->vm_shm = shmmap_s; 89790075Sobrien for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) 89890075Sobrien if (shmmap_s->shmid != -1) 89990075Sobrien shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++; 90090075Sobrien mtx_unlock(&Giant); 901132718Skan} 90290075Sobrien 903169689Skanstatic void 90490075Sobrienshmexit_myhook(struct vmspace *vm) 90590075Sobrien{ 90690075Sobrien struct shmmap_state *base, *shm; 90790075Sobrien int i; 90890075Sobrien 90990075Sobrien if ((base = vm->vm_shm) != NULL) { 91090075Sobrien vm->vm_shm = NULL; 91190075Sobrien mtx_lock(&Giant); 91290075Sobrien for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) { 91390075Sobrien if (shm->shmid != -1) 914169689Skan shm_delete_mapping(vm, shm); 91590075Sobrien } 916169689Skan mtx_unlock(&Giant); 917169689Skan free(base, M_SHM); 918169689Skan } 919169689Skan} 920169689Skan 921169689Skanstatic void 92290075Sobrienshmrealloc(void) 923169689Skan{ 924169689Skan int i; 925169689Skan struct shmid_kernel *newsegs; 926169689Skan 92790075Sobrien if (shmalloced >= shminfo.shmmni) 92890075Sobrien return; 92990075Sobrien 930169689Skan newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK); 931169689Skan if (newsegs == NULL) 932169689Skan return; 933169689Skan for (i = 0; i < shmalloced; i++) 93490075Sobrien bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0])); 935169689Skan for (; i < shminfo.shmmni; i++) { 936169689Skan shmsegs[i].u.shm_perm.mode = SHMSEG_FREE; 937169689Skan shmsegs[i].u.shm_perm.seq = 0; 93890075Sobrien#ifdef MAC 939169689Skan mac_init_sysv_shm(&shmsegs[i]); 940169689Skan#endif 941169689Skan } 942169689Skan free(shmsegs, M_SHM); 943169689Skan shmsegs = newsegs; 944169689Skan shmalloced = shminfo.shmmni; 945169689Skan} 946169689Skan 947169689Skanstatic void 948169689Skanshminit() 949169689Skan{ 950169689Skan int i; 951169689Skan 952169689Skan TUNABLE_ULONG_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall); 953169689Skan for (i = PAGE_SIZE; i > 0; i--) { 954169689Skan shminfo.shmmax = shminfo.shmall * i; 955169689Skan if (shminfo.shmmax >= shminfo.shmall) 95690075Sobrien break; 957169689Skan } 958169689Skan TUNABLE_ULONG_FETCH("kern.ipc.shmmin", &shminfo.shmmin); 959169689Skan TUNABLE_ULONG_FETCH("kern.ipc.shmmni", &shminfo.shmmni); 960169689Skan TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &shminfo.shmseg); 96190075Sobrien TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys); 962169689Skan 963169689Skan shmalloced = shminfo.shmmni; 964169689Skan shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK); 965169689Skan if (shmsegs == NULL) 966169689Skan panic("cannot allocate initial memory for sysvshm"); 96790075Sobrien for (i = 0; i < shmalloced; i++) { 968169689Skan shmsegs[i].u.shm_perm.mode = SHMSEG_FREE; 969169689Skan shmsegs[i].u.shm_perm.seq = 0; 970169689Skan#ifdef MAC 971169689Skan mac_init_sysv_shm(&shmsegs[i]); 972169689Skan#endif 97390075Sobrien } 974169689Skan shm_last_free = 0; 975169689Skan shm_nused = 0; 97690075Sobrien shm_committed = 0; 97790075Sobrien shmexit_hook = &shmexit_myhook; 978169689Skan shmfork_hook = &shmfork_myhook; 979117395Skan} 980169689Skan 981169689Skanstatic int 982169689Skanshmunload() 98390075Sobrien{ 98490075Sobrien#ifdef MAC 98590075Sobrien int i; 986169689Skan#endif 987169689Skan 98890075Sobrien if (shm_nused > 0) 989169689Skan return (EBUSY); 990169689Skan 991169689Skan#ifdef MAC 99290075Sobrien for (i = 0; i < shmalloced; i++) 993169689Skan mac_destroy_sysv_shm(&shmsegs[i]); 994169689Skan#endif 995169689Skan free(shmsegs, M_SHM); 996169689Skan shmexit_hook = NULL; 997169689Skan shmfork_hook = NULL; 998169689Skan return (0); 999169689Skan} 1000169689Skan 1001169689Skanstatic int 1002169689Skansysctl_shmsegs(SYSCTL_HANDLER_ARGS) 1003169689Skan{ 1004169689Skan 1005169689Skan return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0]))); 100690075Sobrien} 1007169689Skan 1008169689Skanstatic int 1009169689Skansysvshm_modload(struct module *module, int cmd, void *arg) 1010169689Skan{ 1011169689Skan int error = 0; 1012169689Skan 1013169689Skan switch (cmd) { 1014169689Skan case MOD_LOAD: 1015169689Skan shminit(); 1016169689Skan break; 1017169689Skan case MOD_UNLOAD: 1018169689Skan error = shmunload(); 1019169689Skan break; 1020169689Skan case MOD_SHUTDOWN: 102190075Sobrien break; 1022169689Skan default: 1023169689Skan error = EINVAL; 1024169689Skan break; 1025169689Skan } 1026169689Skan return (error); 1027169689Skan} 1028169689Skan 1029169689Skanstatic moduledata_t sysvshm_mod = { 1030169689Skan "sysvshm", 1031169689Skan &sysvshm_modload, 1032169689Skan NULL 1033169689Skan}; 1034169689Skan 1035169689SkanSYSCALL_MODULE_HELPER(shmsys); 1036169689SkanSYSCALL_MODULE_HELPER(shmat); 1037169689SkanSYSCALL_MODULE_HELPER(shmctl); 1038169689SkanSYSCALL_MODULE_HELPER(shmdt); 1039169689SkanSYSCALL_MODULE_HELPER(shmget); 1040169689Skan 1041169689SkanDECLARE_MODULE(sysvshm, sysvshm_mod, 1042169689Skan SI_SUB_SYSV_SHM, SI_ORDER_FIRST); 1043169689SkanMODULE_VERSION(sysvshm, 1); 104490075Sobrien