--- /usr/src/sys/kern/sysv_shm.c	Sun Mar 25 03:26:07 2007
+++ s	Mon Apr 30 15:23:49 2007
@@ -1,3 +1,4 @@
+//depot/user/wkoszek/wkoszek_lessgiant/src/sys/kern/sysv_shm.c#3 - edit change 116478 (text+ko)
 /*	$NetBSD: sysv_shm.c,v 1.23 1994/07/04 23:25:12 glass Exp $	*/
 /*-
  * Copyright (c) 1994 Adam Glass and Charles Hannum.  All rights reserved.
@@ -72,6 +73,7 @@
 #include <sys/lock.h>
 #include <sys/sysctl.h>
 #include <sys/shm.h>
+#include <sys/sx.h>
 #include <sys/proc.h>
 #include <sys/malloc.h>
 #include <sys/mman.h>
@@ -123,6 +125,24 @@
 
 static int shm_last_free, shm_nused, shm_committed, shmalloced;
 static struct shmid_kernel	*shmsegs;
+static struct sx		 shm_sx;
+
+#define SHM_SX_XLOCK()		sx_xlock(&(shm_sx))
+#define SHM_SX_XUNLOCK()	sx_xunlock(&(shm_sx))
+#define SHM_SX_LOCK_INIT()	sx_init(&(shm_sx), "shm_mtx");
+#define SHM_SX_LOCK_DESTROY()	sx_destroy(&(shm_sx))
+#define SHM_SX_ASSERT(f)	sx_assert(&(shm_sx), (f))

Since you are going to just use xlock case, I would remove the f argument
by here, so as XLOCK. I would use instead something like:

#define	SHM_LOCK_INIT		sx_init(&shm_sx, "shm");
#define	SHM_LOCK_DESTROY	sx_destroy(&shm_sx);
#define	SHM_LOCK		sx_xlock(&shm_sx)
#define	SHM_UNLOCK		sx_xunlock(&shm_sx)

+static u_int	shm_debug = 0;
+
+#define SHM_DEBUG(...)	do {				\
+	if (shm_debug == 1) {				\
+		printf("%s(%d)", __func__, __LINE__);	\
+		printf(__VA_ARGS__);			\
+		printf("\n");				\
+	}						\
+} while (0)
+
 
 struct shmmap_state {
 	vm_offset_t va;
@@ -134,7 +154,6 @@
 static struct shmid_kernel *shm_find_segment_by_shmid(int);
 static struct shmid_kernel *shm_find_segment_by_shmidx(int);
 static int shm_delete_mapping(struct vmspace *vm, struct shmmap_state *);
-static void shmrealloc(void);
 static void shminit(void);
 static int sysvshm_modload(struct module *, int, void *);
 static int shmunload(void);
@@ -195,15 +214,17 @@
     "Current number of shared memory segments allocated");
 
 static int
-shm_find_segment_by_key(key)
-	key_t key;
+shm_find_segment_by_key(key_t key)
 {
+	struct ipc_perm *pm;
 	int i;
 
-	for (i = 0; i < shmalloced; i++)
-		if ((shmsegs[i].u.shm_perm.mode & SHMSEG_ALLOCATED) &&
-		    shmsegs[i].u.shm_perm.key == key)
+	SHM_SX_ASSERT(SX_LOCKED);
+	for (i = 0; i < shmalloced; i++) {
+		pm = &(shmsegs[i].u.shm_perm);
+		if (pm->mode & SHMSEG_ALLOCATED && pm->key == key)
 			return (i);
+	}
 	return (-1);
 }
 
@@ -213,15 +234,27 @@
 	int segnum;
 	struct shmid_kernel *shmseg;
 
+	SHM_SX_ASSERT(SX_LOCKED);
+
 	segnum = IPCID_TO_IX(shmid);
-	if (segnum < 0 || segnum >= shmalloced)
+	if (segnum < 0 || segnum >= shmalloced) {
+		SHM_DEBUG("segnum improper");
 		return (NULL);
+	}
 	shmseg = &shmsegs[segnum];
-	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
-	    (!shm_allow_removed &&
-	     (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) ||
-	    shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid))
+	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0) {
+		SHM_DEBUG("not allocated");
 		return (NULL);
+	}
+	if (!shm_allow_removed &&
+	    (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0) {
+		SHM_DEBUG("shseg_removed");
+		return (NULL);
+	}
+	if (shmseg->u.shm_perm.seq != IPCID_TO_SEQ(shmid)) {
+		SHM_DEBUG("shmseg == NULL");
+		return (NULL);
+	}
 	return (shmseg);
 }
 
@@ -229,14 +262,24 @@
 shm_find_segment_by_shmidx(int segnum)
 {
 	struct shmid_kernel *shmseg;
+	struct ipc_perm *pm;
+
+	SHM_SX_ASSERT(SX_LOCKED);
 
-	if (segnum < 0 || segnum >= shmalloced)
+	if (segnum < 0 || segnum >= shmalloced) {
+		SHM_DEBUG("segnum improper");
 		return (NULL);
+	}
 	shmseg = &shmsegs[segnum];
-	if ((shmseg->u.shm_perm.mode & SHMSEG_ALLOCATED) == 0 ||
-	    (!shm_allow_removed &&
-	     (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) != 0))
+	pm = &(shmseg->u.shm_perm);
+	if ((pm->mode & SHMSEG_ALLOCATED) == 0) {
+		SHM_DEBUG("segnum improper");
+		return (NULL);
+	}
+	if (!shm_allow_removed && (pm->mode & SHMSEG_REMOVED) != 0) {
+		SHM_DEBUG("segnum improper");
 		return (NULL);
+	}
 	return (shmseg);
 }
 
@@ -246,7 +289,7 @@
 {
 	size_t size;
 
-	GIANT_REQUIRED;
+	SHM_SX_ASSERT(SX_XLOCKED);
 
 	vm_object_deallocate(shmseg->u.shm_internal);
 	shmseg->u.shm_internal = NULL;
@@ -266,7 +309,7 @@
 	int segnum, result;
 	size_t size;
 
-	GIANT_REQUIRED;
+	SHM_SX_ASSERT(SX_XLOCKED);
 
 	segnum = IPCID_TO_IX(shmmap_s->shmid);
 	shmseg = &shmsegs[segnum];
@@ -304,12 +347,10 @@
 
 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
 		return (ENOSYS);
-	mtx_lock(&Giant);
 	shmmap_s = p->p_vmspace->vm_shm;
- 	if (shmmap_s == NULL) {
-		error = EINVAL;
-		goto done2;
-	}
+ 	if (shmmap_s == NULL)
+		return (EINVAL);
+	SHM_SX_XLOCK();
 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++) {
 		if (shmmap_s->shmid != -1 &&
 		    shmmap_s->va == (vm_offset_t)uap->shmaddr) {
@@ -317,18 +358,21 @@

I think that vm_shm should be under lock too. It is unprotected and
passible of races (example: shmdt() and shmat()).

 		}
 	}
 	if (i == shminfo.shmseg) {
-		error = EINVAL;
-		goto done2;
+		SHM_SX_XUNLOCK();
+		return (EINVAL);
 	}
 #ifdef MAC
 	shmsegptr = &shmsegs[IPCID_TO_IX(shmmap_s->shmid)];
 	error = mac_check_sysv_shmdt(td->td_ucred, shmsegptr);
-	if (error != 0)
-		goto done2;
+	if (error != 0) {
+		SHM_SX_XUNLOCK();
+		SHM_DEBUG("error = %d\n", error);
+		return (error);
+	}
 #endif
 	error = shm_delete_mapping(p->p_vmspace, shmmap_s);
-done2:
-	mtx_unlock(&Giant);
+	SHM_SX_XUNLOCK();
+	SHM_DEBUG("error = %d\n", error);
 	return (error);
 }
 
@@ -358,15 +402,17 @@
 
 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
 		return (ENOSYS);
-	mtx_lock(&Giant);
-	shmmap_s = p->p_vmspace->vm_shm;
-	if (shmmap_s == NULL) {
+	if (p->p_vmspace->vm_shm == NULL) {
 		size = shminfo.shmseg * sizeof(struct shmmap_state);
 		shmmap_s = malloc(size, M_SHM, M_WAITOK);
 		for (i = 0; i < shminfo.shmseg; i++)
 			shmmap_s[i].shmid = -1;
 		p->p_vmspace->vm_shm = shmmap_s;
+	} else {
+		shmmap_s = p->p_vmspace->vm_shm;
 	}
+	SHM_SX_XLOCK();
+	/* This should go first, really.. */
 	shmseg = shm_find_segment_by_shmid(shmid);
 	if (shmseg == NULL) {
 		error = EINVAL;
@@ -438,7 +484,8 @@
 	shmseg->u.shm_nattch++;
 	td->td_retval[0] = attach_va;
 done2:
-	mtx_unlock(&Giant);
+	SHM_SX_XUNLOCK();
+	SHM_DEBUG("error = %d\n", error);
 	return (error);
 }
 
@@ -480,14 +527,13 @@
 
 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
 		return (ENOSYS);
-	mtx_lock(&Giant);
+	SHM_SX_XLOCK();
 	shmseg = shm_find_segment_by_shmid(uap->shmid);
 	if (shmseg == NULL) {
 		error = EINVAL;
 		goto done2;
 	}
-	switch (uap->cmd) {
-	case IPC_STAT:
+	if (uap->cmd == IPC_STAT) {
 		error = ipcperm(td, &shmseg->u.shm_perm, IPC_R);
 		if (error)
 			goto done2;
@@ -505,16 +551,20 @@
 		outbuf.shm_dtime = shmseg->u.shm_dtime;
 		outbuf.shm_ctime = shmseg->u.shm_ctime;
 		outbuf.shm_handle = shmseg->u.shm_internal;
+		SHM_SX_XUNLOCK();
 		error = copyout(&outbuf, uap->ubuf, sizeof(outbuf));
+		SHM_SX_XLOCK();
 		if (error)
 			goto done2;

here you don't need to acquire the lock again.
The ideal would be that you remove the unlock just before the return.
You can handle missing unlock in the previous paths as you alredy did with
other parts of code: just do unlock and return/jmp.

-		break;
-	default:
+	} else {
+		SHM_SX_XUNLOCK();
 		error = shmctl(td, (struct shmctl_args *)uap);
-		break;
+		SHM_DEBUG("error = %d\n", error);
+		return (error);
 	}
 done2:
-	mtx_unlock(&Giant);
+	SHM_SX_XUNLOCK();
+	SHM_DEBUG("error = %d\n", error);
 	return (error);
 #else
 	return (EINVAL);
@@ -539,20 +589,23 @@
 {
 	int error = 0;
 	struct shmid_kernel *shmseg;
+	struct shm_info shm_info;
+	struct shmid_ds *shmobj;
 
 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
 		return (ENOSYS);
-
-	mtx_lock(&Giant);
 	switch (cmd) {
 	case IPC_INFO:
+		SHM_SX_XLOCK();
 		memcpy(buf, &shminfo, sizeof(shminfo));
+		SHM_SX_XUNLOCK();
 		if (bufsz)
 			*bufsz = sizeof(shminfo);
 		td->td_retval[0] = shmalloced;
-		goto done2;
-	case SHM_INFO: {
-		struct shm_info shm_info;
+		return (error);
+		/* NOT REACHED */
+		break;
+	case SHM_INFO:
 		shm_info.used_ids = shm_nused;
 		shm_info.shm_rss = 0;	/*XXX where to get from ? */
 		shm_info.shm_tot = 0;	/*XXX where to get from ? */
@@ -563,9 +616,11 @@
 		if (bufsz)
 			*bufsz = sizeof(shm_info);
 		td->td_retval[0] = shmalloced;
-		goto done2;
-	}
+		return (error);
+		/* NOT REACHED */
+		break;
 	}
+	SHM_SX_XLOCK();
 	if (cmd == SHM_STAT)
 		shmseg = shm_find_segment_by_shmidx(shmid);
 	else
@@ -591,25 +646,25 @@
 		if (cmd == SHM_STAT)
 			td->td_retval[0] = IXSEQ_TO_IPCID(shmid, shmseg->u.shm_perm);
 		break;
-	case IPC_SET: {
-		struct shmid_ds *shmid;
+	case IPC_SET:
 
-		shmid = (struct shmid_ds *)buf;
+		shmobj = (struct shmid_ds *)buf;
 		error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
 		if (error)
 			goto done2;
-		shmseg->u.shm_perm.uid = shmid->shm_perm.uid;
-		shmseg->u.shm_perm.gid = shmid->shm_perm.gid;
+		shmseg->u.shm_perm.uid = shmobj->shm_perm.uid;
+		shmseg->u.shm_perm.gid = shmobj->shm_perm.gid;
 		shmseg->u.shm_perm.mode =
 		    (shmseg->u.shm_perm.mode & ~ACCESSPERMS) |
-		    (shmid->shm_perm.mode & ACCESSPERMS);
+		    (shmobj->shm_perm.mode & ACCESSPERMS);
 		shmseg->u.shm_ctime = time_second;
 		break;
-	}
 	case IPC_RMID:
 		error = ipcperm(td, &shmseg->u.shm_perm, IPC_M);
-		if (error)
+		if (error) {
+			SHM_DEBUG("returning %d\n", error);
 			goto done2;
+		}
 		shmseg->u.shm_perm.key = IPC_PRIVATE;
 		shmseg->u.shm_perm.mode |= SHMSEG_REMOVED;
 		if (shmseg->u.shm_nattch <= 0) {
@@ -626,7 +681,8 @@
 		break;
 	}
 done2:
-	mtx_unlock(&Giant);
+	SHM_DEBUG("error = %d\n", error);
+	SHM_SX_XUNLOCK();

You could swap these 2 lines?

 	return (error);
 }
 
@@ -660,6 +716,7 @@
 	}
 
 done:
+	SHM_DEBUG("error = %d\n", error);
 	if (error) {
 		/* Invalidate the return value */
 		td->td_retval[0] = -1;
@@ -683,7 +740,9 @@
 	int segnum;
 {
 	struct shmid_kernel *shmseg;
-	int error;
+	int error = 0;
+
+	SHM_SX_ASSERT(SX_LOCKED);
 
 	shmseg = &shmsegs[segnum];
 	if (shmseg->u.shm_perm.mode & SHMSEG_REMOVED) {
@@ -703,12 +762,16 @@
 #ifdef MAC
 	error = mac_check_sysv_shmget(td->td_ucred, shmseg, uap->shmflg);
 	if (error != 0)
-		return (error);
+		goto done2;
 #endif
-	if (uap->size && uap->size > shmseg->u.shm_segsz)
-		return (EINVAL);
+	if (uap->size && uap->size > shmseg->u.shm_segsz) {
+		error = EINVAL;
+		goto done2;
+	}
 	td->td_retval[0] = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
-	return (0);
+done2:
+	SHM_DEBUG("error = %d\n", error);
+	return (error);
 }
 
 static int
@@ -722,7 +785,7 @@
 	struct shmid_kernel *shmseg;
 	vm_object_t shm_object;
 
-	GIANT_REQUIRED;
+	SHM_SX_ASSERT(SX_XLOCKED);
 
 	if (uap->size < shminfo.shmmin || uap->size > shminfo.shmmax)
 		return (EINVAL);
@@ -732,7 +795,6 @@
 	if (shm_committed + btoc(size) > shminfo.shmall)
 		return (ENOMEM);
 	if (shm_last_free < 0) {
-		shmrealloc();	/* Maybe expand the shmsegs[] array. */
 		for (i = 0; i < shmalloced; i++)
 			if (shmsegs[i].u.shm_perm.mode & SHMSEG_FREE)
 				break;
@@ -745,14 +807,15 @@
 	}
 	shmseg = &shmsegs[segnum];
 	/*
-	 * In case we sleep in malloc(), mark the segment present but deleted
-	 * so that noone else tries to create the same key.
+	 * Mark the segment present but deleted so that noone else tries to
+	 * create the same key.
 	 */
 	shmseg->u.shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED;
 	shmseg->u.shm_perm.key = uap->key;
 	shmseg->u.shm_perm.seq = (shmseg->u.shm_perm.seq + 1) & 0x7fff;
 	shmid = IXSEQ_TO_IPCID(segnum, shmseg->u.shm_perm);
-	
+
+	SHM_SX_XUNLOCK();
 	/*
 	 * We make sure that we have allocated a pager before we need
 	 * to.
@@ -768,7 +831,7 @@
 	vm_object_clear_flag(shm_object, OBJ_ONEMAPPING);
 	vm_object_set_flag(shm_object, OBJ_NOSPLIT);
 	VM_OBJECT_UNLOCK(shm_object);
-
+	SHM_SX_XLOCK();
 	shmseg->u.shm_internal = shm_object;
 	shmseg->u.shm_perm.cuid = shmseg->u.shm_perm.uid = cred->cr_uid;
 	shmseg->u.shm_perm.cgid = shmseg->u.shm_perm.gid = cred->cr_gid;
@@ -806,7 +869,7 @@
 
 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
 		return (ENOSYS);
-	mtx_lock(&Giant);
+	SHM_SX_XLOCK();
 	mode = uap->shmflg & ACCESSPERMS;
 	if (uap->key != IPC_PRIVATE) {
 	again:
@@ -823,8 +886,12 @@
 		}
 	}
 	error = shmget_allocate_segment(td, uap, mode);
+	SHM_SX_XUNLOCK();
+	SHM_DEBUG("error = %d\n", error);
+	return (error);
 done2:
-	mtx_unlock(&Giant);
+	SHM_SX_XUNLOCK();
+	SHM_DEBUG("error = %d\n", error);
 	return (error);
 }
 
@@ -847,9 +914,7 @@
 	if (uap->which < 0 ||
 	    uap->which >= sizeof(shmcalls)/sizeof(shmcalls[0]))
 		return (EINVAL);
-	mtx_lock(&Giant);
 	error = (*shmcalls[uap->which])(td, &uap->a2);
-	mtx_unlock(&Giant);
 	return (error);
 #else
 	return (nosys(td, NULL));
@@ -864,15 +929,15 @@
 	size_t size;
 	int i;
 
-	mtx_lock(&Giant);
 	size = shminfo.shmseg * sizeof(struct shmmap_state);
 	shmmap_s = malloc(size, M_SHM, M_WAITOK);
 	bcopy(p1->p_vmspace->vm_shm, shmmap_s, size);
 	p2->p_vmspace->vm_shm = shmmap_s;
+	SHM_SX_XLOCK();
 	for (i = 0; i < shminfo.shmseg; i++, shmmap_s++)
 		if (shmmap_s->shmid != -1)
 			shmsegs[IPCID_TO_IX(shmmap_s->shmid)].u.shm_nattch++;
-	mtx_unlock(&Giant);
+	SHM_SX_XUNLOCK();
 }
 
 static void
@@ -883,43 +948,17 @@
 
 	if ((base = vm->vm_shm) != NULL) {
 		vm->vm_shm = NULL;
-		mtx_lock(&Giant);
+		SHM_SX_XLOCK();
 		for (i = 0, shm = base; i < shminfo.shmseg; i++, shm++) {
 			if (shm->shmid != -1)
 				shm_delete_mapping(vm, shm);
 		}
-		mtx_unlock(&Giant);
+		SHM_SX_XUNLOCK();
 		free(base, M_SHM);
 	}
 }
 
 static void
-shmrealloc(void)
-{
-	int i;
-	struct shmid_kernel *newsegs;
-
-	if (shmalloced >= shminfo.shmmni)
-		return;
-
-	newsegs = malloc(shminfo.shmmni * sizeof(*newsegs), M_SHM, M_WAITOK);
-	if (newsegs == NULL)
-		return;
-	for (i = 0; i < shmalloced; i++)
-		bcopy(&shmsegs[i], &newsegs[i], sizeof(newsegs[0]));
-	for (; i < shminfo.shmmni; i++) {
-		shmsegs[i].u.shm_perm.mode = SHMSEG_FREE;
-		shmsegs[i].u.shm_perm.seq = 0;
-#ifdef MAC
-		mac_init_sysv_shm(&shmsegs[i]);
-#endif
-	}
-	free(shmsegs, M_SHM);
-	shmsegs = newsegs;
-	shmalloced = shminfo.shmmni;
-}
-
-static void
 shminit()
 {
 	int i;
@@ -935,6 +974,7 @@
 	TUNABLE_ULONG_FETCH("kern.ipc.shmseg", &shminfo.shmseg);
 	TUNABLE_INT_FETCH("kern.ipc.shm_use_phys", &shm_use_phys);
 
+	SHM_SX_LOCK_INIT();
 	shmalloced = shminfo.shmmni;
 	shmsegs = malloc(shmalloced * sizeof(shmsegs[0]), M_SHM, M_WAITOK);
 	if (shmsegs == NULL)
@@ -968,6 +1008,7 @@
 		mac_destroy_sysv_shm(&shmsegs[i]);
 #endif
 	free(shmsegs, M_SHM);
+	SHM_SX_LOCK_DESTROY();
 	shmexit_hook = NULL;
 	shmfork_hook = NULL;
 	return (0);
