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

next in thread | previous in thread | raw e-mail | index | archive | help
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 <kostikbel@gmail.com>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 <Address 0x104 out of bounds>)
> >     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();
>  }
>
>



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