summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormbr <mbr@FreeBSD.org>2003-05-05 09:22:58 +0000
committermbr <mbr@FreeBSD.org>2003-05-05 09:22:58 +0000
commit98d5255d63c13a42c0aa2a18fa0b934016966057 (patch)
tree9ac126232eca288ee23257e5843e5279793d14e4
parentb958e56c35be663c8232acc9e8a75afaa2fa26a4 (diff)
downloadFreeBSD-src-98d5255d63c13a42c0aa2a18fa0b934016966057.zip
FreeBSD-src-98d5255d63c13a42c0aa2a18fa0b934016966057.tar.gz
Change the semantics of sysv shm emulation to take a additional
argument to the functions shm{at,ctl}1 and shm_find_segment_by_shmid{x}. The BSD semantics didn't allow the usage of shared segment after being marked for removal through IPC_RMID. The patch involves the following functions: - shmat - shmctl - shm_find_segment_by_shmid - shm_find_segment_by_shmidx - linux_shmat - linux_shmctl Submitted by: Orlando Bassotto <orlando.bassotto@ieo-research.it> Reviewed by: marcel
-rw-r--r--sys/compat/linux/linux_ipc.c133
-rw-r--r--sys/kern/sysv_shm.c150
-rw-r--r--sys/sys/syscallsubr.h4
3 files changed, 179 insertions, 108 deletions
diff --git a/sys/compat/linux/linux_ipc.c b/sys/compat/linux/linux_ipc.c
index 92fa13d..4f95277 100644
--- a/sys/compat/linux/linux_ipc.c
+++ b/sys/compat/linux/linux_ipc.c
@@ -30,6 +30,7 @@
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/syscallsubr.h>
#include <sys/sysproto.h>
#include <sys/proc.h>
#include <sys/limits.h>
@@ -703,81 +704,93 @@ linux_shmctl(struct thread *td, struct linux_shmctl_args *args)
struct l_shmid_ds linux_shmid;
struct l_shminfo linux_shminfo;
struct l_shm_info linux_shm_info;
- struct shmctl_args /* {
- int shmid;
- int cmd;
- struct shmid_ds *buf;
- } */ bsd_args;
+ struct shmid_ds bsd_shmid;
+ size_t bufsz;
int error;
- caddr_t sg = stackgap_init();
switch (args->cmd & ~LINUX_IPC_64) {
- case LINUX_IPC_INFO:
- bsd_args.shmid = args->shmid;
- bsd_args.cmd = IPC_INFO;
- bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shminfo));
- if ((error = shmctl(td, &bsd_args)))
+ case LINUX_IPC_INFO: {
+ struct shminfo bsd_shminfo;
+
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, IPC_INFO,
+ (void *)&bsd_shminfo, &bufsz, 1);
+ if (error)
return error;
- bsd_to_linux_shminfo( (struct shminfo *)bsd_args.buf, &linux_shminfo );
- return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
- &linux_shminfo, (caddr_t)args->buf));
-
- case LINUX_SHM_INFO:
- bsd_args.shmid = args->shmid;
- bsd_args.cmd = SHM_INFO;
- bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shm_info));
- if ((error = shmctl(td, &bsd_args)))
- return error;
- bsd_to_linux_shm_info( (struct shm_info *)bsd_args.buf, &linux_shm_info );
- return copyout(&linux_shm_info, (caddr_t)args->buf, sizeof(struct shm_info));
-
- case LINUX_IPC_STAT:
- bsd_args.shmid = args->shmid;
- bsd_args.cmd = IPC_STAT;
- bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
- if ((error = shmctl(td, &bsd_args)))
- return error;
- bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
- return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
- &linux_shmid, (caddr_t)args->buf));
+
+ bsd_to_linux_shminfo(&bsd_shminfo, &linux_shminfo);
- case LINUX_SHM_STAT:
- bsd_args.shmid = args->shmid;
- bsd_args.cmd = SHM_STAT;
- bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
- if ((error = shmctl(td, &bsd_args))) {
- return error;
+ return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_shminfo, (caddr_t)args->buf));
}
- bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid);
- return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
+
+ case LINUX_SHM_INFO: {
+ struct shm_info bsd_shm_info;
+
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, SHM_INFO,
+ (void *)&bsd_shm_info, &bufsz, 1);
+ if (error)
+ return error;
+
+ bsd_to_linux_shm_info(&bsd_shm_info, &linux_shm_info);
+
+ return copyout(&linux_shm_info, (caddr_t)args->buf,
+ sizeof(struct l_shm_info));
+ }
+
+ case LINUX_IPC_STAT:
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, IPC_STAT,
+ (void *)&bsd_shmid, &bufsz, 1);
+ if (error)
+ return error;
+
+ bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
+
+ return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
&linux_shmid, (caddr_t)args->buf));
+ case LINUX_SHM_STAT:
+ /* Perform shmctl wanting removed segments lookup */
+ error = kern_shmctl(td, args->shmid, IPC_STAT,
+ (void *)&bsd_shmid, &bufsz, 1);
+ if (error)
+ return error;
+
+ bsd_to_linux_shmid_ds(&bsd_shmid, &linux_shmid);
+
+ return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64,
+ &linux_shmid, (caddr_t)args->buf));
+
case LINUX_IPC_SET:
error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
&linux_shmid, (caddr_t)args->buf);
- if (error != 0)
- return error;
- bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
- linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
- bsd_args.shmid = args->shmid;
- bsd_args.cmd = IPC_SET;
- return shmctl(td, &bsd_args);
-
- case LINUX_IPC_RMID:
- bsd_args.shmid = args->shmid;
- bsd_args.cmd = IPC_RMID;
+ if (error)
+ return error;
+
+ linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
+
+ /* Perform shmctl wanting removed segments lookup */
+ return kern_shmctl(td, args->shmid, IPC_SET,
+ (void *)&bsd_shmid, &bufsz, 1);
+
+ case LINUX_IPC_RMID: {
+ void *buf;
+
if (args->buf == NULL)
- bsd_args.buf = NULL;
+ buf = NULL;
else {
- error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
- &linux_shmid, (caddr_t)args->buf);
- if (error != 0)
- return error;
- bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds));
- linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf);
+ error = linux_shmid_pullup(args->cmd & LINUX_IPC_64,
+ &linux_shmid, (caddr_t)args->buf);
+ if (error)
+ return error;
+ linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
+ buf = (void *)&bsd_shmid;
}
- return shmctl(td, &bsd_args);
+ return kern_shmctl(td, args->shmid, IPC_RMID, buf, &bufsz, 1);
+ }
case LINUX_SHM_LOCK:
case LINUX_SHM_UNLOCK:
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index ec70337..3600ebe 100644
--- a/sys/kern/sysv_shm.c
+++ b/sys/kern/sysv_shm.c
@@ -46,6 +46,7 @@
#include <sys/mutex.h>
#include <sys/stat.h>
#include <sys/syscall.h>
+#include <sys/syscallsubr.h>
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/jail.h>
@@ -95,8 +96,8 @@ struct shmmap_state {
static void shm_deallocate_segment(struct shmid_ds *);
static int shm_find_segment_by_key(key_t);
-static struct shmid_ds *shm_find_segment_by_shmid(int);
-static struct shmid_ds *shm_find_segment_by_shmidx(int);
+static struct shmid_ds *shm_find_segment_by_shmid(int, int);
+static struct shmid_ds *shm_find_segment_by_shmidx(int, int);
static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
static void shmrealloc(void);
static void shminit(void);
@@ -163,8 +164,7 @@ shm_find_segment_by_key(key)
}
static struct shmid_ds *
-shm_find_segment_by_shmid(shmid)
- int shmid;
+shm_find_segment_by_shmid(int shmid, int wantrem)
{
int segnum;
struct shmid_ds *shmseg;
@@ -173,23 +173,23 @@ shm_find_segment_by_shmid(shmid)
if (segnum < 0 || segnum >= shmalloced)
return (NULL);
shmseg = &shmsegs[segnum];
- if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
- != SHMSEG_ALLOCATED ||
+ if (!((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) ||
+ (wantrem && !(shmseg->shm_perm.mode & SHMSEG_REMOVED))) ||
shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid))
return (NULL);
return (shmseg);
}
static struct shmid_ds *
-shm_find_segment_by_shmidx(int segnum)
+shm_find_segment_by_shmidx(int segnum, int wantrem)
{
struct shmid_ds *shmseg;
if (segnum < 0 || segnum >= shmalloced)
return (NULL);
shmseg = &shmsegs[segnum];
- if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED))
- != SHMSEG_ALLOCATED )
+ if (!((shmseg->shm_perm.mode & SHMSEG_ALLOCATED) ||
+ (wantrem && !(shmseg->shm_perm.mode & SHMSEG_REMOVED))))
return (NULL);
return (shmseg);
}
@@ -293,9 +293,12 @@ struct shmat_args {
* MPSAFE
*/
int
-shmat(td, uap)
+kern_shmat(td, shmid, shmaddr, shmflg, wantrem)
struct thread *td;
- struct shmat_args *uap;
+ int shmid;
+ const void *shmaddr;
+ int shmflg;
+ int wantrem;
{
struct proc *p = td->td_proc;
int i, flags;
@@ -319,13 +322,13 @@ shmat(td, uap)
shmmap_s[i].shmid = -1;
p->p_vmspace->vm_shm = shmmap_s;
}
- shmseg = shm_find_segment_by_shmid(uap->shmid);
+ shmseg = shm_find_segment_by_shmid(shmid, wantrem);
if (shmseg == NULL) {
error = EINVAL;
goto done2;
}
error = ipcperm(td, &shmseg->shm_perm,
- (uap->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
+ (shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W);
if (error)
goto done2;
for (i = 0; i < shminfo.shmseg; i++) {
@@ -343,15 +346,15 @@ shmat(td, uap)
#else
prot = VM_PROT_READ;
#endif
- if ((uap->shmflg & SHM_RDONLY) == 0)
+ if ((shmflg & SHM_RDONLY) == 0)
prot |= VM_PROT_WRITE;
flags = MAP_ANON | MAP_SHARED;
- if (uap->shmaddr) {
+ if (shmaddr) {
flags |= MAP_FIXED;
- if (uap->shmflg & SHM_RND) {
- attach_va = (vm_offset_t)uap->shmaddr & ~(SHMLBA-1);
- } else if (((vm_offset_t)uap->shmaddr & (SHMLBA-1)) == 0) {
- attach_va = (vm_offset_t)uap->shmaddr;
+ if (shmflg & SHM_RND) {
+ attach_va = (vm_offset_t)shmaddr & ~(SHMLBA-1);
+ } else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) {
+ attach_va = (vm_offset_t)shmaddr;
} else {
error = EINVAL;
goto done2;
@@ -377,7 +380,7 @@ shmat(td, uap)
attach_va, attach_va + size, VM_INHERIT_SHARE);
shmmap_s->va = attach_va;
- shmmap_s->shmid = uap->shmid;
+ shmmap_s->shmid = shmid;
shmseg->shm_lpid = p->p_pid;
shmseg->shm_atime = time_second;
shmseg->shm_nattch++;
@@ -387,6 +390,14 @@ done2:
return (error);
}
+int
+shmat(td, uap)
+ struct thread *td;
+ struct shmat_args *uap;
+{
+ return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg, 0);
+}
+
struct oshmid_ds {
struct ipc_perm shm_perm; /* operation perms */
int shm_segsz; /* size of segment (bytes) */
@@ -421,7 +432,7 @@ oshmctl(td, uap)
if (!jail_sysvipc_allowed && jailed(td->td_ucred))
return (ENOSYS);
mtx_lock(&Giant);
- shmseg = shm_find_segment_by_shmid(uap->shmid);
+ shmseg = shm_find_segment_by_shmid(uap->shmid, 0);
if (shmseg == NULL) {
error = EINVAL;
goto done2;
@@ -469,22 +480,26 @@ struct shmctl_args {
* MPSAFE
*/
int
-shmctl(td, uap)
+kern_shmctl(td, shmid, cmd, buf, bufsz, wantrem)
struct thread *td;
- struct shmctl_args *uap;
+ int shmid;
+ int cmd;
+ void *buf;
+ size_t *bufsz;
+ int wantrem;
{
int error = 0;
- struct shmid_ds inbuf;
struct shmid_ds *shmseg;
if (!jail_sysvipc_allowed && jailed(td->td_ucred))
return (ENOSYS);
+
mtx_lock(&Giant);
- switch (uap->cmd) {
+ switch (cmd) {
case IPC_INFO:
- error = copyout(&shminfo, uap->buf, sizeof(shminfo));
- if (error)
- goto done2;
+ memcpy(buf, &shminfo, sizeof(shminfo));
+ if (bufsz)
+ *bufsz = sizeof(shminfo);
td->td_retval[0] = shmalloced;
goto done2;
case SHM_INFO: {
@@ -495,47 +510,48 @@ shmctl(td, uap)
shm_info.shm_swp = 0; /*XXX where to get from ? */
shm_info.swap_attempts = 0; /*XXX where to get from ? */
shm_info.swap_successes = 0; /*XXX where to get from ? */
- error = copyout(&shm_info, uap->buf, sizeof(shm_info));
- if (error)
- goto done2;
+ memcpy(buf, &shm_info, sizeof(shm_info));
+ if (bufsz)
+ *bufsz = sizeof(shm_info);
td->td_retval[0] = shmalloced;
goto done2;
}
}
- if( (uap->cmd) == SHM_STAT )
- shmseg = shm_find_segment_by_shmidx(uap->shmid);
+ if (cmd == SHM_STAT)
+ shmseg = shm_find_segment_by_shmidx(shmid, wantrem);
else
- shmseg = shm_find_segment_by_shmid(uap->shmid);
+ shmseg = shm_find_segment_by_shmid(shmid, wantrem);
if (shmseg == NULL) {
error = EINVAL;
goto done2;
}
- switch (uap->cmd) {
+ switch (cmd) {
case SHM_STAT:
case IPC_STAT:
error = ipcperm(td, &shmseg->shm_perm, IPC_R);
if (error)
goto done2;
- error = copyout(shmseg, uap->buf, sizeof(inbuf));
- if (error)
- goto done2;
- else if( (uap->cmd) == SHM_STAT )
- td->td_retval[0] = IXSEQ_TO_IPCID( uap->shmid, shmseg->shm_perm );
+ memcpy(buf, shmseg, sizeof(struct shmid_ds));
+ if (bufsz)
+ *bufsz = sizeof(struct shmid_ds);
+ if (cmd == SHM_STAT)
+ td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->shm_perm);
break;
- case IPC_SET:
+ case IPC_SET: {
+ struct shmid_ds *shmid;
+
+ shmid = (struct shmid_ds *)buf;
error = ipcperm(td, &shmseg->shm_perm, IPC_M);
if (error)
goto done2;
- error = copyin(uap->buf, &inbuf, sizeof(inbuf));
- if (error)
- goto done2;
- shmseg->shm_perm.uid = inbuf.shm_perm.uid;
- shmseg->shm_perm.gid = inbuf.shm_perm.gid;
+ shmseg->shm_perm.uid = shmid->shm_perm.uid;
+ shmseg->shm_perm.gid = shmid->shm_perm.gid;
shmseg->shm_perm.mode =
(shmseg->shm_perm.mode & ~ACCESSPERMS) |
- (inbuf.shm_perm.mode & ACCESSPERMS);
+ (shmid->shm_perm.mode & ACCESSPERMS);
shmseg->shm_ctime = time_second;
break;
+ }
case IPC_RMID:
error = ipcperm(td, &shmseg->shm_perm, IPC_M);
if (error)
@@ -544,7 +560,7 @@ shmctl(td, uap)
shmseg->shm_perm.mode |= SHMSEG_REMOVED;
if (shmseg->shm_nattch <= 0) {
shm_deallocate_segment(shmseg);
- shm_last_free = IPCID_TO_IX(uap->shmid);
+ shm_last_free = IPCID_TO_IX(shmid);
}
break;
#if 0
@@ -560,6 +576,44 @@ done2:
return (error);
}
+int
+shmctl(td, uap)
+ struct thread *td;
+ struct shmctl_args *uap;
+{
+ int error = 0;
+ struct shmid_ds buf;
+ size_t bufsz;
+
+ /* IPC_SET needs to copyin the buffer before calling kern_shmctl */
+ if (uap->cmd == IPC_SET) {
+ if ((error = copyin(uap->buf, &buf, sizeof(struct shmid_ds))))
+ goto done;
+ }
+
+ error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz, 0);
+ if (error)
+ goto done;
+
+ /* Cases in which we need to copyout */
+ switch (uap->cmd) {
+ case IPC_INFO:
+ case SHM_INFO:
+ case SHM_STAT:
+ case IPC_STAT:
+ error = copyout(&buf, uap->buf, bufsz);
+ break;
+ }
+
+done:
+ if (error) {
+ /* Invalidate the return value */
+ td->td_retval[0] = -1;
+ }
+ return (error);
+}
+
+
#ifndef _SYS_SYSPROTO_H_
struct shmget_args {
key_t key;
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index cac8091..9f1eb11 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -70,6 +70,10 @@ int kern_rename(struct thread *td, char *from, char *to,
int kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg);
int kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
fd_set *fd_ex, struct timeval *tvp);
+int kern_shmat(struct thread *td, int shmid, const void *shmaddr,
+ int shmflg, int wantrem);
+int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf,
+ size_t *bufsz, int wantrem);
int kern_sigaction(struct thread *td, int sig, struct sigaction *act,
struct sigaction *oact, int flags);
int kern_sigaltstack(struct thread *td, stack_t *ss, stack_t *oss);
OpenPOWER on IntegriCloud