This patch changes the semantics of sysv shm emulation which is wrongly emulated under linux. The patch involves the following functions: - shmat - shmctl - shm_find_segment_by_shmid - shm_find_segment_by_shmidx - linux_shmat - linux_shmctl `shmat' and `shmctl' are now a wrapper for `shmat1' and `shmctl1'. The BSD semantic doesn't allow the usage of shared segment after being marked for removal through IPC_RMID. This patch adds a parameter to the functions shm{at,ctl}1 and shm_find_segment_by_shmid{x} that specifies if we want look up segments marked as removed, which appears to be the Linux semantic. Patch by: Orlando Bassotto diff -ru sys/compat/linux/linux_ipc.c sys/compat/linux/linux_ipc.c --- sys/compat/linux/linux_ipc.c Sat Mar 29 23:14:31 2003 +++ sys/compat/linux/linux_ipc.c Sat Mar 29 23:20:47 2003 @@ -662,7 +662,7 @@ bsd_args.shmid = args->shmid; bsd_args.shmaddr = args->shmaddr; bsd_args.shmflg = args->shmflg; - if ((error = shmat(td, &bsd_args))) + if ((error = shmat1(td, &bsd_args, 1))) return error; #ifdef __i386__ if ((error = copyout(td->td_retval, args->raddr, sizeof(l_ulong)))) @@ -718,7 +718,7 @@ 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))) + if ((error = shmctl1(td, &bsd_args, 1))) return error; bsd_to_linux_shminfo( (struct shminfo *)bsd_args.buf, &linux_shminfo ); return (linux_shminfo_pushdown(args->cmd & LINUX_IPC_64, @@ -728,7 +728,7 @@ 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))) + if ((error = shmctl1(td, &bsd_args, 1))) 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)); @@ -737,7 +737,7 @@ 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))) + if ((error = shmctl1(td, &bsd_args, 1))) return error; bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); return (linux_shmid_pushdown(args->cmd & LINUX_IPC_64, @@ -747,7 +747,7 @@ 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))) { + if ((error = shmctl1(td, &bsd_args, 1))) { return error; } bsd_to_linux_shmid_ds(bsd_args.buf, &linux_shmid); @@ -763,7 +763,7 @@ 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); + return shmctl1(td, &bsd_args, 1); case LINUX_IPC_RMID: bsd_args.shmid = args->shmid; @@ -778,7 +778,7 @@ bsd_args.buf = (struct shmid_ds*)stackgap_alloc(&sg, sizeof(struct shmid_ds)); linux_to_bsd_shmid_ds(&linux_shmid, bsd_args.buf); } - return shmctl(td, &bsd_args); + return shmctl1(td, &bsd_args, 1); case LINUX_SHM_LOCK: case LINUX_SHM_UNLOCK: Only in sys.patched.cvs/compat/linux: linux_ipc.c.2 diff -ru sys.cvs/kern/sysv_shm.c sys.patched.cvs/kern/sysv_shm.c --- sys/kern/sysv_shm.c Sat Mar 29 23:14:07 2003 +++ sys/kern/sysv_shm.c Sun Mar 30 04:09:08 2003 @@ -95,8 +95,8 @@ 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 +163,9 @@ } static struct shmid_ds * -shm_find_segment_by_shmid(shmid) +shm_find_segment_by_shmid(shmid, wantrem) int shmid; + int wantrem; { int segnum; struct shmid_ds *shmseg; @@ -173,23 +174,23 @@ 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 +294,10 @@ * MPSAFE */ int -shmat(td, uap) +shmat1(td, uap, wantrem) struct thread *td; struct shmat_args *uap; + int wantrem; { struct proc *p = td->td_proc; int i, flags; @@ -319,7 +321,7 @@ 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(uap->shmid, wantrem); if (shmseg == NULL) { error = EINVAL; goto done2; @@ -387,6 +389,14 @@ return (error); } +int +shmat(td, uap) + struct thread *td; + struct shmat_args *uap; +{ + return shmat1(td, uap, 0); +} + struct oshmid_ds { struct ipc_perm shm_perm; /* operation perms */ int shm_segsz; /* size of segment (bytes) */ @@ -421,7 +431,7 @@ 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,9 +479,10 @@ * MPSAFE */ int -shmctl(td, uap) +shmctl1(td, uap, wantrem) struct thread *td; struct shmctl_args *uap; + int wantrem; { int error = 0; struct shmid_ds inbuf; @@ -503,9 +514,9 @@ } } if( (uap->cmd) == SHM_STAT ) - shmseg = shm_find_segment_by_shmidx(uap->shmid); + shmseg = shm_find_segment_by_shmidx(uap->shmid, wantrem); else - shmseg = shm_find_segment_by_shmid(uap->shmid); + shmseg = shm_find_segment_by_shmid(uap->shmid, wantrem); if (shmseg == NULL) { error = EINVAL; goto done2; @@ -558,6 +569,14 @@ done2: mtx_unlock(&Giant); return (error); +} + +int +shmctl(td, uap) + struct thread *td; + struct shmctl_args *uap; +{ + return shmctl1(td, uap, 0); } #ifndef _SYS_SYSPROTO_H_ diff -ru sys.cvs/sys/sysproto.h sys.patched.cvs/sys/sysproto.h --- sys/sys/sysproto.h Sat Mar 29 23:13:36 2003 +++ sys/sys/sysproto.h Sat Mar 29 23:23:55 2003 @@ -1372,7 +1372,9 @@ int msgget(struct thread *, struct msgget_args *); int msgsnd(struct thread *, struct msgsnd_args *); int msgrcv(struct thread *, struct msgrcv_args *); +int shmat1(struct thread *, struct shmat_args *, int); int shmat(struct thread *, struct shmat_args *); +int shmctl1(struct thread *, struct shmctl_args *, int); int shmctl(struct thread *, struct shmctl_args *); int shmdt(struct thread *, struct shmdt_args *); int shmget(struct thread *, struct shmget_args *);