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