On 15/02/20(Sat) 16:56, Visa Hankala wrote:
> When I added the knote_acquire() call in kqueue_register(), I overlooked
> the fact that the knote could be modified by a (soft) interrupt.
> Interrupts have to be blocked when changing kn_status. Otherwise the
> state could become confused.

Can the same knote be modified by different interrupt handlers or are we
just considering a race between process and interrupt contexts?

> The diff below adds splhigh() where kn_status is modified. This also
> ensures that the steps of knote_activate() run as an uninterrupted
> sequence. As a consequence, knote_enqueue() and knote_dequeue() can rely
> on the caller to raise the spl.

Do you think it would make sense to document which fields required a SPL
protection just like we started doing with locks?
 
> OK?

ok mpi@

> Index: kern/kern_event.c
> ===================================================================
> RCS file: src/sys/kern/kern_event.c,v
> retrieving revision 1.124
> diff -u -p -r1.124 kern_event.c
> --- kern/kern_event.c 14 Feb 2020 16:50:25 -0000      1.124
> +++ kern/kern_event.c 15 Feb 2020 16:52:41 -0000
> @@ -312,8 +312,11 @@ filt_proc(struct knote *kn, long hint)
>        */
>       if (event == NOTE_EXIT) {
>               struct process *pr = kn->kn_ptr.p_process;
> +             int s;
>  
> +             s = splhigh();
>               kn->kn_status |= KN_DETACHED;
> +             splx(s);
>               kn->kn_flags |= (EV_EOF | EV_ONESHOT);
>               kn->kn_data = W_EXITCODE(pr->ps_xexit, pr->ps_xsig);
>               SLIST_REMOVE(&pr->ps_klist, kn, knote, kn_selnext);
> @@ -712,13 +715,16 @@ again:
>               SLIST_FOREACH(kn, list, kn_link) {
>                       if (kev->filter == kn->kn_filter &&
>                           kev->ident == kn->kn_id) {
> -                             if (knote_acquire(kn) == 0) {
> +                             s = splhigh();
> +                             if (!knote_acquire(kn)) {
> +                                     splx(s);
>                                       if (fp != NULL) {
>                                               FRELE(fp, p);
>                                               fp = NULL;
>                                       }
>                                       goto again;
>                               }
> +                             splx(s);
>                               break;
>                       }
>               }
> @@ -820,7 +826,9 @@ again:
>               splx(s);
>       }
>  
> +     s = splhigh();
>       knote_release(kn);
> +     splx(s);
>  done:
>       if (fp != NULL)
>               FRELE(fp, p);
> @@ -1157,6 +1165,7 @@ kqueue_expand_list(struct kqueue *kq, in
>  int
>  knote_acquire(struct knote *kn)
>  {
> +     splassert(IPL_HIGH);
>       KASSERT(kn->kn_filter != EVFILT_MARKER);
>  
>       if (kn->kn_status & KN_PROCESSING) {
> @@ -1175,6 +1184,7 @@ knote_acquire(struct knote *kn)
>  void
>  knote_release(struct knote *kn)
>  {
> +     splassert(IPL_HIGH);
>       KASSERT(kn->kn_filter != EVFILT_MARKER);
>       KASSERT(kn->kn_status & KN_PROCESSING);
>  
> @@ -1192,9 +1202,13 @@ knote_release(struct knote *kn)
>  void
>  knote_activate(struct knote *kn)
>  {
> +     int s;
> +
> +     s = splhigh();
>       kn->kn_status |= KN_ACTIVE;
>       if ((kn->kn_status & (KN_QUEUED | KN_DISABLED)) == 0)
>               knote_enqueue(kn);
> +     splx(s);
>  }
>  
>  /*
> @@ -1217,10 +1231,15 @@ void
>  knote_remove(struct proc *p, struct klist *list)
>  {
>       struct knote *kn;
> +     int s;
>  
>       while ((kn = SLIST_FIRST(list)) != NULL) {
> -             if (!knote_acquire(kn))
> +             s = splhigh();
> +             if (!knote_acquire(kn)) {
> +                     splx(s);
>                       continue;
> +             }
> +             splx(s);
>               kn->kn_fop->f_detach(kn);
>               knote_drop(kn, p);
>       }
> @@ -1297,6 +1316,7 @@ knote_drop(struct knote *kn, struct proc
>  {
>       struct kqueue *kq = kn->kn_kq;
>       struct klist *list;
> +     int s;
>  
>       KASSERT(kn->kn_filter != EVFILT_MARKER);
>  
> @@ -1306,12 +1326,14 @@ knote_drop(struct knote *kn, struct proc
>               list = &kq->kq_knhash[KN_HASH(kn->kn_id, kq->kq_knhashmask)];
>  
>       SLIST_REMOVE(list, kn, knote, kn_link);
> +     s = splhigh();
>       if (kn->kn_status & KN_QUEUED)
>               knote_dequeue(kn);
>       if (kn->kn_status & KN_WAITING) {
>               kn->kn_status &= ~KN_WAITING;
>               wakeup(kn);
>       }
> +     splx(s);
>       if (kn->kn_fop->f_isfd)
>               FRELE(kn->kn_fp, p);
>       pool_put(&knote_pool, kn);
> @@ -1322,8 +1344,8 @@ void
>  knote_enqueue(struct knote *kn)
>  {
>       struct kqueue *kq = kn->kn_kq;
> -     int s = splhigh();
>  
> +     splassert(IPL_HIGH);
>       KASSERT(kn->kn_filter != EVFILT_MARKER);
>       KASSERT((kn->kn_status & KN_QUEUED) == 0);
>  
> @@ -1332,7 +1354,6 @@ knote_enqueue(struct knote *kn)
>       kn->kn_status |= KN_QUEUED;
>       kq->kq_count++;
>       kqueue_check(kq);
> -     splx(s);
>       kqueue_wakeup(kq);
>  }
>  
> @@ -1340,8 +1361,8 @@ void
>  knote_dequeue(struct knote *kn)
>  {
>       struct kqueue *kq = kn->kn_kq;
> -     int s = splhigh();
>  
> +     splassert(IPL_HIGH);
>       KASSERT(kn->kn_filter != EVFILT_MARKER);
>       KASSERT(kn->kn_status & KN_QUEUED);
>  
> @@ -1350,13 +1371,13 @@ knote_dequeue(struct knote *kn)
>       kn->kn_status &= ~KN_QUEUED;
>       kq->kq_count--;
>       kqueue_check(kq);
> -     splx(s);
>  }
>  
>  void
>  klist_invalidate(struct klist *list)
>  {
>       struct knote *kn;
> +     int s;
>  
>       /*
>        * NET_LOCK() must not be held because it can block another thread
> @@ -1364,12 +1385,16 @@ klist_invalidate(struct klist *list)
>        */
>       NET_ASSERT_UNLOCKED();
>  
> +     s = splhigh();
>       while ((kn = SLIST_FIRST(list)) != NULL) {
> -             if (knote_acquire(kn) == 0)
> +             if (!knote_acquire(kn))
>                       continue;
> +             splx(s);
>               kn->kn_fop->f_detach(kn);
>               kn->kn_fop = &dead_filtops;
>               knote_activate(kn);
> +             s = splhigh();
>               knote_release(kn);
>       }
> +     splx(s);
>  }
> 

Reply via email to