tech-kern archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: RFC: PERCPU_LIST to fix PR kern/52515



> Date: Tue, 19 Sep 2017 05:44:27 +0000
> From: Taylor R Campbell <campbell+netbsd-tech-kern%mumble.net@localhost>
> 
> > Date: Tue, 19 Sep 2017 05:36:40 +0000
> > From: Taylor R Campbell <campbell+netbsd-tech-kern%mumble.net@localhost>
> > 
> > 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();


Home | Main Index | Thread Index | Old Index