From owner-freebsd-hackers@FreeBSD.ORG Sun Jan 11 19:04:12 2009 Return-Path: Delivered-To: freebsd-hackers@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id B4B7E106564A for ; Sun, 11 Jan 2009 19:04:12 +0000 (UTC) (envelope-from omerfsen@gmail.com) Received: from nf-out-0910.google.com (nf-out-0910.google.com [64.233.182.189]) by mx1.freebsd.org (Postfix) with ESMTP id 9C0DD8FC0A for ; Sun, 11 Jan 2009 19:04:11 +0000 (UTC) (envelope-from omerfsen@gmail.com) Received: by nf-out-0910.google.com with SMTP id h3so1858360nfh.33 for ; Sun, 11 Jan 2009 11:04:10 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from:to :subject:cc:in-reply-to:mime-version:content-type:references; bh=ShFoB1dG0iG6Dp2N98xeR/6cbiVLPfE8SDpppKRZACU=; b=UPQUAKlJr8f2anhSrbXkz2j0ShQbvoTM4b03jEdv9xsqNqJHr6Ast4odqQzXHRlG9M ouYQfkaAEOLN8vG2OCKUZZOcHX/D2nM4JlkpEbnufIbgXS3mo3iAZdabj4tRAHuVA3uc UubitN74Ws0xTfsFdpfqqcuEPYqthRuH7N0Es= DomainKey-Signature: a=rsa-sha1; c=nofws; d=gmail.com; s=gamma; h=message-id:date:from:to:subject:cc:in-reply-to:mime-version :content-type:references; b=FQyL/J/cqAsHrMtzqJOcMHpclEEEAeP4EFynTD1KE7QxSvA6y16RokieZydojBKWUW 2EFwXzVpithOj/NTLS0Z+QK7heT/hIv8S5cQKYUNR8c2i0r8GTAk77RC1P0dLO61s7BO NfFeNvIZf2vGNKQPzPrisdC69rRflCwdjxIB0= Received: by 10.66.222.6 with SMTP id u6mr793797ugg.19.1231700650382; Sun, 11 Jan 2009 11:04:10 -0800 (PST) Received: by 10.67.99.13 with HTTP; Sun, 11 Jan 2009 11:04:10 -0800 (PST) Message-ID: <75a268720901111104m6297614jae11f5d1ea4f85df@mail.gmail.com> Date: Sun, 11 Jan 2009 21:04:10 +0200 From: "Omer Faruk Sen" To: "Kostik Belousov" In-Reply-To: <20090111155854.GS93900@deviant.kiev.zoral.com.ua> MIME-Version: 1.0 References: <75a268720901090839q406ed8f3g8d09e83a9a452415@mail.gmail.com> <20090111155854.GS93900@deviant.kiev.zoral.com.ua> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline X-Content-Filtered-By: Mailman/MimeDel 2.1.5 Cc: freebsd-hackers@freebsd.org Subject: Re: kernel dump with 7.1-RELEASE X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 11 Jan 2009 19:04:13 -0000 Hi Kostik, I will try that patch and will return to -hackers if that solves semid not allocated problem. Thanks for prompt action. Best Regards. On Sun, Jan 11, 2009 at 5:58 PM, Kostik Belousov wrote: > On Fri, Jan 09, 2009 at 06:39:53PM +0200, Omer Faruk Sen wrote: > > Hi, > > > > I am having kernel dump with FreeBSD 7.1: > > > > Here is crashinfo output of it (Actually i don't know the state of > > crashinfo in Fbsd 7.1) > > > > 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 > > > > > > > > panic: semexit - semid not allocated > > > > 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 > conditions. > > Type "show copying" to see the conditions. > > There is absolutely no warranty for GDB. Type "show warranty" for > details. > > This GDB was configured as "amd64-marcel-freebsd"... > > > > 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 > > > > #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=260) > > at /usr/src/sys/kern/kern_shutdown.c:418 > > #3 0xffffffff804b50f2 in panic (fmt=0x104
) > > at /usr/src/sys/kern/kern_shutdown.c:574 > > #4 0xffffffff804f846d in semexit_myhook (arg=Variable "arg" is not > available. > > ) > > at /usr/src/sys/kern/sysv_sem.c:1328 > > #5 0xffffffff80490dbc in exit1 (td=0xffffff000995f370, rv=0) > > at /usr/src/sys/kern/kern_exit.c:244 > > #6 0xffffffff8049239e in sys_exit (td=Variable "td" is not available. > > ) at /usr/src/sys/kern/kern_exit.c:109 > > #7 0xffffffff8078a7c7 in syscall (frame=0xffffffffb0d4ac80) > > 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); > > 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); > > /* XXX casting to (sy_call_t *) is bogus, as usual. */ > @@ -98,15 +98,17 @@ static sy_call_t *semcalls[] = { > }; > > static struct mtx sem_mtx; /* semaphore global lock */ > +static struct mtx sem_undo_mtx; > static int semtot = 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; > > -#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 */ > }; > > @@ -250,12 +254,15 @@ seminit(void) > } > for (i = 0; i < seminfo.semmni; i++) > mtx_init(&sema_mtx[i], "semid", NULL, MTX_DEF); > + LIST_INIT(&semu_free_list); > for (i = 0; i < seminfo.semmnu; i++) { > struct sem_undo *suptr = SEMU(i); > suptr->un_proc = 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 = EVENTHANDLER_REGISTER(process_exit, semexit_myhook, > NULL, > EVENTHANDLER_PRI_ANY); > } > @@ -265,6 +272,7 @@ semunload(void) > { > int i; > > + /* XXXKIB */ > if (semtot != 0) > return (EBUSY); > > @@ -279,6 +287,7 @@ semunload(void) > for (i = 0; i < seminfo.semmni; i++) > mtx_destroy(&sema_mtx[i]); > mtx_destroy(&sem_mtx); > + mtx_destroy(&sem_undo_mtx); > return (0); > } > > @@ -350,69 +359,31 @@ semsys(td, uap) > */ > > 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; > > 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 = 0; attempt < 2; attempt++) { > - /* > - * Look for a free structure. > - * Fill it in and return it if we find one. > - */ > - > - for (i = 0; i < seminfo.semmnu; i++) { > - suptr = SEMU(i); > - if (suptr->un_proc == NULL) { > - SLIST_INSERT_HEAD(&semu_list, suptr, > un_next); > - suptr->un_cnt = 0; > - suptr->un_proc = 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 = LIST_FIRST(&semu_free_list)) == NULL) > + return (NULL); > + LIST_REMOVE(suptr, un_next); > + LIST_INSERT_HEAD(&semu_list, suptr, un_next); > + suptr->un_cnt = 0; > + suptr->un_proc = td->td_proc; > + return (suptr); > +} > > - if (attempt == 0) { > - /* All the structures are in use - try to free one > */ > - int did_something = 0; > +static int > +semu_try_free(struct sem_undo *suptr) > +{ > > - SLIST_FOREACH_PREVPTR(suptr, supptr, &semu_list, > - un_next) { > - if (suptr->un_cnt == 0) { > - suptr->un_proc = NULL; > - did_something = 1; > - *supptr = SLIST_NEXT(suptr, > un_next); > - break; > - } > - } > + SEMUNDO_LOCKASSERT(MA_OWNED); > > - /* 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 != 0) > + return (0); > + LIST_REMOVE(suptr, un_next); > + LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); > + return (1); > } > > /* > @@ -420,11 +391,8 @@ semu_alloc(td) > */ > > 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 = td->td_proc; > struct sem_undo *suptr; > @@ -437,7 +405,7 @@ semundo_adjust(td, supptr, semid, semnum, adjval) > > suptr = *supptr; > if (suptr == NULL) { > - SLIST_FOREACH(suptr, &semu_list, un_next) { > + LIST_FOREACH(suptr, &semu_list, un_next) { > if (suptr->un_proc == p) { > *supptr = suptr; > break; > @@ -448,7 +416,7 @@ semundo_adjust(td, supptr, semid, semnum, adjval) > return(0); > suptr = semu_alloc(td); > if (suptr == NULL) > - return(ENOSPC); > + return (ENOSPC); > *supptr = suptr; > } > } > @@ -472,58 +440,59 @@ semundo_adjust(td, supptr, semid, semnum, adjval) > if (i < suptr->un_cnt) > suptr->un_ent[i] = > suptr->un_ent[suptr->un_cnt]; > + if (suptr->un_cnt == 0) > + semu_try_free(suptr); > } > - return(0); > + return (0); > } > > /* Didn't find the right entry - create it */ > if (adjval == 0) > - return(0); > + return (0); > if (adjval > seminfo.semaem || adjval < -seminfo.semaem) > return (ERANGE); > if (suptr->un_cnt != seminfo.semume) { > sunptr = &suptr->un_ent[suptr->un_cnt]; > suptr->un_cnt++; > sunptr->un_adjval = adjval; > - sunptr->un_id = semid; sunptr->un_num = semnum; > + sunptr->un_id = semid; > + sunptr->un_num = semnum; > + sunptr->un_seq = semseq; > } else > - return(EINVAL); > - return(0); > + return (EINVAL); > + return (0); > } > > 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; > > SEMUNDO_LOCKASSERT(MA_OWNED); > - SLIST_FOREACH(suptr, &semu_list, un_next) { > - struct undo *sunptr = &suptr->un_ent[0]; > - int i = 0; > - > - while (i < suptr->un_cnt) { > - if (sunptr->un_id == semid) { > - if (semnum == -1 || sunptr->un_num == > semnum) { > - suptr->un_cnt--; > - if (i < suptr->un_cnt) { > - suptr->un_ent[i] = > - > suptr->un_ent[suptr->un_cnt]; > - continue; > - } > + LIST_FOREACH_SAFE(suptr, &semu_list, un_next, suptr1) { > + sunptr = &suptr->un_ent[0]; > + for (i = 0; i < suptr->un_cnt; i++, sunptr++) { > + if (sunptr->un_id != semid) > + continue; > + if (semnum == -1 || sunptr->un_num == semnum) { > + suptr->un_cnt--; > + if (i < suptr->un_cnt) { > + suptr->un_ent[i] = > + suptr->un_ent[suptr->un_cnt]; > + continue; > } > - if (semnum != -1) > - break; > + semu_try_free(suptr); > } > - i++, sunptr++; > + if (semnum != -1) > + break; > } > } > } > > static int > -semvalid(semid, semakptr) > - int semid; > - struct semid_kernel *semakptr; > +semvalid(int semid, struct semid_kernel *semakptr) > { > > return ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 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, > int cmd, > > semakptr = &sema[semidx]; > sema_mtxp = &sema_mtx[semidx]; > + if (cmd == IPC_RMID) > + mtx_lock(&sem_mtx); > mtx_lock(sema_mtxp); > #ifdef MAC > error = 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 = cred->cr_uid; > semakptr->u.sem_perm.uid = cred->cr_uid; > - semtot -= semakptr->u.sem_nsems; > + semakptr->u.sem_perm.mode = 0; > + SEMUNDO_LOCK(); > + semundo_clear(semidx, -1); > + SEMUNDO_UNLOCK(); > +#ifdef MAC > + mac_cleanup_sysv_sem(semakptr); > +#endif > + wakeup(semakptr); > + for (i = 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 = semakptr->u.sem_base - sem; i < semtot; i++) > sem[i] = sem[i + semakptr->u.sem_nsems]; > for (i = 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 -= semakptr->u.sem_nsems; > + mtx_unlock(&sema_mtx[i]); > + } > } > - semakptr->u.sem_perm.mode = 0; > -#ifdef MAC > - mac_cleanup_sysv_sem(semakptr); > -#endif > - SEMUNDO_LOCK(); > - semundo_clear(semidx, -1); > - SEMUNDO_UNLOCK(); > - wakeup(semakptr); > + semtot -= semakptr->u.sem_nsems; > break; > > case IPC_SET: > @@ -855,6 +831,8 @@ kern_semctl(struct thread *td, int semid, int semnum, > int cmd, > > done2: > mtx_unlock(sema_mtxp); > + if (cmd == IPC_RMID) > + mtx_unlock(&sem_mtx); > if (array != 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 = 0; > int key = uap->key; > int nsems = uap->nsems; > int semflg = uap->semflg; > struct ucred *cred = td->td_ucred; > + register_t ret; > +#ifdef MAC > + int sem_found; > +#endif > > DPRINTF(("semget(0x%x, %d, 0%o)\n", key, nsems, semflg)); > if (!jail_sysvipc_allowed && jailed(td->td_ucred)) > return (ENOSYS); > > - mtx_lock(&Giant); > + mtx_lock(&sem_mtx); > if (key != IPC_PRIVATE) { > for (semid = 0; semid < seminfo.semmni; semid++) { > if ((sema[semid].u.sem_perm.mode & SEM_ALLOC) && > @@ -905,15 +885,12 @@ semget(td, uap) > error = EEXIST; > goto done2; > } > -#ifdef MAC > - error = mac_check_sysv_semget(cred, &sema[semid]); > - if (error != 0) > - goto done2; > -#endif > + sem_found = 1; > goto found; > } > } > > + sem_found = 0; > DPRINTF(("need to allocate the semid_kernel\n")); > if (key == IPC_PRIVATE || (semflg & IPC_CREAT)) { > if (nsems <= 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 = %p, next = %p\n", > sema[semid].u.sem_base, &sem[semtot])); > @@ -966,9 +942,19 @@ semget(td, uap) > } > > found: > - td->td_retval[0] = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); > + ret = IXSEQ_TO_IPCID(semid, sema[semid].u.sem_perm); > + mtx_unlock(&sem_mtx); > +#ifdef MAC > + if (error == 0) { > + if (sem_found) > + error = mac_check_sysv_semget(cred, &sema[semid]); > + else > + mac_create_sysv_sem(cred, &sema[semid]); > + } > + if (error == 0) > +#endif > + td->td_retval[0] = ret; > done2: > - mtx_unlock(&Giant); > return (error); > } > > @@ -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; > > #ifdef SEM_DEBUG > sops = NULL; > @@ -1036,7 +1021,8 @@ semop(td, uap) > error = EINVAL; > goto done2; > } > - if (semakptr->u.sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { > + seq = semakptr->u.sem_perm.seq; > + if (seq != IPCID_TO_SEQ(uap->semid)) { > error = EINVAL; > goto done2; > } > @@ -1160,8 +1146,9 @@ semop(td, uap) > /* > * Make sure that the semaphore still exists > */ > + seq = semakptr->u.sem_perm.seq; > if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || > - semakptr->u.sem_perm.seq != IPCID_TO_SEQ(uap->semid)) { > + seq != IPCID_TO_SEQ(uap->semid)) { > error = EIDRM; > goto done2; > } > @@ -1213,7 +1200,7 @@ done: > adjval = sops[i].sem_op; > if (adjval == 0) > continue; > - error = semundo_adjust(td, &suptr, semid, > + error = semundo_adjust(td, &suptr, semid, seq, > sops[i].sem_num, -adjval); > if (error == 0) > continue; > @@ -1234,7 +1221,7 @@ done: > adjval = sops[k].sem_op; > if (adjval == 0) > continue; > - if (semundo_adjust(td, &suptr, semid, > + if (semundo_adjust(td, &suptr, semid, seq, > sops[k].sem_num, adjval) != 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; > > /* > * 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 == p) { > - *supptr = SLIST_NEXT(suptr, un_next); > + LIST_FOREACH(suptr, &semu_list, un_next) { > + if (suptr->un_proc == p) > break; > - } > } > - SEMUNDO_UNLOCK(); > - > - if (suptr == NULL) > + if (suptr == NULL) { > + SEMUNDO_UNLOCK(); > return; > + } > + LIST_REMOVE(suptr, un_next); > > 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 = 0; ix < suptr->un_cnt; ix++) { > - int semid = suptr->un_ent[ix].un_id; > - int semnum = suptr->un_ent[ix].un_num; > - int adjval = suptr->un_ent[ix].un_adjval; > - struct semid_kernel *semakptr; > - struct mtx *sema_mtxp; > - > + semid = suptr->un_ent[ix].un_id; > + semnum = suptr->un_ent[ix].un_num; > + adjval = suptr->un_ent[ix].un_adjval; > + seq = suptr->un_ent[ix].un_seq; > semakptr = &sema[semid]; > sema_mtxp = &sema_mtx[semid]; > + > mtx_lock(sema_mtxp); > - SEMUNDO_LOCK(); > - if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0) > - panic("semexit - semid not allocated"); > + if ((semakptr->u.sem_perm.mode & SEM_ALLOC) == 0 || > + (semakptr->u.sem_perm.seq != seq)) { > + mtx_unlock(sema_mtxp); > + continue; > + } > if (semnum >= semakptr->u.sem_nsems) > panic("semexit - semnum out of range"); > > @@ -1336,29 +1323,26 @@ semexit_myhook(arg, p) > suptr->un_ent[ix].un_adjval, > semakptr->u.sem_base[semnum].semval)); > > - if (adjval < 0) { > - if (semakptr->u.sem_base[semnum].semval < > - -adjval) > - semakptr->u.sem_base[semnum].semval > = 0; > - else > - semakptr->u.sem_base[semnum].semval > += > - adjval; > - } else > + if (adjval < 0 && > semakptr->u.sem_base[semnum].semval < > + -adjval) > + semakptr->u.sem_base[semnum].semval = 0; > + else > semakptr->u.sem_base[semnum].semval += > adjval; > > wakeup(semakptr); > DPRINTF(("semexit: back from wakeup\n")); > mtx_unlock(sema_mtxp); > - SEMUNDO_UNLOCK(); > } > + SEMUNDO_LOCK(); > } > > /* > * Deallocate the undo vector. > */ > DPRINTF(("removing vector\n")); > - SEMUNDO_LOCK(); > suptr->un_proc = NULL; > + suptr->un_cnt = 0; > + LIST_INSERT_HEAD(&semu_free_list, suptr, un_next); > SEMUNDO_UNLOCK(); > } > >