Subject: Re: ipc errors/Linux Emulation NetBSD-3BETA using Oracle
To: None <current-users@netbsd.org>
From: Chuck Silvers <chuq@chuq.com>
List: tech-kern
Date: 11/02/2005 02:11:36
--/9DWx/yDrRhgMJTb
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Wed, Nov 02, 2005 at 01:28:06AM +0000, Christos Zoulas wrote:
> Try to recompile with a different MAX_SOPS define in <sys/sem.h> It is
> currently 5. You might want to add a debugging message to see how much
> is needed. If you need help doing that, please let me know.

the MAX_SOPS constant seems bogus in general.  there's a seminfo.semopm
global which can be changed via a SEMOPM kernel config option and
is reported by "ipcs -S", but this is ignored and MAX_SOPS used instead.

as a first step we should get rid of MAX_SOPS and use seminfo.semopm.
later we should add sysctl tunables like the other BSDs have.
a patch for the former is attached, anyone see any problems with it?

-Chuck

--/9DWx/yDrRhgMJTb
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="diff.semopm"

Index: src/sys/sys/sem.h
===================================================================
RCS file: /cvsroot/src/sys/sys/sem.h,v
retrieving revision 1.19
diff -u -p -r1.19 sem.h
--- src/sys/sys/sem.h	13 Sep 2005 01:42:51 -0000	1.19
+++ src/sys/sys/sem.h	2 Nov 2005 09:59:02 -0000
@@ -100,8 +100,6 @@ struct sembuf {
 #define SEMVMX	32767		/* semaphore maximum value */
 #define SEMAEM	16384		/* adjust on exit max value */
 
-#define MAX_SOPS	5	/* maximum # of sembuf's per semop call */
-
 /*
  * Permissions
  */
Index: src/sys/kern/sysv_sem.c
===================================================================
RCS file: /cvsroot/src/sys/kern/sysv_sem.c,v
retrieving revision 1.56
diff -u -p -r1.56 sysv_sem.c
--- src/sys/kern/sysv_sem.c	1 Apr 2005 11:59:37 -0000	1.56
+++ src/sys/kern/sysv_sem.c	2 Nov 2005 09:59:02 -0000
@@ -54,6 +54,7 @@ __KERNEL_RCSID(0, "$NetBSD: sysv_sem.c,v
 #include <sys/kernel.h>
 #include <sys/sem.h>
 #include <sys/sysctl.h>
+#include <sys/malloc.h>
 #include <sys/mount.h>		/* XXX for <sys/syscallargs.h> */
 #include <sys/sa.h>
 #include <sys/syscallargs.h>
@@ -565,6 +566,8 @@ found:
 	return (0);
 }
 
+#define SMALL_SOPS 8
+
 int
 sys_semop(l, v, retval)
 	struct lwp *l;
@@ -579,7 +582,8 @@ sys_semop(l, v, retval)
 	struct proc *p = l->l_proc;
 	int semid = SCARG(uap, semid), seq;
 	size_t nsops = SCARG(uap, nsops);
-	struct sembuf sops[MAX_SOPS];
+	struct sembuf small_sops[SMALL_SOPS];
+	struct sembuf *sops;
 	struct semid_ds *semaptr;
 	struct sembuf *sopptr = NULL;
 	struct __sem *semptr = NULL;
@@ -588,8 +592,7 @@ sys_semop(l, v, retval)
 	int i, eval;
 	int do_wakeup, do_undos;
 
-	SEM_PRINTF(("call to semop(%d, %p, %lld)\n", semid, sops,
-	    (long long)nsops));
+	SEM_PRINTF(("call to semop(%d, %p, %zd)\n", semid, sops, nsops));
 
 	semid = IPCID_TO_IX(semid);	/* Convert back to zero origin */
 	if (semid < 0 || semid >= seminfo.semmni)
@@ -606,23 +609,28 @@ sys_semop(l, v, retval)
 		return (eval);
 	}
 
-	if (nsops > MAX_SOPS) {
-		SEM_PRINTF(("too many sops (max=%d, nsops=%lld)\n", MAX_SOPS,
-		    (long long)nsops));
+	if (nsops <= SMALL_SOPS) {
+		sops = small_sops;
+	} else if (nsops <= seminfo.semopm) {
+		sops = malloc(nsops * sizeof(*sops), M_TEMP, M_WAITOK);
+	} else {
+		SEM_PRINTF(("too many sops (max=%d, nsops=%zd)\n",
+		    seminfo.semopm, nsops));
 		return (E2BIG);
 	}
 
 	if ((eval = copyin(SCARG(uap, sops),
 	    sops, nsops * sizeof(sops[0]))) != 0) {
-		SEM_PRINTF(("eval = %d from copyin(%p, %p, %lld)\n", eval,
-		    SCARG(uap, sops), &sops,
-		    (long long)(nsops * sizeof(sops[0]))));
-		return (eval);
+		SEM_PRINTF(("eval = %d from copyin(%p, %p, %zd)\n", eval,
+		    SCARG(uap, sops), &sops, nsops * sizeof(sops[0])));
+		goto out;
 	}
 
 	for (i = 0; i < nsops; i++)
-		if (sops[i].sem_num >= semaptr->sem_nsems)
-			return (EFBIG);
+		if (sops[i].sem_num >= semaptr->sem_nsems) {
+			eval = EFBIG;
+			goto out;
+		}
 
 	/*
 	 * Loop trying to satisfy the vector of requests.
@@ -695,8 +703,10 @@ sys_semop(l, v, retval)
 		 * If the request that we couldn't satisfy has the
 		 * NOWAIT flag set then return with EAGAIN.
 		 */
-		if (sopptr->sem_flg & IPC_NOWAIT)
-			return (EAGAIN);
+		if (sopptr->sem_flg & IPC_NOWAIT) {
+			eval = EAGAIN;
+			goto out;
+		}
 
 		if (sopptr->sem_op == 0)
 			semptr->semzcnt++;
@@ -713,13 +723,8 @@ sys_semop(l, v, retval)
 		 */
 		if ((semaptr->sem_perm.mode & SEM_ALLOC) == 0 ||
 		    semaptr->sem_perm._seq != seq) {
-			/* The man page says to return EIDRM. */
-			/* Unfortunately, BSD doesn't define that code! */
-#ifdef EIDRM
-			return (EIDRM);
-#else
-			return (EINVAL);
-#endif
+			eval = EIDRM;
+			goto out;
 		}
 
 		/*
@@ -736,8 +741,10 @@ sys_semop(l, v, retval)
 		 * (Delayed check of tsleep() return code because we
 		 * need to decrement sem[nz]cnt either way.)
 		 */
-		if (eval != 0)
-			return (EINTR);
+		if (eval != 0) {
+			eval = EINTR;
+			goto out;
+		}
 		SEM_PRINTF(("semop:  good morning!\n"));
 	}
 
@@ -788,7 +795,7 @@ done:
 				    sops[i].sem_op;
 
 			SEM_PRINTF(("eval = %d from semundo_adjust\n", eval));
-			return (eval);
+			goto out;
 		} /* loop through the sops */
 	} /* if (do_undos) */
 
@@ -814,7 +821,12 @@ done:
 	}
 	SEM_PRINTF(("semop:  done\n"));
 	*retval = 0;
-	return (0);
+
+out:
+	if (sops != small_sops) {
+		free(sops, M_TEMP);
+	}
+	return eval;
 }
 
 /*

--/9DWx/yDrRhgMJTb--