> Date: Tue, 19 Sep 2017 05:44:27 +0000
> From: Taylor R Campbell <campbell+netbsd-tech-k...@mumble.net>
> 
> > Date: Tue, 19 Sep 2017 05:36:40 +0000
> > From: Taylor R Campbell <campbell+netbsd-tech-k...@mumble.net>
> > 
> > I've attached a small patch that might serve as a quicker stop-gap
> > (untested).  It's gross, but it doesn't change the ABI, add any header
> > files, &c.
> 
> I made sure to forget to attach it so I could keep my klutz
> credentials, but here's the standard followup with the actual
> attachment.

To increase my chances of passing the Klutz^2 certification test, I
mistyped the MIME type of the attachment as `application/pdf'.  Here
it is as plain text.  (Unless I'm going for a summa klutz laude
degree.)
diff --git a/sys/kern/subr_psref.c b/sys/kern/subr_psref.c
index c3f76ab0e743..bd393def5a4c 100644
--- a/sys/kern/subr_psref.c
+++ b/sys/kern/subr_psref.c
@@ -251,6 +251,7 @@ psref_acquire(struct psref *psref, const struct 
psref_target *target,
 
        /* Record our reference.  */
        LIST_INSERT_HEAD(&pcpu->pcpu_head, psref, psref_entry);
+       psref->psref_entry.le_prev = NULL; /* XXX see psref_release */
        psref->psref_target = target;
        psref->psref_lwp = curlwp;
        psref->psref_cpu = curcpu();
@@ -297,12 +298,33 @@ psref_release(struct psref *psref, const struct 
psref_target *target,
 
        /*
         * Block interrupts and remove the psref from the current CPU's
-        * list.  No need to percpu_getref or get the head of the list,
-        * and the caller guarantees that we are bound to a CPU anyway
-        * (as does blocking interrupts).
+        * list.  No need to percpu_getref or get the head of the list
+        * unless we turn out to be removing the head of the list, and
+        * the caller guarantees that we are bound to a CPU anyway (as
+        * does blocking interrupts).
         */
        s = splraiseipl(class->prc_iplcookie);
-       LIST_REMOVE(psref, psref_entry);
+       /* XXX begin abstraction violation */
+       /*
+        * XXX We cannot reliably use &pcpu->pcpu_head.lh_first,
+        * because percpu(9) may move it around when allocating other
+        * per-CPU storage.  But LIST_REMOVE relies on *le_prev
+        * working.  So work around it by getting the prev-pointer from
+        * the percpu if we're at the head of the list.
+        */
+       if (psref->psref_entry.le_prev != NULL) {
+               LIST_REMOVE(psref, psref_entry);
+       } else {
+               struct psref_cpu *pcpu;
+
+               if (LIST_NEXT(psref, psref_entry) != NULL)
+                       LIST_NEXT(psref, psref_entry)->psref_entry.le_prev =
+                           psref->psref_entry.le_prev;
+               pcpu = perpcu_getref(class->prc_percpu);
+               pcpu->pcpu_head.lh_first = LIST_NEXT(psref, psref_entry);
+               percpu_putref(class->prc_percpu);
+       }
+       /* XXX end abstraction violation */
        splx(s);
 
        /* If someone is waiting for users to drain, notify 'em.  */
@@ -354,6 +376,7 @@ psref_copy(struct psref *pto, const struct psref *pfrom,
 
        /* Record the new reference.  */
        LIST_INSERT_HEAD(&pcpu->pcpu_head, pto, psref_entry);
+       pto->psref_entry.le_prev = NULL; /* XXX see psref_release */
        pto->psref_target = pfrom->psref_target;
        pto->psref_lwp = curlwp;
        pto->psref_cpu = curcpu();

Reply via email to