--- /tmp/tmp.3245.0	Fri Apr 13 17:52:38 2007
+++ src/sys/compat/freebsd32/freebsd32_misc.c	Fri Apr 13 17:50:13 2007
@@ -1507,7 +1507,7 @@
 		PTRIN_CP(u32.shmid_ds32, u.shmid_ds, shm_internal);
 	}
 	
-	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz);
+	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&u, &sz, -1);
 	if (error)
 		goto done;
 	
--- /tmp/tmp.3245.1	Fri Apr 13 17:52:39 2007
+++ src/sys/compat/linux/linux_ipc.c	Fri Apr 13 17:52:11 2007
@@ -698,20 +698,13 @@
 int
 linux_shmat(struct thread *td, struct linux_shmat_args *args)
 {
-    struct shmat_args /* {
-	int shmid;
-	void *shmaddr;
-	int shmflg;
-    } */ bsd_args;
     int error;
 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
     l_uintptr_t addr;
 #endif
 
-    bsd_args.shmid = args->shmid;
-    bsd_args.shmaddr = PTRIN(args->shmaddr);
-    bsd_args.shmflg = args->shmflg;
-    if ((error = shmat(td, &bsd_args)))
+    /* XXX: linux always sets shm_find_segment_by_shmid */
+    if ((error = kern_shmat(td, args->shmid, PTRIN(args->shmaddr), args->shmflg, 1)))
 	return error;
 #if defined(__i386__) || (defined(__amd64__) && defined(COMPAT_LINUX32))
     addr = td->td_retval[0];
@@ -764,7 +757,7 @@
 
 	    /* Perform shmctl wanting removed segments lookup */
 	    error = kern_shmctl(td, args->shmid, IPC_INFO,
-	        (void *)&bsd_shminfo, NULL);
+	        (void *)&bsd_shminfo, NULL, 1);
 	    if (error)
 		return error;
 	
@@ -779,7 +772,7 @@
 
 	    /* Perform shmctl wanting removed segments lookup */
 	    error = kern_shmctl(td, args->shmid, SHM_INFO,
-	        (void *)&bsd_shm_info, NULL);
+	        (void *)&bsd_shm_info, NULL, 1);
 	    if (error)
 		return error;
 
@@ -792,7 +785,7 @@
 	case LINUX_IPC_STAT:
 	    /* Perform shmctl wanting removed segments lookup */
 	    error = kern_shmctl(td, args->shmid, IPC_STAT,
-	        (void *)&bsd_shmid, NULL);
+	        (void *)&bsd_shmid, NULL, 1);
 	    if (error)
 		return error;
 		
@@ -804,7 +797,7 @@
     case LINUX_SHM_STAT:
 	/* Perform shmctl wanting removed segments lookup */
 	error = kern_shmctl(td, args->shmid, IPC_STAT,
-	    (void *)&bsd_shmid, NULL);
+	    (void *)&bsd_shmid, NULL, 1);
 	if (error)
 		return error;
 		
@@ -823,7 +816,7 @@
 
 	/* Perform shmctl wanting removed segments lookup */
 	return kern_shmctl(td, args->shmid, IPC_SET,
-	    (void *)&bsd_shmid, NULL);
+	    (void *)&bsd_shmid, NULL, 1);
 
     case LINUX_IPC_RMID: {
 	void *buf;
@@ -838,7 +831,7 @@
 		linux_to_bsd_shmid_ds(&linux_shmid, &bsd_shmid);
 		buf = (void *)&bsd_shmid;
 	}
-	return kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL);
+	return kern_shmctl(td, args->shmid, IPC_RMID, buf, NULL, 1);
     }
 
     case LINUX_SHM_LOCK:
--- /tmp/tmp.3245.2	Fri Apr 13 17:52:39 2007
+++ src/sys/compat/svr4/svr4_ipc.c	Fri Apr 13 17:50:36 2007
@@ -690,7 +690,7 @@
 		return (EINVAL);
 	}
 		
-	error = kern_shmctl(td, uap->shmid, cmd, &bs, &bufsize);
+	error = kern_shmctl(td, uap->shmid, cmd, &bs, &bufsize, -1);
 	if (error)
 		return (error);
 
--- /tmp/tmp.3245.3	Fri Apr 13 17:52:39 2007
+++ src/sys/i386/ibcs2/ibcs2_ipc.c	Fri Apr 13 17:51:16 2007
@@ -476,7 +476,7 @@
 
 	switch(uap->cmd) {
 	case IBCS2_IPC_STAT:
-		error = kern_shmctl(td, uap->shmid, IPC_STAT, &bs, NULL);
+		error = kern_shmctl(td, uap->shmid, IPC_STAT, &bs, NULL, -1);
 		if (error)
 			return (error);
 		cvt_shmid2ishmid(&bs, &is);
@@ -487,7 +487,7 @@
 		if (error)
 			return (error);
 		cvt_ishmid2shmid(&is, &bs);
-		return (kern_shmctl(td, uap->shmid, IPC_SET, &bs, NULL));
+		return kern_shmctl(td, uap->shmid, IPC_SET, &bs, NULL, -1);
 
 	case IPC_INFO:
 	case SHM_INFO:
@@ -496,7 +496,7 @@
 		return (EINVAL);
 	}
 
-	return (kern_shmctl(td, uap->shmid, uap->cmd, NULL, NULL));
+	return kern_shmctl(td, uap->shmid, uap->cmd, NULL, NULL, -1);
 }
 
 struct ibcs2_shmdt_args {
--- /tmp/tmp.3245.4	Fri Apr 13 17:52:39 2007
+++ src/sys/kern/sysv_shm.c	Fri Apr 13 17:47:36 2007
@@ -131,8 +131,8 @@
 
 static void shm_deallocate_segment(struct shmid_kernel *);
 static int shm_find_segment_by_key(key_t);
-static struct shmid_kernel *shm_find_segment_by_shmid(int);
-static struct shmid_kernel *shm_find_segment_by_shmidx(int);
+static struct shmid_kernel *shm_find_segment_by_shmid(int, int);
+static struct shmid_kernel *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);
@@ -208,17 +208,23 @@
 }
 
 static struct shmid_kernel *
-shm_find_segment_by_shmid(int shmid)
+shm_find_segment_by_shmid(int shmid, int allow_removed)
 {
 	int segnum;
 	struct shmid_kernel *shmseg;
+	int shm_allow_removed1;
 
 	segnum = IPCID_TO_IX(shmid);
 	if (segnum < 0 || segnum >= shmalloced)
 		return (NULL);
 	shmseg = &shmsegs[segnum];
+
+	if (allow_removed == -1)
+		shm_allow_removed1 = shm_allow_removed;
+	else
+		shm_allow_removed1 = allow_removed;
 	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
-	    (!shm_allow_removed &&
+	    (!shm_allow_removed1 &&
 	     (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
 	    shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid))
 		return (NULL);
@@ -226,15 +232,20 @@
 }
 
 static struct shmid_kernel *
-shm_find_segment_by_shmidx(int segnum)
+shm_find_segment_by_shmidx(int segnum, int allow_removed)
 {
 	struct shmid_kernel *shmseg;
+	int shm_allow_removed1;
 
 	if (segnum < 0 || segnum >= shmalloced)
 		return (NULL);
 	shmseg = &shmsegs[segnum];
+	if (allow_removed == -1)
+		shm_allow_removed1 = shm_allow_removed;
+	else
+		shm_allow_removed1 = allow_removed;
 	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
-	    (!shm_allow_removed &&
+	    (!shm_allow_removed1 &&
 	     (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0))
 		return (NULL);
 	return (shmseg);
@@ -340,11 +351,12 @@
 };
 #endif
 int
-kern_shmat(td, shmid, shmaddr, shmflg)
+kern_shmat(td, shmid, shmaddr, shmflg, allow_removed)
 	struct thread *td;
 	int shmid;
 	const void *shmaddr;
 	int shmflg;
+	int allow_removed;
 {
 	struct proc *p = td->td_proc;
 	int i, flags;
@@ -367,7 +379,7 @@
 			shmmap_s[i].shmid = -1;
 		p->p_vmspace->vm_shm = shmmap_s;
 	}
-	shmseg = shm_find_segment_by_shmid(shmid);
+	shmseg = shm_find_segment_by_shmid(shmid, allow_removed);
 	if (shmseg == NULL) {
 		error = EINVAL;
 		goto done2;
@@ -447,7 +459,7 @@
 	struct thread *td;
 	struct shmat_args *uap;
 {
-	return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg);
+	return kern_shmat(td, uap->shmid, uap->shmaddr, uap->shmflg, -1);
 }
 
 #if defined(__i386__) && (defined(COMPAT_FREEBSD4) || defined(COMPAT_43))
@@ -481,7 +493,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, -1);
 	if (shmseg == NULL) {
 		error = EINVAL;
 		goto done2;
@@ -530,12 +542,13 @@
 };
 #endif
 int
-kern_shmctl(td, shmid, cmd, buf, bufsz)
+kern_shmctl(td, shmid, cmd, buf, bufsz, allow_removed)
 	struct thread *td;
 	int shmid;
 	int cmd;
 	void *buf;
 	size_t *bufsz;
+	int allow_removed;
 {
 	int error = 0;
 	struct shmid_kernel *shmseg;
@@ -567,9 +580,9 @@
 	}
 	}
 	if (cmd == SHM_STAT)
-		shmseg = shm_find_segment_by_shmidx(shmid);
+		shmseg = shm_find_segment_by_shmidx(shmid, allow_removed);
 	else
-		shmseg = shm_find_segment_by_shmid(shmid);
+		shmseg = shm_find_segment_by_shmid(shmid, allow_removed);
 	if (shmseg == NULL) {
 		error = EINVAL;
 		goto done2;
@@ -645,7 +658,7 @@
 			goto done;
 	}
 	
-	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz);
+	error = kern_shmctl(td, uap->shmid, uap->cmd, (void *)&buf, &bufsz, -1);
 	if (error)
 		goto done;
 	
--- /tmp/tmp.3245.5	Fri Apr 13 17:52:39 2007
+++ src/sys/sys/syscallsubr.h	Fri Apr 13 17:40:19 2007
@@ -153,9 +153,9 @@
 int	kern_settimeofday(struct thread *td, struct timeval *tv,
 	    struct timezone *tzp);
 int	kern_shmat(struct thread *td, int shmid, const void *shmaddr,
-	    int shmflg);
+	    int shmflg, int allow_removed);
 int	kern_shmctl(struct thread *td, int shmid, int cmd, void *buf,
-	    size_t *bufsz);
+	    size_t *bufsz, int allow_removed);
 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);
