aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/sysv_shm.c
diff options
context:
space:
mode:
authorMartin Blapp <mbr@FreeBSD.org>2003-05-05 09:22:58 +0000
committerMartin Blapp <mbr@FreeBSD.org>2003-05-05 09:22:58 +0000
commitf130dcf22a358c27d9f031bb256c3e3d1fd68d98 (patch)
tree9ac126232eca288ee23257e5843e5279793d14e4 /sys/kern/sysv_shm.c
parent824eb9dc1b1fc2c3824c40156f9e05bea2d9190d (diff)
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
Notes
Notes: svn path=/head/; revision=114724
Diffstat (limited to 'sys/kern/sysv_shm.c')
-rw-r--r--sys/kern/sysv_shm.c150
1 files changed, 102 insertions, 48 deletions
diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c
index ec7033746579..3600ebe8bdca 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;