diff options
author | Martin Blapp <mbr@FreeBSD.org> | 2003-05-05 09:22:58 +0000 |
---|---|---|
committer | Martin Blapp <mbr@FreeBSD.org> | 2003-05-05 09:22:58 +0000 |
commit | f130dcf22a358c27d9f031bb256c3e3d1fd68d98 (patch) | |
tree | 9ac126232eca288ee23257e5843e5279793d14e4 /sys/kern/sysv_shm.c | |
parent | 824eb9dc1b1fc2c3824c40156f9e05bea2d9190d (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.c | 150 |
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; |