xref: /freebsd/sys/kern/sysv_shm.c (revision 41466b50c1d5bfd1cf6adaae547a579a75d7c04e)
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 __P((struct thread *td, struct oshmctl_args *uap));
65 
66 static int shmget_allocate_segment __P((struct thread *td,
67     struct shmget_args *uap, int mode));
68 static int shmget_existing __P((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 __P((struct shmid_ds *));
97 static int shm_find_segment_by_key __P((key_t));
98 static struct shmid_ds *shm_find_segment_by_shmid __P((int));
99 static struct shmid_ds *shm_find_segment_by_shmidx __P((int));
100 static int shm_delete_mapping __P((struct proc *p, struct shmmap_state *));
101 static void shmrealloc __P((void));
102 static void shminit __P((void));
103 static int sysvshm_modload __P((struct module *, int, void *));
104 static int shmunload __P((void));
105 static void shmexit_myhook __P((struct proc *p));
106 static void shmfork_myhook __P((struct proc *p1, struct proc *p2));
107 static int sysctl_shmsegs __P((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((caddr_t)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(p, shmmap_s)
218 	struct proc *p;
219 	struct shmmap_state *shmmap_s;
220 {
221 	struct shmid_ds *shmseg;
222 	int segnum, result;
223 	size_t size;
224 
225 	GIANT_REQUIRED;
226 
227 	segnum = IPCID_TO_IX(shmmap_s->shmid);
228 	shmseg = &shmsegs[segnum];
229 	size = round_page(shmseg->shm_segsz);
230 	result = vm_map_remove(&p->p_vmspace->vm_map, shmmap_s->va,
231 	    shmmap_s->va + size);
232 	if (result != KERN_SUCCESS)
233 		return EINVAL;
234 	shmmap_s->shmid = -1;
235 	shmseg->shm_dtime = time_second;
236 	if ((--shmseg->shm_nattch <= 0) &&
237 	    (shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
238 		shm_deallocate_segment(shmseg);
239 		shm_last_free = segnum;
240 	}
241 	return 0;
242 }
243 
244 #ifndef _SYS_SYSPROTO_H_
245 struct shmdt_args {
246 	void *shmaddr;
247 };
248 #endif
249 
250 /*
251  * MPSAFE
252  */
253 int
254 shmdt(td, uap)
255 	struct thread *td;
256 	struct shmdt_args *uap;
257 {
258 	struct proc *p = td->td_proc;
259 	struct shmmap_state *shmmap_s;
260 	int i;
261 	int error = 0;
262 
263 	mtx_lock(&Giant);
264 	if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
265 		error = ENOSYS;
266 		goto done2;
267 	}
268 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
269  	if (shmmap_s == NULL) {
270 		error = EINVAL;
271 		goto done2;
272 	}
273 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
274 		if (shmmap_s->shmid != -1 &&
275 		    shmmap_s->va == (vm_offset_t)uap->shmaddr) {
276 			break;
277 		}
278 	}
279 	if (i == shminfo.shmseg) {
280 		error = EINVAL;
281 		goto done2;
282 	}
283 	error = shm_delete_mapping(p, shmmap_s);
284 done2:
285 	mtx_unlock(&Giant);
286 	return (error);
287 }
288 
289 #ifndef _SYS_SYSPROTO_H_
290 struct shmat_args {
291 	int shmid;
292 	void *shmaddr;
293 	int shmflg;
294 };
295 #endif
296 
297 /*
298  * MPSAFE
299  */
300 int
301 shmat(td, uap)
302 	struct thread *td;
303 	struct shmat_args *uap;
304 {
305 	struct proc *p = td->td_proc;
306 	int i, flags;
307 	struct shmid_ds *shmseg;
308 	struct shmmap_state *shmmap_s = NULL;
309 	struct shm_handle *shm_handle;
310 	vm_offset_t attach_va;
311 	vm_prot_t prot;
312 	vm_size_t size;
313 	int rv;
314 	int error = 0;
315 
316 	mtx_lock(&Giant);
317 	if (!jail_sysvipc_allowed && jailed(p->p_ucred)) {
318 		error = ENOSYS;
319 		goto done2;
320 	}
321 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
322 	if (shmmap_s == NULL) {
323 		size = shminfo.shmseg * sizeof(struct shmmap_state);
324 		shmmap_s = malloc(size, M_SHM, M_WAITOK);
325 		for (i = 0; i < shminfo.shmseg; i++)
326 			shmmap_s[i].shmid = -1;
327 		p->p_vmspace->vm_shm = (caddr_t)shmmap_s;
328 	}
329 	shmseg = shm_find_segment_by_shmid(uap->shmid);
330 	if (shmseg == NULL) {
331 		error = EINVAL;
332 		goto done2;
333 	}
334 	error = ipcperm(td, &shmseg->shm_perm,
335 	    (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
336 	if (error)
337 		goto done2;
338 	for (i = 0; i < shminfo.shmseg; i++) {
339 		if (shmmap_s->shmid == -1)
340 			break;
341 		shmmap_s++;
342 	}
343 	if (i >= shminfo.shmseg) {
344 		error = EMFILE;
345 		goto done2;
346 	}
347 	size = round_page(shmseg->shm_segsz);
348 #ifdef VM_PROT_READ_IS_EXEC
349 	prot = VM_PROT_READ | VM_PROT_EXECUTE;
350 #else
351 	prot = VM_PROT_READ;
352 #endif
353 	if ((uap->shmflg & SHM_RDONLY) == 0)
354 		prot |= VM_PROT_WRITE;
355 	flags = MAP_ANON | MAP_SHARED;
356 	if (uap->shmaddr) {
357 		flags |= MAP_FIXED;
358 		if (uap->shmflg & SHM_RND) {
359 			attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1);
360 		} else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0) {
361 			attach_va = (vm_offset_t)uap->shmaddr;
362 		} else {
363 			error = EINVAL;
364 			goto done2;
365 		}
366 	} else {
367 		/*
368 		 * This is just a hint to vm_map_find() about where to
369 		 * put it.
370 		 */
371 		attach_va = round_page((vm_offset_t)p->p_vmspace->vm_taddr
372 		    + maxtsiz + maxdsiz);
373 	}
374 
375 	shm_handle = shmseg->shm_internal;
376 	vm_object_reference(shm_handle->shm_object);
377 	rv = vm_map_find(&p->p_vmspace->vm_map, shm_handle->shm_object,
378 		0, &attach_va, size, (flags & MAP_FIXED)?0:1, prot, prot, 0);
379 	if (rv != KERN_SUCCESS) {
380 		error = ENOMEM;
381 		goto done2;
382 	}
383 	vm_map_inherit(&p->p_vmspace->vm_map,
384 		attach_va, attach_va + size, VM_INHERIT_SHARE);
385 
386 	shmmap_s->va = attach_va;
387 	shmmap_s->shmid = uap->shmid;
388 	shmseg->shm_lpid = p->p_pid;
389 	shmseg->shm_atime = time_second;
390 	shmseg->shm_nattch++;
391 	td->td_retval[0] = attach_va;
392 done2:
393 	mtx_unlock(&Giant);
394 	return (error);
395 }
396 
397 struct oshmid_ds {
398 	struct	ipc_perm shm_perm;	/* operation perms */
399 	int	shm_segsz;		/* size of segment (bytes) */
400 	ushort	shm_cpid;		/* pid, creator */
401 	ushort	shm_lpid;		/* pid, last operation */
402 	short	shm_nattch;		/* no. of current attaches */
403 	time_t	shm_atime;		/* last attach time */
404 	time_t	shm_dtime;		/* last detach time */
405 	time_t	shm_ctime;		/* last change time */
406 	void	*shm_handle;		/* internal handle for shm segment */
407 };
408 
409 struct oshmctl_args {
410 	int shmid;
411 	int cmd;
412 	struct oshmid_ds *ubuf;
413 };
414 
415 /*
416  * MPSAFE
417  */
418 static int
419 oshmctl(td, uap)
420 	struct thread *td;
421 	struct oshmctl_args *uap;
422 {
423 #ifdef COMPAT_43
424 	int error = 0;
425 	struct shmid_ds *shmseg;
426 	struct oshmid_ds outbuf;
427 
428 	mtx_lock(&Giant);
429 	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
430 		error = ENOSYS;
431 		goto done2;
432 	}
433 	shmseg = shm_find_segment_by_shmid(uap->shmid);
434 	if (shmseg == NULL) {
435 		error = EINVAL;
436 		goto done2;
437 	}
438 	switch (uap->cmd) {
439 	case IPC_STAT:
440 		error = ipcperm(td, &shmseg->shm_perm, IPC_R);
441 		if (error)
442 			goto done2;
443 		outbuf.shm_perm = shmseg->shm_perm;
444 		outbuf.shm_segsz = shmseg->shm_segsz;
445 		outbuf.shm_cpid = shmseg->shm_cpid;
446 		outbuf.shm_lpid = shmseg->shm_lpid;
447 		outbuf.shm_nattch = shmseg->shm_nattch;
448 		outbuf.shm_atime = shmseg->shm_atime;
449 		outbuf.shm_dtime = shmseg->shm_dtime;
450 		outbuf.shm_ctime = shmseg->shm_ctime;
451 		outbuf.shm_handle = shmseg->shm_internal;
452 		error = copyout((caddr_t)&outbuf, uap->ubuf, sizeof(outbuf));
453 		if (error)
454 			goto done2;
455 		break;
456 	default:
457 		/* XXX casting to (sy_call_t *) is bogus, as usual. */
458 		error = ((sy_call_t *)shmctl)(td, uap);
459 		break;
460 	}
461 done2:
462 	mtx_unlock(&Giant);
463 	return (error);
464 #else
465 	return EINVAL;
466 #endif
467 }
468 
469 #ifndef _SYS_SYSPROTO_H_
470 struct shmctl_args {
471 	int shmid;
472 	int cmd;
473 	struct shmid_ds *buf;
474 };
475 #endif
476 
477 /*
478  * MPSAFE
479  */
480 int
481 shmctl(td, uap)
482 	struct thread *td;
483 	struct shmctl_args *uap;
484 {
485 	int error = 0;
486 	struct shmid_ds inbuf;
487 	struct shmid_ds *shmseg;
488 
489 	mtx_lock(&Giant);
490 	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
491 		error = ENOSYS;
492 		goto done2;
493 	}
494 	switch (uap->cmd) {
495 	case IPC_INFO:
496 		error = copyout( (caddr_t)&shminfo, uap->buf, sizeof( shminfo ) );
497 		if (error)
498 			goto done2;
499 		td->td_retval[0] = shmalloced;
500 		goto done2;
501 	case SHM_INFO: {
502 		struct shm_info shm_info;
503 		shm_info.used_ids = shm_nused;
504 		shm_info.shm_rss = 0;	/*XXX where to get from ? */
505 		shm_info.shm_tot = 0;	/*XXX where to get from ? */
506 		shm_info.shm_swp = 0;	/*XXX where to get from ? */
507 		shm_info.swap_attempts = 0;	/*XXX where to get from ? */
508 		shm_info.swap_successes = 0;	/*XXX where to get from ? */
509 		error = copyout( (caddr_t)&shm_info, uap->buf, sizeof( shm_info ) );
510 		if (error)
511 			goto done2;
512 		td->td_retval[0] = shmalloced;
513 		goto done2;
514 	}
515 	}
516 	if( (uap->cmd) == SHM_STAT )
517 		shmseg = shm_find_segment_by_shmidx(uap->shmid);
518 	else
519 		shmseg = shm_find_segment_by_shmid(uap->shmid);
520 	if (shmseg == NULL) {
521 		error = EINVAL;
522 		goto done2;
523 	}
524 	switch (uap->cmd) {
525 	case SHM_STAT:
526 	case IPC_STAT:
527 		error = ipcperm(td, &shmseg->shm_perm, IPC_R);
528 		if (error)
529 			goto done2;
530 		error = copyout((caddr_t)shmseg, uap->buf, sizeof(inbuf));
531 		if (error)
532 			goto done2;
533 		else if( (uap->cmd) == SHM_STAT )
534 			td->td_retval[0] = IXSEQ_TO_IPCID( uap->shmid, shmseg->shm_perm );
535 		break;
536 	case IPC_SET:
537 		error = ipcperm(td, &shmseg->shm_perm, IPC_M);
538 		if (error)
539 			goto done2;
540 		error = copyin(uap->buf, (caddr_t)&inbuf, sizeof(inbuf));
541 		if (error)
542 			goto done2;
543 		shmseg->shm_perm.uid = inbuf.shm_perm.uid;
544 		shmseg->shm_perm.gid = inbuf.shm_perm.gid;
545 		shmseg->shm_perm.mode =
546 		    (shmseg->shm_perm.mode & ~ACCESSPERMS) |
547 		    (inbuf.shm_perm.mode & ACCESSPERMS);
548 		shmseg->shm_ctime = time_second;
549 		break;
550 	case IPC_RMID:
551 		error = ipcperm(td, &shmseg->shm_perm, IPC_M);
552 		if (error)
553 			goto done2;
554 		shmseg->shm_perm.key = IPC_PRIVATE;
555 		shmseg->shm_perm.mode |= SHMSEG_REMOVED;
556 		if (shmseg->shm_nattch <= 0) {
557 			shm_deallocate_segment(shmseg);
558 			shm_last_free = IPCID_TO_IX(uap->shmid);
559 		}
560 		break;
561 #if 0
562 	case SHM_LOCK:
563 	case SHM_UNLOCK:
564 #endif
565 	default:
566 		error = EINVAL;
567 		break;
568 	}
569 done2:
570 	mtx_unlock(&Giant);
571 	return (error);
572 }
573 
574 #ifndef _SYS_SYSPROTO_H_
575 struct shmget_args {
576 	key_t key;
577 	size_t size;
578 	int shmflg;
579 };
580 #endif
581 
582 static int
583 shmget_existing(td, uap, mode, segnum)
584 	struct thread *td;
585 	struct shmget_args *uap;
586 	int mode;
587 	int segnum;
588 {
589 	struct shmid_ds *shmseg;
590 	int error;
591 
592 	shmseg = &shmsegs[segnum];
593 	if (shmseg->shm_perm.mode & SHMSEG_REMOVED) {
594 		/*
595 		 * This segment is in the process of being allocated.  Wait
596 		 * until it's done, and look the key up again (in case the
597 		 * allocation failed or it was freed).
598 		 */
599 		shmseg->shm_perm.mode |= SHMSEG_WANTED;
600 		error = tsleep((caddr_t)shmseg, PLOCK | PCATCH, "shmget", 0);
601 		if (error)
602 			return error;
603 		return EAGAIN;
604 	}
605 	if ((uap->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL))
606 		return EEXIST;
607 	error = ipcperm(td, &shmseg->shm_perm, mode);
608 	if (error)
609 		return error;
610 	if (uap->size && uap->size > shmseg->shm_segsz)
611 		return EINVAL;
612 	td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
613 	return 0;
614 }
615 
616 static int
617 shmget_allocate_segment(td, uap, mode)
618 	struct thread *td;
619 	struct shmget_args *uap;
620 	int mode;
621 {
622 	int i, segnum, shmid, size;
623 	struct ucred *cred = td->td_proc->p_ucred;
624 	struct shmid_ds *shmseg;
625 	struct shm_handle *shm_handle;
626 
627 	GIANT_REQUIRED;
628 
629 	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
630 		return EINVAL;
631 	if (shm_nused >= shminfo.shmmni) /* Any shmids left? */
632 		return ENOSPC;
633 	size = round_page(uap->size);
634 	if (shm_committed + btoc(size) > shminfo.shmall)
635 		return ENOMEM;
636 	if (shm_last_free < 0) {
637 		shmrealloc();	/* Maybe expand the shmsegs[] array. */
638 		for (i = 0; i < shmalloced; i++)
639 			if (shmsegs[i].shm_perm.mode & SHMSEG_FREE)
640 				break;
641 		if (i == shmalloced)
642 			return ENOSPC;
643 		segnum = i;
644 	} else  {
645 		segnum = shm_last_free;
646 		shm_last_free = -1;
647 	}
648 	shmseg = &shmsegs[segnum];
649 	/*
650 	 * In case we sleep in malloc(), mark the segment present but deleted
651 	 * so that noone else tries to create the same key.
652 	 */
653 	shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
654 	shmseg->shm_perm.key = uap->key;
655 	shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff;
656 	shm_handle = (struct shm_handle *)
657 	    malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
658 	shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
659 
660 	/*
661 	 * We make sure that we have allocated a pager before we need
662 	 * to.
663 	 */
664 	if (shm_use_phys) {
665 		shm_handle->shm_object =
666 		    vm_pager_allocate(OBJT_PHYS, 0, size, VM_PROT_DEFAULT, 0);
667 	} else {
668 		shm_handle->shm_object =
669 		    vm_pager_allocate(OBJT_SWAP, 0, size, VM_PROT_DEFAULT, 0);
670 	}
671 	vm_object_clear_flag(shm_handle->shm_object, OBJ_ONEMAPPING);
672 	vm_object_set_flag(shm_handle->shm_object, OBJ_NOSPLIT);
673 
674 	shmseg->shm_internal = shm_handle;
675 	shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cr_uid;
676 	shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cr_gid;
677 	shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) |
678 	    (mode & ACCESSPERMS) | SHMSEG_ALLOCATED;
679 	shmseg->shm_segsz = uap->size;
680 	shmseg->shm_cpid = td->td_proc->p_pid;
681 	shmseg->shm_lpid = shmseg->shm_nattch = 0;
682 	shmseg->shm_atime = shmseg->shm_dtime = 0;
683 	shmseg->shm_ctime = time_second;
684 	shm_committed += btoc(size);
685 	shm_nused++;
686 	if (shmseg->shm_perm.mode & SHMSEG_WANTED) {
687 		/*
688 		 * Somebody else wanted this key while we were asleep.  Wake
689 		 * them up now.
690 		 */
691 		shmseg->shm_perm.mode &= ~SHMSEG_WANTED;
692 		wakeup((caddr_t)shmseg);
693 	}
694 	td->td_retval[0] = shmid;
695 	return 0;
696 }
697 
698 /*
699  * MPSAFE
700  */
701 int
702 shmget(td, uap)
703 	struct thread *td;
704 	struct shmget_args *uap;
705 {
706 	int segnum, mode;
707 	int error;
708 
709 	mtx_lock(&Giant);
710 	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
711 		error = ENOSYS;
712 		goto done2;
713 	}
714 	mode = uap->shmflg & ACCESSPERMS;
715 	if (uap->key != IPC_PRIVATE) {
716 	again:
717 		segnum = shm_find_segment_by_key(uap->key);
718 		if (segnum >= 0) {
719 			error = shmget_existing(td, uap, mode, segnum);
720 			if (error == EAGAIN)
721 				goto again;
722 			goto done2;
723 		}
724 		if ((uap->shmflg & IPC_CREAT) == 0) {
725 			error = ENOENT;
726 			goto done2;
727 		}
728 	}
729 	error = shmget_allocate_segment(td, uap, mode);
730 done2:
731 	mtx_unlock(&Giant);
732 	return (error);
733 }
734 
735 /*
736  * MPSAFE
737  */
738 int
739 shmsys(td, uap)
740 	struct thread *td;
741 	/* XXX actually varargs. */
742 	struct shmsys_args /* {
743 		u_int	which;
744 		int	a2;
745 		int	a3;
746 		int	a4;
747 	} */ *uap;
748 {
749 	int error;
750 
751 	mtx_lock(&Giant);
752 	if (!jail_sysvipc_allowed && jailed(td->td_proc->p_ucred)) {
753 		error = ENOSYS;
754 		goto done2;
755 	}
756 	if (uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0])) {
757 		error = EINVAL;
758 		goto done2;
759 	}
760 	error = (*shmcalls[uap->which])(td, &uap->a2);
761 done2:
762 	mtx_unlock(&Giant);
763 	return (error);
764 }
765 
766 static void
767 shmfork_myhook(p1, p2)
768 	struct proc *p1, *p2;
769 {
770 	struct shmmap_state *shmmap_s;
771 	size_t size;
772 	int i;
773 
774 	size = shminfo.shmseg * sizeof(struct shmmap_state);
775 	shmmap_s = malloc(size, M_SHM, M_WAITOK);
776 	bcopy((caddr_t)p1->p_vmspace->vm_shm, (caddr_t)shmmap_s, size);
777 	p2->p_vmspace->vm_shm = (caddr_t)shmmap_s;
778 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
779 		if (shmmap_s->shmid != -1)
780 			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
781 }
782 
783 static void
784 shmexit_myhook(p)
785 	struct proc *p;
786 {
787 	struct shmmap_state *shmmap_s;
788 	int i;
789 
790 	GIANT_REQUIRED;
791 
792 	shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
793 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
794 		if (shmmap_s->shmid != -1)
795 			shm_delete_mapping(p, shmmap_s);
796 	free((caddr_t)p->p_vmspace->vm_shm, M_SHM);
797 	p->p_vmspace->vm_shm = NULL;
798 }
799 
800 static void
801 shmrealloc(void)
802 {
803 	int i;
804 	struct shmid_ds *newsegs;
805 
806 	if (shmalloced >= shminfo.shmmni)
807 		return;
808 
809 	newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
810 	if (newsegs == NULL)
811 		return;
812 	for (i = 0; i < shmalloced; i++)
813 		bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
814 	for (; i < shminfo.shmmni; i++) {
815 		shmsegs[i].shm_perm.mode = SHMSEG_FREE;
816 		shmsegs[i].shm_perm.seq = 0;
817 	}
818 	free(shmsegs, M_SHM);
819 	shmsegs = newsegs;
820 	shmalloced = shminfo.shmmni;
821 }
822 
823 static void
824 shminit()
825 {
826 	int i;
827 
828 	TUNABLE_INT_FETCH("kern.ipc.shmmaxpgs", &shminfo.shmall);
829 	shminfo.shmmax = shminfo.shmall * PAGE_SIZE;
830 	TUNABLE_INT_FETCH("kern.ipc.shmmin", &shminfo.shmmin);
831 	TUNABLE_INT_FETCH("kern.ipc.shmmni", &shminfo.shmmni);
832 	TUNABLE_INT_FETCH("kern.ipc.shmseg", &shminfo.shmseg);
833 	TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
834 
835 	shmalloced = shminfo.shmmni;
836 	shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
837 	if (shmsegs == NULL)
838 		panic("cannot allocate initial memory for sysvshm");
839 	for (i = 0; i < shmalloced; i++) {
840 		shmsegs[i].shm_perm.mode = SHMSEG_FREE;
841 		shmsegs[i].shm_perm.seq = 0;
842 	}
843 	shm_last_free = 0;
844 	shm_nused = 0;
845 	shm_committed = 0;
846 	shmexit_hook = &shmexit_myhook;
847 	shmfork_hook = &shmfork_myhook;
848 }
849 
850 static int
851 shmunload()
852 {
853 
854 	if (shm_nused > 0)
855 		return (EBUSY);
856 
857 	free(shmsegs, M_SHM);
858 	shmexit_hook = NULL;
859 	shmfork_hook = NULL;
860 	return (0);
861 }
862 
863 static int
864 sysctl_shmsegs(SYSCTL_HANDLER_ARGS)
865 {
866 
867 	return (SYSCTL_OUT(req, shmsegs, shmalloced * sizeof(shmsegs[0])));
868 }
869 
870 static int
871 sysvshm_modload(struct module *module, int cmd, void *arg)
872 {
873 	int error = 0;
874 
875 	switch (cmd) {
876 	case MOD_LOAD:
877 		shminit();
878 		break;
879 	case MOD_UNLOAD:
880 		error = shmunload();
881 		break;
882 	case MOD_SHUTDOWN:
883 		break;
884 	default:
885 		error = EINVAL;
886 		break;
887 	}
888 	return (error);
889 }
890 
891 static moduledata_t sysvshm_mod = {
892 	"sysvshm",
893 	&sysvshm_modload,
894 	NULL
895 };
896 
897 SYSCALL_MODULE_HELPER(shmsys, 4);
898 SYSCALL_MODULE_HELPER(shmat, 3);
899 SYSCALL_MODULE_HELPER(shmctl, 3);
900 SYSCALL_MODULE_HELPER(shmdt, 1);
901 SYSCALL_MODULE_HELPER(shmget, 3);
902 
903 DECLARE_MODULE(sysvshm, sysvshm_mod,
904 	SI_SUB_SYSV_SHM, SI_ORDER_FIRST);
905 MODULE_VERSION(sysvshm, 1);
906