sysv_shm.c from Adam.
sysv_ipc.c from me. and various sundry changes to make sysv_ipc.c fit in. (somewhat untested and not very pleasant reading material)
This commit is contained in:
parent
d1584360d9
commit
2d7c7416dd
|
@ -1,102 +1,61 @@
|
|||
/*
|
||||
* Copyright (c) 1988 University of Utah.
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* Copyright (c) 1994 Herb Peyerl <hpeyerl@novatel.ca>
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* the Systems Programming Group of the University of Utah Computer
|
||||
* Science Department. Originally from University of Wisconsin.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* 2. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* from: Utah $Hdr: uipc_shm.c 1.9 89/08/14$
|
||||
*
|
||||
* from: @(#)sysv_shm.c 7.15 (Berkeley) 5/13/91
|
||||
* $Id: sysv_ipc.c,v 1.3 1994/05/12 00:54:58 cgd Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* IPC routines shared by some or all of the SYSV IPC system calls.
|
||||
*/
|
||||
|
||||
#ifndef SYSVIPC
|
||||
|
||||
#ifdef SYSVSHM
|
||||
#define SYSVIPC
|
||||
#endif
|
||||
|
||||
#ifdef SYSVSEM
|
||||
#define SYSVIPC
|
||||
#endif
|
||||
|
||||
#ifdef SYSVMSG
|
||||
#define SYSVIPC
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef SYSVIPC
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
/*
|
||||
* Perform access checking.
|
||||
* Check for ipc permission
|
||||
*/
|
||||
|
||||
ipcaccess(ipc, mode, cred)
|
||||
register struct ipc_perm *ipc;
|
||||
int
|
||||
ipcperm(uc, perm, mode)
|
||||
struct ucred *uc;
|
||||
struct ipc_perm *perm;
|
||||
int mode;
|
||||
register struct ucred *cred;
|
||||
{
|
||||
register int m;
|
||||
int i = 0;
|
||||
|
||||
if (cred->cr_uid == 0)
|
||||
if (uc->cr_uid == 0)
|
||||
return(0);
|
||||
|
||||
/*
|
||||
* Access check is based on only one of owner, group, public.
|
||||
* If not owner, then check group.
|
||||
* If not a member of the group, then check public access.
|
||||
* Does the user have permission?
|
||||
*/
|
||||
mode &= 0700;
|
||||
m = ipc->mode;
|
||||
if (cred->cr_uid != ipc->uid && cred->cr_uid != ipc->cuid) {
|
||||
m <<= 3;
|
||||
if (!groupmember(ipc->gid, cred) &&
|
||||
!groupmember(ipc->cgid, cred))
|
||||
m <<= 3;
|
||||
if (uc->cr_uid != perm->cuid && uc->cr_uid != perm->uid) {
|
||||
i = 3;
|
||||
/*
|
||||
* Does the group have permission?
|
||||
*/
|
||||
if (!groupmember(perm->gid, uc) && !groupmember(perm->cgid, uc))
|
||||
i += 3;
|
||||
}
|
||||
if ((mode&m) == mode)
|
||||
return (0);
|
||||
return (EACCES);
|
||||
|
||||
if (((mode&0700) & (perm->mode << i)) != mode)
|
||||
return(EACCES);
|
||||
}
|
||||
#endif /* SYSVSHM */
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
*
|
||||
* This software is provided ``AS IS'' without any warranties of any kind.
|
||||
*
|
||||
* $Id: sysv_msg.c,v 1.5 1994/02/15 13:35:53 mycroft Exp $
|
||||
* $Id: sysv_msg.c,v 1.6 1994/05/25 02:14:33 hpeyerl Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -257,7 +257,7 @@ msgctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case IPC_STAT:
|
||||
if ((eval = ipcaccess(&msqptr->msg_perm, IPC_R, cred))) {
|
||||
if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
|
||||
#ifdef MSG_DEBUG_OK
|
||||
printf("requester doesn't have read access\n");
|
||||
#endif
|
||||
|
@ -317,8 +317,7 @@ msgget(p, uap, retval)
|
|||
#endif
|
||||
return(EEXIST);
|
||||
}
|
||||
if ((eval = ipcaccess(&msqptr->msg_perm, msgflg & 0700,
|
||||
cred))) {
|
||||
if ((eval = ipcperm(cred, &msqptr->msg_perm, msgflg & 0700 ))) {
|
||||
#ifdef MSG_DEBUG_OK
|
||||
printf("requester doesn't have 0%o access\n",
|
||||
msgflg & 0700);
|
||||
|
@ -437,7 +436,7 @@ msgsnd(p, uap, retval)
|
|||
return(EINVAL);
|
||||
}
|
||||
|
||||
if ((eval = ipcaccess(&msqptr->msg_perm, IPC_W, cred))) {
|
||||
if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_W))) {
|
||||
#ifdef MSG_DEBUG_OK
|
||||
printf("requester doesn't have write access\n");
|
||||
#endif
|
||||
|
@ -774,7 +773,7 @@ msgrcv(p, uap, retval)
|
|||
return(EINVAL);
|
||||
}
|
||||
|
||||
if ((eval = ipcaccess(&msqptr->msg_perm, IPC_R, cred))) {
|
||||
if ((eval = ipcperm(cred, &msqptr->msg_perm, IPC_R))) {
|
||||
#ifdef MSG_DEBUG_OK
|
||||
printf("requester doesn't have read access\n");
|
||||
#endif
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* This software is provided ``AS IS'' without any warranties of any kind.
|
||||
*
|
||||
* $Id: sysv_sem.c,v 1.6 1994/02/13 11:31:16 mycroft Exp $
|
||||
* $Id: sysv_sem.c,v 1.7 1994/05/25 02:14:29 hpeyerl Exp $
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
|
@ -361,7 +361,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case IPC_STAT:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
|
||||
return(eval);
|
||||
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
|
||||
return(eval);
|
||||
|
@ -370,7 +370,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case GETNCNT:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
|
||||
return(eval);
|
||||
if (semnum < 0 || semnum >= semaptr->sem_nsems)
|
||||
return(EINVAL);
|
||||
|
@ -378,7 +378,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case GETPID:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
|
||||
return(eval);
|
||||
if (semnum < 0 || semnum >= semaptr->sem_nsems)
|
||||
return(EINVAL);
|
||||
|
@ -386,7 +386,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case GETVAL:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
|
||||
return(eval);
|
||||
if (semnum < 0 || semnum >= semaptr->sem_nsems)
|
||||
return(EINVAL);
|
||||
|
@ -394,7 +394,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case GETALL:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
|
||||
return(eval);
|
||||
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
|
||||
return(eval);
|
||||
|
@ -407,7 +407,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case GETZCNT:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_R, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_R)))
|
||||
return(eval);
|
||||
if (semnum < 0 || semnum >= semaptr->sem_nsems)
|
||||
return(EINVAL);
|
||||
|
@ -415,7 +415,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case SETVAL:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
|
||||
return(eval);
|
||||
if (semnum < 0 || semnum >= semaptr->sem_nsems)
|
||||
return(EINVAL);
|
||||
|
@ -427,7 +427,7 @@ semctl(p, uap, retval)
|
|||
break;
|
||||
|
||||
case SETALL:
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred)))
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W)))
|
||||
return(eval);
|
||||
if ((eval = copyin(arg, &real_arg, sizeof(real_arg))) != 0)
|
||||
return(eval);
|
||||
|
@ -483,8 +483,8 @@ semget(p, uap, retval)
|
|||
#ifdef SEM_DEBUG
|
||||
printf("found public key\n");
|
||||
#endif
|
||||
if ((eval = ipcaccess(&sema[semid].sem_perm,
|
||||
semflg & 0700, cred)))
|
||||
if ((eval = ipcperm(cred, &sema[semid].sem_perm,
|
||||
semflg & 0700)))
|
||||
return(eval);
|
||||
if (nsems > 0 && sema[semid].sem_nsems < nsems) {
|
||||
#ifdef SEM_DEBUG
|
||||
|
@ -602,7 +602,7 @@ semop(p, uap, retval)
|
|||
if (semaptr->sem_perm.seq != IPCID_TO_SEQ(uap->semid))
|
||||
return(EINVAL);
|
||||
|
||||
if ((eval = ipcaccess(&semaptr->sem_perm, IPC_W, cred))) {
|
||||
if ((eval = ipcperm(cred, &semaptr->sem_perm, IPC_W))) {
|
||||
#ifdef SEM_DEBUG
|
||||
printf("eval = %d from ipaccess\n", eval);
|
||||
#endif
|
||||
|
|
|
@ -1 +1,534 @@
|
|||
revision 1.10 intentionally removed
|
||||
/*
|
||||
* Copyright (c) 1994 Adam Glass
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. The name of the Author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL Adam Glass BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* based on ..., ..., and ...
|
||||
* $Header: /cvsroot/src/sys/kern/sysv_shm.c,v 1.11 1994/05/25 02:14:27 hpeyerl Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/systm.h>
|
||||
|
||||
#include <vm/vm.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_map.h>
|
||||
#include <vm/vm_kern.h>
|
||||
|
||||
/*
|
||||
* Provides the following externally accessible functions:
|
||||
*
|
||||
* shminit(void); initialization
|
||||
* shmexit(struct proc *) cleanup
|
||||
* shmfork(struct proc *, struct proc *, int) fork handling
|
||||
* shmsys(arg1, arg2, arg3, arg4); shm{at,ctl,dt,get}(arg2, arg3, arg4)
|
||||
*
|
||||
* Structures:
|
||||
* shmsegs (an array of 'struct shmid_ds')
|
||||
* per proc array of 'struct shmmap_state'
|
||||
*/
|
||||
|
||||
#define SHMSEG_FREE 0x200
|
||||
#define SHMSEG_REMOVED 0x400
|
||||
#define SHMSEG_ALLOCATED 0x800
|
||||
#define SHMSEG_INVALID (SHMSEG_FREE | SHMSEG_REMOVED)
|
||||
#define SHMSEG_PERM_MASK 0x1FF
|
||||
|
||||
vm_map_t sysvshm_map;
|
||||
int shm_last_free, shm_nused, shm_committed;
|
||||
|
||||
struct shmat_args {
|
||||
u_int shm_syscall;
|
||||
int shmid;
|
||||
void *shmaddr;
|
||||
int shmflg;
|
||||
};
|
||||
|
||||
struct shmctl_args {
|
||||
u_int shm_syscall;
|
||||
int shmid;
|
||||
int cmd;
|
||||
struct shmat_ds *ubuf;
|
||||
};
|
||||
|
||||
struct shmdt_args {
|
||||
u_int shm_syscall;
|
||||
int shmid;
|
||||
void *shmaddr;
|
||||
int shmflg;
|
||||
};
|
||||
|
||||
struct shmget_args {
|
||||
u_int shm_syscall;
|
||||
key_t key;
|
||||
size_t size;
|
||||
int shmflg;
|
||||
};
|
||||
|
||||
struct shmsys_args {
|
||||
u_int shm_syscall;
|
||||
};
|
||||
|
||||
struct shm_handle {
|
||||
vm_offset_t kva;
|
||||
};
|
||||
|
||||
struct shmmap_state {
|
||||
vm_offset_t va;
|
||||
int shmid;
|
||||
};
|
||||
|
||||
/* external intefaces */
|
||||
int shmsys __P((struct proc *, struct shmsys_args *, int *));
|
||||
void shminit __P((void));
|
||||
|
||||
/* internal functions */
|
||||
static int shmseg_alloc __P((struct proc *, key_t, size_t, int, int *));
|
||||
static int shmseg_find_key __P((key_t));
|
||||
static struct shmid_ds *shmseg_find_shmid __P((int, int *));
|
||||
static int shmget_existing __P((struct proc *, struct shmget_args *, int,
|
||||
int, int *));
|
||||
static int shmget __P((struct proc *, struct shmget_args *, int *));
|
||||
static int shmctl __P((struct proc *, struct shmctl_args *, int *));
|
||||
|
||||
static int shmseg_alloc(p, key, size, mode, retval)
|
||||
struct proc *p;
|
||||
key_t key;
|
||||
size_t size;
|
||||
int mode;
|
||||
int *retval;
|
||||
{
|
||||
int i, segnum, result, shmid;
|
||||
struct ucred *ucred = p->p_ucred;
|
||||
struct shmid_ds *shmseg;
|
||||
struct shm_handle *shm_handle;
|
||||
|
||||
if (shm_nused >= shminfo.shmmni) /* any shmids left? */
|
||||
return ENOSPC;
|
||||
if (shm_last_free < 0) {
|
||||
for (i=0; i < shminfo.shmmni; i++)
|
||||
if (shmsegs[i].shm_perm.mode & SHMSEG_FREE) break;
|
||||
if (i == shminfo.shmmni)
|
||||
panic("shmseg free count inconsistent");
|
||||
segnum = i;
|
||||
}
|
||||
else
|
||||
segnum = shm_last_free;
|
||||
shmseg = &shmsegs[segnum];
|
||||
shmseg->shm_perm.mode = SHMSEG_ALLOCATED;
|
||||
shm_handle = (struct shm_handle *)
|
||||
malloc(sizeof(struct shm_handle), M_SHM, M_WAITOK);
|
||||
shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
|
||||
result = vm_mmap(sysvshm_map, &shm_handle->kva,
|
||||
ctob(clrnd(btoc(size))), VM_PROT_ALL, VM_PROT_DEFAULT,
|
||||
MAP_ANON, shmid, 0);
|
||||
if (result != KERN_SUCCESS) {
|
||||
shmseg->shm_perm.mode = SHMSEG_FREE;
|
||||
free((caddr_t) shm_handle, M_SHM);
|
||||
return ENOMEM;
|
||||
}
|
||||
shmseg->shm_internal = shm_handle;
|
||||
shmseg->shm_perm.cuid = shmseg->shm_perm.uid =
|
||||
ucred->cr_uid;
|
||||
shmseg->shm_perm.cgid = shmseg->shm_perm.gid =
|
||||
ucred->cr_gid;
|
||||
shmseg->shm_perm.mode = mode;
|
||||
shmseg->shm_perm.seq = shmseg->shm_perm.seq + 1;
|
||||
shmseg->shm_perm.key = key;
|
||||
shmseg->shm_segsz = size;
|
||||
shmseg->shm_cpid = p->p_pid;
|
||||
shmseg->shm_lpid = shmseg->shm_nattch =
|
||||
shmseg->shm_atime = shmseg->shm_dtime = 0;
|
||||
shmseg->shm_ctime = time.tv_sec;
|
||||
shmseg->shm_internal = NULL; /* we aren't using this field */
|
||||
shm_committed += clrnd(btoc(size));
|
||||
shm_nused++;
|
||||
shm_last_free = -1;
|
||||
*retval = shmid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shmseg_find_key(key)
|
||||
key_t key;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0; i < shminfo.shmmni; i++) {
|
||||
if (shmsegs[i].shm_perm.mode & SHMSEG_INVALID) continue;
|
||||
if (shmsegs[i].shm_perm.key != key) continue;
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct shmid_ds *shmseg_find_shmid(shmid, where)
|
||||
int shmid;
|
||||
int *where;
|
||||
{
|
||||
int segnum;
|
||||
struct shmid_ds *shmseg;
|
||||
|
||||
segnum = IPCID_TO_IX(shmid);
|
||||
if (segnum >= shminfo.shmmni)
|
||||
return NULL;
|
||||
shmseg = &shmsegs[segnum];
|
||||
if ((shmseg->shm_perm.mode & (SHMSEG_FREE|SHMSEG_ALLOCATED)) ||
|
||||
(shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid)))
|
||||
return NULL;
|
||||
if (where)
|
||||
*where = segnum;
|
||||
return shmseg;
|
||||
}
|
||||
|
||||
static vm_offset_t shm_find_space(p, size)
|
||||
struct proc *p;
|
||||
size_t size;
|
||||
{
|
||||
vm_offset_t low_end, range, current;
|
||||
int result;
|
||||
|
||||
low_end = (vm_offset_t) p->p_vmspace->vm_daddr +
|
||||
NBPG * p->p_vmspace->vm_dsize;
|
||||
range = (USRSTACK - low_end);
|
||||
|
||||
/* current = range *3/4 + low_end */
|
||||
current = ((range&1)<<1 + range)>>2 + range>>1 + low_end;
|
||||
#if 0
|
||||
result = vm_map_find(&p->p_vmspace->vm_map, NULL, 0, ¤t, size,
|
||||
TRUE);
|
||||
if (result)
|
||||
return NULL;
|
||||
#endif
|
||||
return current;
|
||||
}
|
||||
|
||||
static int shmdt_seg(p, shmseg, shmmap_s)
|
||||
struct proc *p;
|
||||
struct shmid_ds *shmseg;
|
||||
struct shmmap_state *shmmap_s;
|
||||
{
|
||||
int result;
|
||||
size_t size;
|
||||
|
||||
size = ctob(clrnd(btoc(shmseg->shm_segsz)));
|
||||
result = vm_deallocate(&p->p_vmspace->vm_map, shmmap_s->va, size);
|
||||
if (result != KERN_SUCCESS)
|
||||
return EINVAL;
|
||||
shmseg->shm_nattch--;
|
||||
shmseg->shm_dtime = time.tv_sec;
|
||||
if ((shmseg->shm_nattch == 0) &&
|
||||
(shmseg->shm_perm.mode & SHMSEG_REMOVED)) {
|
||||
shmseg->shm_perm.mode = SHMSEG_FREE;
|
||||
shm_last_free = IPCID_TO_IX(shmmap_s->shmid);
|
||||
}
|
||||
shmmap_s->va = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shmdt(p, uap, retval)
|
||||
struct proc *p;
|
||||
struct shmdt_args *uap;
|
||||
int *retval;
|
||||
{
|
||||
int i;
|
||||
struct shmid_ds *shmseg;
|
||||
struct shmmap_state *shmmap_s;
|
||||
|
||||
if (p->p_vmspace->vm_shm == NULL)
|
||||
return EINVAL;
|
||||
shmseg = shmseg_find_shmid(uap->shmid, NULL);
|
||||
if (shmseg == NULL)
|
||||
return EINVAL;
|
||||
shmmap_s = (struct shmmap_state *) p->p_vmspace->vm_shm;
|
||||
for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
|
||||
if ((shmmap_s->va != (vm_offset_t) uap->shmaddr) ||
|
||||
(shmmap_s->shmid != uap->shmid)) continue;
|
||||
break;
|
||||
}
|
||||
if (i == shminfo.shmseg)
|
||||
return EINVAL;
|
||||
return shmdt_seg(p, shmseg, shmmap_s);
|
||||
}
|
||||
|
||||
static int shmat(p, uap, retval)
|
||||
struct proc *p;
|
||||
struct shmat_args *uap;
|
||||
int *retval;
|
||||
{
|
||||
int error, segnum, i, ipc_prot;
|
||||
struct ucred *ucred = p->p_ucred;
|
||||
struct shmid_ds *shmseg;
|
||||
struct shmmap_state *shmmap_s = NULL;
|
||||
vm_offset_t attach_va;
|
||||
vm_prot_t prot;
|
||||
vm_size_t size;
|
||||
|
||||
start:
|
||||
shmseg = shmseg_find_shmid(uap->shmid, NULL);
|
||||
if (shmseg == NULL)
|
||||
return EINVAL;
|
||||
if (error = ipcperm(ucred, &shmseg->shm_perm,
|
||||
((uap->shmflg & SHM_RDONLY) ? IPC_R :
|
||||
(IPC_R|IPC_W)))) return error;
|
||||
prot = VM_PROT_READ | ((uap->shmflg & SHM_RDONLY) ? 0 : VM_PROT_WRITE);
|
||||
if (p->p_vmspace->vm_shm == NULL) {
|
||||
shmmap_s = malloc(sizeof(struct shmmap_state)*shminfo.shmseg,
|
||||
M_SHM, M_WAITOK);
|
||||
bzero((caddr_t) shmmap_s, sizeof(struct shmmap_state) *
|
||||
shminfo.shmseg);
|
||||
p->p_vmspace->vm_shm = (caddr_t) shmmap_s;
|
||||
goto start; /* things may have changed if we slept */
|
||||
}
|
||||
if (shmmap_s == NULL) {
|
||||
shmmap_s = (struct shmmap_state *) p->p_vmspace->vm_shm;
|
||||
for (i = 0; i < shminfo.shmseg; i++) {
|
||||
if (shmmap_s->va == 0) break;
|
||||
shmmap_s++;
|
||||
}
|
||||
if (i == shminfo.shmseg)
|
||||
return EMFILE;
|
||||
}
|
||||
if (uap->shmaddr) {
|
||||
if (uap->shmflg & SHM_RND)
|
||||
attach_va = (vm_offset_t) uap->shmaddr -
|
||||
((vm_offset_t)uap->shmaddr % SHMLBA);
|
||||
else
|
||||
attach_va = (vm_offset_t) uap->shmaddr;
|
||||
}
|
||||
else attach_va = shm_find_space(p, shmseg->shm_segsz);
|
||||
if (attach_va == NULL)
|
||||
return ENOMEM;
|
||||
size = ctob(clrnd(btoc(shmseg->shm_segsz)));
|
||||
error = vm_mmap(&p->p_vmspace->vm_map, &attach_va, size,
|
||||
prot, VM_PROT_DEFAULT,
|
||||
MAP_ANON|MAP_SHARED|(uap->shmaddr ? MAP_FIXED : 0),
|
||||
uap->shmid, 0);
|
||||
if (error)
|
||||
return error;
|
||||
shmmap_s->shmid = uap->shmid;
|
||||
shmseg->shm_lpid = p->p_pid;
|
||||
shmseg->shm_atime = time.tv_sec;
|
||||
shmseg->shm_nattch++;
|
||||
*retval = shmmap_s->va = attach_va;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shmctl(p, uap, retval)
|
||||
struct proc *p;
|
||||
struct shmctl_args *uap;
|
||||
int *retval;
|
||||
{
|
||||
int error, segnum;
|
||||
struct ucred *ucred = p->p_ucred;
|
||||
struct shmid_ds inbuf;
|
||||
struct shmid_ds *shmseg;
|
||||
|
||||
shmseg = shmseg_find_shmid(uap->shmid, &segnum);
|
||||
if (shmseg == NULL)
|
||||
return EINVAL;
|
||||
switch (uap->cmd) {
|
||||
case IPC_STAT:
|
||||
if (error = ipcperm(ucred, &shmseg->shm_perm, IPC_R))
|
||||
return error;
|
||||
if (error = copyout((caddr_t) shmseg,
|
||||
uap->ubuf, sizeof(inbuf)))
|
||||
return error;
|
||||
break;
|
||||
case IPC_SET:
|
||||
if (ucred->cr_uid && (ucred->cr_uid != shmseg->shm_perm.uid) &&
|
||||
(ucred->cr_uid != shmseg->shm_perm.cuid))
|
||||
return EPERM;
|
||||
if (error = copyin((caddr_t) uap->ubuf, (caddr_t)&inbuf,
|
||||
sizeof(inbuf)))
|
||||
return error;
|
||||
shmseg->shm_perm.uid = inbuf.shm_perm.uid;
|
||||
shmseg->shm_perm.gid = inbuf.shm_perm.gid;
|
||||
shmseg->shm_perm.mode = inbuf.shm_perm.mode & SHMSEG_PERM_MASK;
|
||||
break;
|
||||
case IPC_RMID:
|
||||
if (ucred->cr_uid && (ucred->cr_uid != shmseg->shm_perm.uid) &&
|
||||
(ucred->cr_uid != shmseg->shm_perm.cuid))
|
||||
return EPERM;
|
||||
if (shmseg->shm_nattch)
|
||||
shmseg->shm_perm.mode |= SHMSEG_REMOVED;
|
||||
else {
|
||||
struct shm_handle *shm_handle = shmseg->shm_internal;
|
||||
|
||||
(void) vm_deallocate(sysvshm_map,
|
||||
shm_handle->kva,
|
||||
ctob(clrnd(btoc(shmseg->shm_segsz))));
|
||||
free((caddr_t) shm_handle, M_SHM);
|
||||
shmseg->shm_internal = NULL;
|
||||
shm_committed -= clrnd(btoc(shmseg->shm_segsz));
|
||||
free((caddr_t) shmseg->shm_internal, M_SHM);
|
||||
shmseg->shm_perm.mode = SHMSEG_FREE;
|
||||
shm_last_free = segnum;
|
||||
}
|
||||
break;
|
||||
#if 0
|
||||
case SHM_LOCK:
|
||||
case SHM_UNLOCK:
|
||||
#endif
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
shmseg->shm_ctime = time.tv_sec;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shmget_existing(p, uap, mode, segnum, retval)
|
||||
struct proc *p;
|
||||
struct shmget_args *uap;
|
||||
int mode;
|
||||
int segnum;
|
||||
int *retval;
|
||||
{
|
||||
int error;
|
||||
struct ucred *ucred = p->p_ucred;
|
||||
struct shmid_ds *shmseg;
|
||||
|
||||
shmseg = &shmsegs[segnum];
|
||||
if ((uap->shmflg & IPC_CREAT) || (uap->shmflg & IPC_EXCL)) /* XXX */
|
||||
return EEXIST;
|
||||
if (error = ipcperm(ucred, shmseg->shm_perm, mode))
|
||||
return error;
|
||||
if (uap->size && (uap->size > shmseg->shm_segsz))
|
||||
return EINVAL;
|
||||
*retval = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shmget(p, uap, retval)
|
||||
struct proc *p;
|
||||
struct shmget_args *uap;
|
||||
int *retval;
|
||||
{
|
||||
int segnum, mode, error;
|
||||
size_t size;
|
||||
struct shmid_ds *shmseg;
|
||||
|
||||
if ((uap->size < shminfo.shmmin) || (uap->size > shminfo.shmmax))
|
||||
return EINVAL;
|
||||
mode = uap->shmflg & SHMSEG_PERM_MASK;
|
||||
if (uap->key != IPC_PRIVATE) {
|
||||
segnum = shmseg_find_key(uap->key);
|
||||
if (segnum >=0)
|
||||
return shmget_existing(p, uap, mode, segnum, retval);
|
||||
}
|
||||
if ((uap->shmflg & IPC_CREAT) == 0)
|
||||
return ENOENT;
|
||||
size = clrnd(btoc(uap->size));
|
||||
if (size + shm_committed > shminfo.shmall)
|
||||
return ENOMEM;
|
||||
return shmseg_alloc(p, uap->key, uap->size, mode, retval);
|
||||
}
|
||||
|
||||
int shmsys(p, uap, retval)
|
||||
struct proc *p;
|
||||
struct shmsys_args *uap;
|
||||
int *retval;
|
||||
{
|
||||
int result;
|
||||
|
||||
/*
|
||||
* pass whole uap to avoid structure alignment problems
|
||||
*/
|
||||
|
||||
/* sub-syscall # not exported in any header file */
|
||||
switch(uap->shm_syscall) {
|
||||
case 0:
|
||||
result = shmat(p, (struct shmat_args *) uap, retval);
|
||||
break;
|
||||
case 1:
|
||||
result = shmctl(p, (struct shmctl_args *) uap, retval);
|
||||
break;
|
||||
case 2:
|
||||
result = shmdt(p, (struct shmdt_args *) uap, retval);
|
||||
break;
|
||||
case 3:
|
||||
result = shmget(p, (struct shmget_args *) uap, retval);
|
||||
break;
|
||||
default:
|
||||
result = EINVAL;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void shmfork(p1, p2, isvfork)
|
||||
struct proc *p1, *p2;
|
||||
int isvfork;
|
||||
{
|
||||
struct shmmap_state *shmmap_s;
|
||||
int i;
|
||||
|
||||
shmmap_s = malloc(sizeof(struct shmmap_state) * shminfo.shmseg,
|
||||
M_SHM, M_WAITOK);
|
||||
p2->p_vmspace->vm_shm = (caddr_t) shmmap_s;
|
||||
bcopy((caddr_t) p1->p_vmspace->vm_shm, (caddr_t) shmmap_s,
|
||||
sizeof(struct shmmap_state) * shminfo.shmseg);
|
||||
for (i=0; i < shminfo.shmseg; i++, shmmap_s++)
|
||||
if (shmmap_s->va != NULL)
|
||||
shmsegs[IPCID_TO_IX(shmmap_s->shmid)].shm_nattch++;
|
||||
}
|
||||
|
||||
void shmexit(p)
|
||||
struct proc *p;
|
||||
{
|
||||
int i;
|
||||
struct shmid_ds *shmseg;
|
||||
struct shmmap_state *shmmap_s;
|
||||
|
||||
shmmap_s = (struct shmmap_state *)p->p_vmspace->vm_shm;
|
||||
for (i=0; i < shminfo.shmseg; i++, shmmap_s++) {
|
||||
if (shmmap_s->va != 0) continue;
|
||||
shmseg = shmseg_find_shmid(shmmap_s->shmid, NULL);
|
||||
(void) shmdt_seg(p, shmseg, shmmap_s);
|
||||
}
|
||||
free(p->p_vmspace->vm_shm, M_SHM);
|
||||
p->p_vmspace->vm_shm = NULL;
|
||||
}
|
||||
|
||||
void shminit()
|
||||
{
|
||||
int i;
|
||||
vm_offset_t garbage1, garbage2;
|
||||
|
||||
/* actually this *should* be pageable. SHM_{LOCK,UNLOCK} */
|
||||
sysvshm_map = kmem_suballoc(kernel_map, &garbage1, &garbage2,
|
||||
shminfo.shmall * NBPG, FALSE);
|
||||
for (i = 0; i < shminfo.shmmni; i++) {
|
||||
shmsegs[i].shm_perm.mode = SHMSEG_FREE;
|
||||
shmsegs[i].shm_perm.seq = 0;
|
||||
}
|
||||
shm_last_free = 0;
|
||||
shm_nused = 0;
|
||||
shm_committed = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue