Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 11 Jan 2009 17:58:55 +0200
From:      Kostik Belousov <kostikbel@gmail.com>
To:        Omer Faruk Sen <omerfsen@gmail.com>
Cc:        freebsd-hackers@freebsd.org
Subject:   Re: kernel dump with 7.1-RELEASE
Message-ID:  <20090111155854.GS93900@deviant.kiev.zoral.com.ua>
In-Reply-To: <75a268720901090839q406ed8f3g8d09e83a9a452415@mail.gmail.com>
References:  <75a268720901090839q406ed8f3g8d09e83a9a452415@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help

--173oMW6+eDUtB8Ng
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

On Fri, Jan 09, 2009 at 06:39:53PM +0200, Omer Faruk Sen wrote:
> Hi,
>=20
> I am having kernel dump with FreeBSD 7.1:
>=20
> Here is crashinfo output of it  (Actually i don't know the state of
> crashinfo in Fbsd 7.1)
>=20
> 7.1-RELEASE FreeBSD 7.1-RELEASE #0: Thu Jan  1 08:58:24 UTC 2009
> root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
>=20
>=20
>=20
> panic: semexit - semid not allocated
>=20
> GNU gdb 6.1.1 [FreeBSD]
> Copyright 2004 Free Software Foundation, Inc.
> GDB is free software, covered by the GNU General Public License, and you =
are
> welcome to change it and/or distribute copies of it under certain conditi=
ons.
> Type "show copying" to see the conditions.
> There is absolutely no warranty for GDB.  Type "show warranty" for detail=
s.
> This GDB was configured as "amd64-marcel-freebsd"...
>=20
> Unread portion of the kernel message buffer:
> Physical memory: 8173 MB
> Dumping 437 MB: 422 406 390 374 358 342 326 310 294 278 262 246 230
> 214 198 182 166 150 134 118 102 86 70 54 38 22 6
>=20
> #0  doadump () at pcpu.h:195
> 195     pcpu.h: No such file or directory.
>         in pcpu.h
> (kgdb) #0  doadump () at pcpu.h:195
> #1  0x0000000000000004 in ?? ()
> #2  0xffffffff804b4ce9 in boot (howto=3D260)
>     at /usr/src/sys/kern/kern_shutdown.c:418
> #3  0xffffffff804b50f2 in panic (fmt=3D0x104 <Address 0x104 out of bounds=
>)
>     at /usr/src/sys/kern/kern_shutdown.c:574
> #4  0xffffffff804f846d in semexit_myhook (arg=3DVariable "arg" is not ava=
ilable.
> )
>     at /usr/src/sys/kern/sysv_sem.c:1328
> #5  0xffffffff80490dbc in exit1 (td=3D0xffffff000995f370, rv=3D0)
>     at /usr/src/sys/kern/kern_exit.c:244
> #6  0xffffffff8049239e in sys_exit (td=3DVariable "td" is not available.
> ) at /usr/src/sys/kern/kern_exit.c:109
> #7  0xffffffff8078a7c7 in syscall (frame=3D0xffffffffb0d4ac80)
>     at /usr/src/sys/amd64/amd64/trap.c:907
> #8  0xffffffff8077088b in Xfast_syscall ()
>     at /usr/src/sys/amd64/amd64/exception.S:330
> #9  0x0000000800a2a30c in ?? ()
> Previous frame inner to this frame (corrupt stack?)
> (kgdb)

It seems that there are at least two issues with IPC_RMID operation
on SysV semaphores.
1. The squeeze of the semaphore array in the kern_semctl() modifies
   sem_base for the semaphores, as well as the values of the
   semaphores, without locking their mutex. This can lead to
   (killable) hangs or unexpected behaviour of the processes
   performing any sem operations while other process does IPC_RMID.
2. The semexit_myhook() eventhandler does not lock SEMUNDO_LOCK()
   while accessing *suptr. I think that this allows for IPC_RMID
   to be performed in parallel with the sem id referenced by the
   current undo structure.

Patch below is the backport of the patch I developed and lightly
tested on CURRENT, that shuffle locking to solve the listed issues.
Testing consisted of running several instances of
tools/regression/sysvsem.

diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c
index 80d07ba..6bc4cce 100644
--- a/sys/kern/sysv_sem.c
+++ b/sys/kern/sysv_sem.c
@@ -88,7 +88,7 @@ int semop(struct thread *td, struct semop_args *uap);
=20
 static struct sem_undo *semu_alloc(struct thread *td);
 static int semundo_adjust(struct thread *td, struct sem_undo **supptr,
-		int semid, int semnum, int adjval);
+    int semid, int semseq, int semnum, int adjval);
 static void semundo_clear(int semid, int semnum);
=20
 /* XXX casting to (sy_call_t *) is bogus, as usual. */
@@ -98,15 +98,17 @@ static sy_call_t *semcalls[] =3D {
 };
=20
 static struct mtx	sem_mtx;	/* semaphore global lock */
+static struct mtx sem_undo_mtx;
 static int	semtot =3D 0;
 static struct semid_kernel *sema;	/* semaphore id pool */
 static struct mtx *sema_mtx;	/* semaphore id pool mutexes*/
 static struct sem *sem;		/* semaphore pool */
-SLIST_HEAD(, sem_undo) semu_list;	/* list of active undo structures */
+LIST_HEAD(, sem_undo) semu_list;	/* list of active undo structures */
+LIST_HEAD(, sem_undo) semu_free_list;	/* list of free undo structures */
 static int	*semu;		/* undo structure pool */
 static eventhandler_tag semexit_tag;
=20
-#define SEMUNDO_MTX		sem_mtx
+#define SEMUNDO_MTX		sem_undo_mtx
 #define SEMUNDO_LOCK()		mtx_lock(&SEMUNDO_MTX);
 #define SEMUNDO_UNLOCK()	mtx_unlock(&SEMUNDO_MTX);
 #define SEMUNDO_LOCKASSERT(how)	mtx_assert(&SEMUNDO_MTX, (how));
@@ -122,13 +124,15 @@ struct sem {
  * Undo structure (one per process)
  */
 struct sem_undo {
-	SLIST_ENTRY(sem_undo) un_next;	/* ptr to next active undo structure */
+	LIST_ENTRY(sem_undo) un_next;	/* ptr to next active undo structure */
 	struct	proc *un_proc;		/* owner of this structure */
 	short	un_cnt;			/* # of active entries */
 	struct undo {
 		short	un_adjval;	/* adjust on exit values */
 		short	un_num;		/* semaphore # */
 		int	un_id;		/* semid */
+		unsigned short un_seq;
+
 	} un_ent[1];			/* undo entries */
 };
=20
@@ -250,12 +254,15 @@ seminit(void)
 	}
 	for (i =3D 0; i < seminfo.semmni; i++)
 		mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF);
+	LIST_INIT(&semu_free_list);
 	for (i =3D 0; i < seminfo.semmnu; i++) {
 		struct sem_undo *suptr =3D SEMU(i);
 		suptr->un_proc =3D NULL;
+		LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
 	}
-	SLIST_INIT(&semu_list);
+	LIST_INIT(&semu_list);
 	mtx_init(&sem_mtx, "sem", NULL, MTX_DEF);
+	mtx_init(&sem_undo_mtx, "semu", NULL, MTX_DEF);
 	semexit_tag =3D EVENTHANDLER_REGISTER(process_exit, semexit_myhook, NULL,
 	    EVENTHANDLER_PRI_ANY);
 }
@@ -265,6 +272,7 @@ semunload(void)
 {
 	int i;
=20
+	/* XXXKIB */
 	if (semtot !=3D 0)
 		return (EBUSY);
=20
@@ -279,6 +287,7 @@ semunload(void)
 	for (i =3D 0; i < seminfo.semmni; i++)
 		mtx_destroy(&sema_mtx[i]);
 	mtx_destroy(&sem_mtx);
+	mtx_destroy(&sem_undo_mtx);
 	return (0);
 }
=20
@@ -350,69 +359,31 @@ semsys(td, uap)
  */
=20
 static struct sem_undo *
-semu_alloc(td)
-	struct thread *td;
+semu_alloc(struct thread *td)
 {
-	int i;
 	struct sem_undo *suptr;
-	struct sem_undo **supptr;
-	int attempt;
=20
 	SEMUNDO_LOCKASSERT(MA_OWNED);
-	/*
-	 * Try twice to allocate something.
-	 * (we'll purge an empty structure after the first pass so
-	 * two passes are always enough)
-	 */
-
-	for (attempt =3D 0; attempt < 2; attempt++) {
-		/*
-		 * Look for a free structure.
-		 * Fill it in and return it if we find one.
-		 */
-
-		for (i =3D 0; i < seminfo.semmnu; i++) {
-			suptr =3D SEMU(i);
-			if (suptr->un_proc =3D=3D NULL) {
-				SLIST_INSERT_HEAD(&semu_list, suptr, un_next);
-				suptr->un_cnt =3D 0;
-				suptr->un_proc =3D td->td_proc;
-				return(suptr);
-			}
-		}
-
-		/*
-		 * We didn't find a free one, if this is the first attempt
-		 * then try to free a structure.
-		 */
+	if ((suptr =3D LIST_FIRST(&semu_free_list)) =3D=3D NULL)
+		return (NULL);
+	LIST_REMOVE(suptr, un_next);
+	LIST_INSERT_HEAD(&semu_list, suptr, un_next);
+	suptr->un_cnt =3D 0;
+	suptr->un_proc =3D td->td_proc;
+	return (suptr);
+}
=20
-		if (attempt =3D=3D 0) {
-			/* All the structures are in use - try to free one */
-			int did_something =3D 0;
+static int
+semu_try_free(struct sem_undo *suptr)
+{
=20
-			SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list,
-			    un_next) {
-				if (suptr->un_cnt =3D=3D 0) {
-					suptr->un_proc =3D NULL;
-					did_something =3D 1;
-					*supptr =3D SLIST_NEXT(suptr, un_next);
-					break;
-				}
-			}
+	SEMUNDO_LOCKASSERT(MA_OWNED);
=20
-			/* If we didn't free anything then just give-up */
-			if (!did_something)
-				return(NULL);
-		} else {
-			/*
-			 * The second pass failed even though we freed
-			 * something after the first pass!
-			 * This is IMPOSSIBLE!
-			 */
-			panic("semu_alloc - second attempt failed");
-		}
-	}
-	return (NULL);
+	if (suptr->un_cnt !=3D 0)
+		return (0);
+	LIST_REMOVE(suptr, un_next);
+	LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
+	return (1);
 }
=20
 /*
@@ -420,11 +391,8 @@ semu_alloc(td)
  */
=20
 static int
-semundo_adjust(td, supptr, semid, semnum, adjval)
-	struct thread *td;
-	struct sem_undo **supptr;
-	int semid, semnum;
-	int adjval;
+semundo_adjust(struct thread *td, struct sem_undo **supptr, int semid,
+    int semseq, int semnum, int adjval)
 {
 	struct proc *p =3D td->td_proc;
 	struct sem_undo *suptr;
@@ -437,7 +405,7 @@ semundo_adjust(td, supptr, semid, semnum, adjval)
=20
 	suptr =3D *supptr;
 	if (suptr =3D=3D NULL) {
-		SLIST_FOREACH(suptr, &semu_list, un_next) {
+		LIST_FOREACH(suptr, &semu_list, un_next) {
 			if (suptr->un_proc =3D=3D p) {
 				*supptr =3D suptr;
 				break;
@@ -448,7 +416,7 @@ semundo_adjust(td, supptr, semid, semnum, adjval)
 				return(0);
 			suptr =3D semu_alloc(td);
 			if (suptr =3D=3D NULL)
-				return(ENOSPC);
+				return (ENOSPC);
 			*supptr =3D suptr;
 		}
 	}
@@ -472,58 +440,59 @@ semundo_adjust(td, supptr, semid, semnum, adjval)
 			if (i < suptr->un_cnt)
 				suptr->un_ent[i] =3D
 				    suptr->un_ent[suptr->un_cnt];
+			if (suptr->un_cnt =3D=3D 0)
+				semu_try_free(suptr);
 		}
-		return(0);
+		return (0);
 	}
=20
 	/* Didn't find the right entry - create it */
 	if (adjval =3D=3D 0)
-		return(0);
+		return (0);
 	if (adjval > seminfo.semaem || adjval < -seminfo.semaem)
 		return (ERANGE);
 	if (suptr->un_cnt !=3D seminfo.semume) {
 		sunptr =3D &suptr->un_ent[suptr->un_cnt];
 		suptr->un_cnt++;
 		sunptr->un_adjval =3D adjval;
-		sunptr->un_id =3D semid; sunptr->un_num =3D semnum;
+		sunptr->un_id =3D semid;
+		sunptr->un_num =3D semnum;
+		sunptr->un_seq =3D semseq;
 	} else
-		return(EINVAL);
-	return(0);
+		return (EINVAL);
+	return (0);
 }
=20
 static void
-semundo_clear(semid, semnum)
-	int semid, semnum;
+semundo_clear(int semid, int semnum)
 {
-	struct sem_undo *suptr;
+	struct sem_undo *suptr, *suptr1;
+	struct undo *sunptr;
+	int i;
=20
 	SEMUNDO_LOCKASSERT(MA_OWNED);
-	SLIST_FOREACH(suptr, &semu_list, un_next) {
-		struct undo *sunptr =3D &suptr->un_ent[0];
-		int i =3D 0;
-
-		while (i < suptr->un_cnt) {
-			if (sunptr->un_id =3D=3D semid) {
-				if (semnum =3D=3D -1 || sunptr->un_num =3D=3D semnum) {
-					suptr->un_cnt--;
-					if (i < suptr->un_cnt) {
-						suptr->un_ent[i] =3D
-						  suptr->un_ent[suptr->un_cnt];
-						continue;
-					}
+	LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) {
+		sunptr =3D &suptr->un_ent[0];
+		for (i =3D 0; i < suptr->un_cnt; i++, sunptr++) {
+			if (sunptr->un_id !=3D semid)
+				continue;
+			if (semnum =3D=3D -1 || sunptr->un_num =3D=3D semnum) {
+				suptr->un_cnt--;
+				if (i < suptr->un_cnt) {
+					suptr->un_ent[i] =3D
+					    suptr->un_ent[suptr->un_cnt];
+					continue;
 				}
-				if (semnum !=3D -1)
-					break;
+				semu_try_free(suptr);
 			}
-			i++, sunptr++;
+			if (semnum !=3D -1)
+				break;
 		}
 	}
 }
=20
 static int
-semvalid(semid, semakptr)
-	int semid;
-	struct semid_kernel *semakptr;
+semvalid(int semid, struct semid_kernel *semakptr)
 {
=20
 	return ((semakptr->u.sem_perm.mode & SEM_ALLOC) =3D=3D 0 ||
@@ -542,9 +511,7 @@ struct __semctl_args {
 };
 #endif
 int
-__semctl(td, uap)
-	struct thread *td;
-	struct __semctl_args *uap;
+__semctl(struct thread *td, struct __semctl_args *uap)
 {
 	struct semid_ds dsbuf;
 	union semun arg, semun;
@@ -655,6 +622,8 @@ kern_semctl(struct thread *td, int semid, int semnum, i=
nt cmd,
=20
 	semakptr =3D &sema[semidx];
 	sema_mtxp =3D &sema_mtx[semidx];
+	if (cmd =3D=3D IPC_RMID)
+		mtx_lock(&sem_mtx);
 	mtx_lock(sema_mtxp);
 #ifdef MAC
 	error =3D mac_check_sysv_sem_semctl(cred, semakptr, cmd);
@@ -673,22 +642,29 @@ kern_semctl(struct thread *td, int semid, int semnum,=
 int cmd,
 			goto done2;
 		semakptr->u.sem_perm.cuid =3D cred->cr_uid;
 		semakptr->u.sem_perm.uid =3D cred->cr_uid;
-		semtot -=3D semakptr->u.sem_nsems;
+		semakptr->u.sem_perm.mode =3D 0;
+		SEMUNDO_LOCK();
+		semundo_clear(semidx, -1);
+		SEMUNDO_UNLOCK();
+#ifdef MAC
+		mac_cleanup_sysv_sem(semakptr);
+#endif
+		wakeup(semakptr);
+		for (i =3D 0; i < seminfo.semmni; i++) {
+			if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
+			    sema[i].u.sem_base > semakptr->u.sem_base)
+				mtx_lock(&sema_mtx[i]);
+		}
 		for (i =3D semakptr->u.sem_base - sem; i < semtot; i++)
 			sem[i] =3D sem[i + semakptr->u.sem_nsems];
 		for (i =3D 0; i < seminfo.semmni; i++) {
 			if ((sema[i].u.sem_perm.mode & SEM_ALLOC) &&
-			    sema[i].u.sem_base > semakptr->u.sem_base)
+			    sema[i].u.sem_base > semakptr->u.sem_base) {
 				sema[i].u.sem_base -=3D semakptr->u.sem_nsems;
+				mtx_unlock(&sema_mtx[i]);
+			}
 		}
-		semakptr->u.sem_perm.mode =3D 0;
-#ifdef MAC
-		mac_cleanup_sysv_sem(semakptr);
-#endif
-		SEMUNDO_LOCK();
-		semundo_clear(semidx, -1);
-		SEMUNDO_UNLOCK();
-		wakeup(semakptr);
+		semtot -=3D semakptr->u.sem_nsems;
 		break;
=20
 	case IPC_SET:
@@ -855,6 +831,8 @@ kern_semctl(struct thread *td, int semid, int semnum, i=
nt cmd,
=20
 done2:
 	mtx_unlock(sema_mtxp);
+	if (cmd =3D=3D IPC_RMID)
+		mtx_unlock(&sem_mtx);
 	if (array !=3D NULL)
 		free(array, M_TEMP);
 	return(error);
@@ -868,21 +846,23 @@ struct semget_args {
 };
 #endif
 int
-semget(td, uap)
-	struct thread *td;
-	struct semget_args *uap;
+semget(struct thread *td, struct semget_args *uap)
 {
 	int semid, error =3D 0;
 	int key =3D uap->key;
 	int nsems =3D uap->nsems;
 	int semflg =3D uap->semflg;
 	struct ucred *cred =3D td->td_ucred;
+	register_t ret;
+#ifdef MAC
+	int sem_found;
+#endif
=20
 	DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg));
 	if (!jail_sysvipc_allowed && jailed(td->td_ucred))
 		return (ENOSYS);
=20
-	mtx_lock(&Giant);
+	mtx_lock(&sem_mtx);
 	if (key !=3D IPC_PRIVATE) {
 		for (semid =3D 0; semid < seminfo.semmni; semid++) {
 			if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) &&
@@ -905,15 +885,12 @@ semget(td, uap)
 				error =3D EEXIST;
 				goto done2;
 			}
-#ifdef MAC
-			error =3D mac_check_sysv_semget(cred, &sema[semid]);
-			if (error !=3D 0)
-				goto done2;
-#endif
+			sem_found =3D 1;
 			goto found;
 		}
 	}
=20
+	sem_found =3D 0;
 	DPRINTF(("need to allocate the semid_kernel\n"));
 	if (key =3D=3D IPC_PRIVATE || (semflg & IPC_CREAT)) {
 		if (nsems <=3D 0 || nsems > seminfo.semmsl) {
@@ -955,7 +932,6 @@ semget(td, uap)
 		bzero(sema[semid].u.sem_base,
 		    sizeof(sema[semid].u.sem_base[0])*nsems);
 #ifdef MAC
-		mac_create_sysv_sem(cred, &sema[semid]);
 #endif
 		DPRINTF(("sembase =3D %p, next =3D %p\n",
 		    sema[semid].u.sem_base, &sem[semtot]));
@@ -966,9 +942,19 @@ semget(td, uap)
 	}
=20
 found:
-	td->td_retval[0] =3D IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
+	ret =3D IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm);
+	mtx_unlock(&sem_mtx);
+#ifdef MAC
+	if (error =3D=3D 0) {
+		if (sem_found)
+			error =3D mac_check_sysv_semget(cred, &sema[semid]);
+		else
+			mac_create_sysv_sem(cred, &sema[semid]);
+	}
+	if (error =3D=3D 0)
+#endif
+		td->td_retval[0] =3D ret;
 done2:
-	mtx_unlock(&Giant);
 	return (error);
 }
=20
@@ -980,9 +966,7 @@ struct semop_args {
 };
 #endif
 int
-semop(td, uap)
-	struct thread *td;
-	struct semop_args *uap;
+semop(struct thread *td, struct semop_args *uap)
 {
 #define SMALL_SOPS	8
 	struct sembuf small_sops[SMALL_SOPS];
@@ -997,6 +981,7 @@ semop(td, uap)
 	size_t i, j, k;
 	int error;
 	int do_wakeup, do_undos;
+	unsigned short seq;
=20
 #ifdef SEM_DEBUG
 	sops =3D NULL;
@@ -1036,7 +1021,8 @@ semop(td, uap)
 		error =3D EINVAL;
 		goto done2;
 	}
-	if (semakptr->u.sem_perm.seq !=3D IPCID_TO_SEQ(uap->semid)) {
+	seq =3D semakptr->u.sem_perm.seq;
+	if (seq !=3D IPCID_TO_SEQ(uap->semid)) {
 		error =3D EINVAL;
 		goto done2;
 	}
@@ -1160,8 +1146,9 @@ semop(td, uap)
 		/*
 		 * Make sure that the semaphore still exists
 		 */
+		seq =3D semakptr->u.sem_perm.seq;
 		if ((semakptr->u.sem_perm.mode & SEM_ALLOC) =3D=3D 0 ||
-		    semakptr->u.sem_perm.seq !=3D IPCID_TO_SEQ(uap->semid)) {
+		    seq !=3D IPCID_TO_SEQ(uap->semid)) {
 			error =3D EIDRM;
 			goto done2;
 		}
@@ -1213,7 +1200,7 @@ done:
 			adjval =3D sops[i].sem_op;
 			if (adjval =3D=3D 0)
 				continue;
-			error =3D semundo_adjust(td, &suptr, semid,
+			error =3D semundo_adjust(td, &suptr, semid, seq,
 			    sops[i].sem_num, -adjval);
 			if (error =3D=3D 0)
 				continue;
@@ -1234,7 +1221,7 @@ done:
 				adjval =3D sops[k].sem_op;
 				if (adjval =3D=3D 0)
 					continue;
-				if (semundo_adjust(td, &suptr, semid,
+				if (semundo_adjust(td, &suptr, semid, seq,
 				    sops[k].sem_num, adjval) !=3D 0)
 					panic("semop - can't undo undos");
 			}
@@ -1281,28 +1268,28 @@ done2:
  * semaphores.
  */
 static void
-semexit_myhook(arg, p)
-	void *arg;
-	struct proc *p;
+semexit_myhook(void *arg, struct proc *p)
 {
 	struct sem_undo *suptr;
-	struct sem_undo **supptr;
+	struct semid_kernel *semakptr;
+	struct mtx *sema_mtxp;
+	int semid, semnum, adjval, ix;
+	unsigned short seq;
=20
 	/*
 	 * Go through the chain of undo vectors looking for one
 	 * associated with this process.
 	 */
 	SEMUNDO_LOCK();
-	SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, un_next) {
-		if (suptr->un_proc =3D=3D p) {
-			*supptr =3D SLIST_NEXT(suptr, un_next);
+	LIST_FOREACH(suptr, &semu_list, un_next) {
+		if (suptr->un_proc =3D=3D p)
 			break;
-		}
 	}
-	SEMUNDO_UNLOCK();
-
-	if (suptr =3D=3D NULL)
+	if (suptr =3D=3D NULL) {
+		SEMUNDO_UNLOCK();
 		return;
+	}
+	LIST_REMOVE(suptr, un_next);
=20
 	DPRINTF(("proc @%p has undo structure with %d entries\n", p,
 	    suptr->un_cnt));
@@ -1311,21 +1298,21 @@ semexit_myhook(arg, p)
 	 * If there are any active undo elements then process them.
 	 */
 	if (suptr->un_cnt > 0) {
-		int ix;
-
+		SEMUNDO_UNLOCK();
 		for (ix =3D 0; ix < suptr->un_cnt; ix++) {
-			int semid =3D suptr->un_ent[ix].un_id;
-			int semnum =3D suptr->un_ent[ix].un_num;
-			int adjval =3D suptr->un_ent[ix].un_adjval;
-			struct semid_kernel *semakptr;
-			struct mtx *sema_mtxp;
-
+			semid =3D suptr->un_ent[ix].un_id;
+			semnum =3D suptr->un_ent[ix].un_num;
+			adjval =3D suptr->un_ent[ix].un_adjval;
+			seq =3D suptr->un_ent[ix].un_seq;
 			semakptr =3D &sema[semid];
 			sema_mtxp =3D &sema_mtx[semid];
+
 			mtx_lock(sema_mtxp);
-			SEMUNDO_LOCK();
-			if ((semakptr->u.sem_perm.mode & SEM_ALLOC) =3D=3D 0)
-				panic("semexit - semid not allocated");
+			if ((semakptr->u.sem_perm.mode & SEM_ALLOC) =3D=3D 0 ||
+			    (semakptr->u.sem_perm.seq !=3D seq)) {
+				mtx_unlock(sema_mtxp);
+				continue;
+			}
 			if (semnum >=3D semakptr->u.sem_nsems)
 				panic("semexit - semnum out of range");
=20
@@ -1336,29 +1323,26 @@ semexit_myhook(arg, p)
 			    suptr->un_ent[ix].un_adjval,
 			    semakptr->u.sem_base[semnum].semval));
=20
-			if (adjval < 0) {
-				if (semakptr->u.sem_base[semnum].semval <
-				    -adjval)
-					semakptr->u.sem_base[semnum].semval =3D 0;
-				else
-					semakptr->u.sem_base[semnum].semval +=3D
-					    adjval;
-			} else
+			if (adjval < 0 && semakptr->u.sem_base[semnum].semval <
+			    -adjval)
+				semakptr->u.sem_base[semnum].semval =3D 0;
+			else
 				semakptr->u.sem_base[semnum].semval +=3D adjval;
=20
 			wakeup(semakptr);
 			DPRINTF(("semexit:  back from wakeup\n"));
 			mtx_unlock(sema_mtxp);
-			SEMUNDO_UNLOCK();
 		}
+		SEMUNDO_LOCK();
 	}
=20
 	/*
 	 * Deallocate the undo vector.
 	 */
 	DPRINTF(("removing vector\n"));
-	SEMUNDO_LOCK();
 	suptr->un_proc =3D NULL;
+	suptr->un_cnt =3D 0;
+	LIST_INSERT_HEAD(&semu_free_list, suptr, un_next);
 	SEMUNDO_UNLOCK();
 }
=20

--173oMW6+eDUtB8Ng
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.9 (FreeBSD)

iEYEARECAAYFAklqFz4ACgkQC3+MBN1Mb4iPEwCgvwSjiY/ShUPbowsrm8xRLl3g
qHwAoJEIpCv93ff7M1cv1rIiyxOc7IAS
=w1Ti
-----END PGP SIGNATURE-----

--173oMW6+eDUtB8Ng--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20090111155854.GS93900>