Module Name:    src
Committed By:   thorpej
Date:           Sat Apr 25 00:07:27 UTC 2020

Modified Files:
        src/sys/dev/ata: ata.c ata_subr.c atavar.h

Log Message:
Rather than creating a kthread-per-channel, use a threadpool and a
threadpool-job-per-channel for the in-thread-context work that needs
to be done (which is rare).

On one of my test systems, this results in the total number of LWPs
after multi-user boot dropping from 116 to 78.


To generate a diff of this commit:
cvs rdiff -u -r1.155 -r1.156 src/sys/dev/ata/ata.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/ata/ata_subr.c
cvs rdiff -u -r1.105 -r1.106 src/sys/dev/ata/atavar.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/ata/ata.c
diff -u src/sys/dev/ata/ata.c:1.155 src/sys/dev/ata/ata.c:1.156
--- src/sys/dev/ata/ata.c:1.155	Mon Apr 13 10:49:34 2020
+++ src/sys/dev/ata/ata.c	Sat Apr 25 00:07:27 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata.c,v 1.155 2020/04/13 10:49:34 jdolecek Exp $	*/
+/*	$NetBSD: ata.c,v 1.156 2020/04/25 00:07:27 thorpej Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.155 2020/04/13 10:49:34 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata.c,v 1.156 2020/04/25 00:07:27 thorpej Exp $");
 
 #include "opt_ata.h"
 
@@ -425,47 +425,60 @@ atabusconfig_thread(void *arg)
 }
 
 /*
- * atabus_thread:
+ * atabus_tp_job:
  *
  *	Worker thread for the ATA bus.
  */
 static void
-atabus_thread(void *arg)
+atabus_tp_job(struct threadpool_job *j)
 {
-	struct atabus_softc *sc = arg;
-	struct ata_channel *chp = sc->sc_chan;
+	struct ata_channel *chp =
+	    container_of(j, struct ata_channel, ch_tp_job);
+	struct atabus_softc *sc = device_private(chp->atabus);
 	struct ata_queue *chq = chp->ch_queue;
 	struct ata_xfer *xfer;
 	int i, rv;
 
+	/* XXX MPSAFE?? */
+	KERNEL_LOCK(1, NULL);
+
 	ata_channel_lock(chp);
-	KASSERT(ata_is_thread_run(chp));
+	chp->ch_job_thread = curlwp;	/* XXX gross */
 
-	/*
-	 * Probe the drives.  Reset type to indicate to controllers
-	 * that can re-probe that all drives must be probed..
-	 *
-	 * Note: ch_ndrives may be changed during the probe.
-	 */
-	KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
-	for (i = 0; i < chp->ch_ndrives; i++) {
-		chp->ch_drive[i].drive_flags = 0;
-		chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
+					/* XXX gross */
+	if (__predict_false(!chp->ch_initial_config_done)) {
+		/*
+		 * Probe the drives.  Reset type to indicate to controllers
+		 * that can re-probe that all drives must be probed..
+		 *
+		 * Note: ch_ndrives may be changed during the probe.
+		 */
+		KASSERT(chp->ch_ndrives == 0 || chp->ch_drive != NULL);
+		for (i = 0; i < chp->ch_ndrives; i++) {
+			chp->ch_drive[i].drive_flags = 0;
+			chp->ch_drive[i].drive_type = ATA_DRIVET_NONE;
+		}
+		chp->ch_initial_config_done = true;
+		ata_channel_unlock(chp);
+		atabusconfig(sc);
+		ata_channel_lock(chp);
 	}
-	ata_channel_unlock(chp);
 
-	atabusconfig(sc);
+#define	WORK_TO_DO							\
+	(ATACH_TH_RESCAN | ATACH_TH_RESET | ATACH_TH_DRIVE_RESET |	\
+	 ATACH_TH_RECOVERY)
 
-	ata_channel_lock(chp);
 	for (;;) {
-		if ((chp->ch_flags & (ATACH_TH_RESET | ATACH_TH_DRIVE_RESET
-		    | ATACH_TH_RECOVERY | ATACH_SHUTDOWN)) == 0 &&
-		    (chq->queue_active == 0 || chq->queue_freeze == 0)) {
-			cv_wait(&chp->ch_thr_idle, &chp->ch_lock);
-		}
 		if (chp->ch_flags & ATACH_SHUTDOWN) {
 			break;
 		}
+		if ((chp->ch_flags & WORK_TO_DO) == 0 &&
+		    (chq->queue_active == 0 || chq->queue_freeze == 0)) {
+			break;
+		}
+
+#undef WORK_TO_DO
+
 		if (chp->ch_flags & ATACH_TH_RESCAN) {
 			chp->ch_flags &= ~ATACH_TH_RESCAN;
 			ata_channel_unlock(chp);
@@ -534,10 +547,11 @@ atabus_thread(void *arg)
 			ata_channel_lock(chp);
 		}
 	}
-	chp->ch_thread = NULL;
-	cv_signal(&chp->ch_thr_idle);
+	chp->ch_job_thread = NULL;	/* XXX gross */
+	threadpool_job_done(&chp->ch_tp_job);
 	ata_channel_unlock(chp);
-	kthread_exit(0);
+
+	KERNEL_UNLOCK_ONE(NULL);
 }
 
 bool
@@ -545,7 +559,7 @@ ata_is_thread_run(struct ata_channel *ch
 {
 	KASSERT(mutex_owned(&chp->ch_lock));
 
-	return (chp->ch_thread == curlwp && !cpu_intr_p());
+	return (chp->ch_job_thread == curlwp && !cpu_intr_p());
 }
 
 static void
@@ -553,7 +567,7 @@ ata_thread_wake_locked(struct ata_channe
 {
 	KASSERT(mutex_owned(&chp->ch_lock));
 	ata_channel_freeze_locked(chp);
-	cv_signal(&chp->ch_thr_idle);
+	threadpool_schedule_job(chp->ch_tp, &chp->ch_tp_job);
 }
 
 /*
@@ -587,7 +601,6 @@ atabus_attach(device_t parent, device_t 
 	struct atabus_softc *sc = device_private(self);
 	struct ata_channel *chp = aux;
 	struct atabus_initq *initq;
-	int error;
 
 	sc->sc_chan = chp;
 
@@ -608,11 +621,15 @@ atabus_attach(device_t parent, device_t 
 	mutex_exit(&atabus_qlock);
 	config_pending_incr(sc->sc_dev);
 
-	/* XXX MPSAFE - no KTHREAD_MPSAFE, so protected by KERNEL_LOCK() */
-	if ((error = kthread_create(PRI_NONE, 0, NULL, atabus_thread, sc,
-	    &chp->ch_thread, "%s", device_xname(self))) != 0)
-		aprint_error_dev(self,
-		    "unable to create kernel thread: error %d\n", error);
+	/* Initialize our threadpool job. */
+	threadpool_job_init(&chp->ch_tp_job, atabus_tp_job,
+	    &chp->ch_lock, "%s", device_xname(self));
+
+	/* ...and run it now to scan the bus. */
+	KASSERT(chp->ch_tp != NULL);
+	ata_channel_lock(chp);
+	threadpool_schedule_job(chp->ch_tp, &chp->ch_tp_job);
+	ata_channel_unlock(chp);
 
 	if (!pmf_device_register(self, atabus_suspend, atabus_resume))
 		aprint_error_dev(self, "couldn't establish power handler\n");
@@ -666,13 +683,10 @@ atabus_detach(device_t self, int flags)
 		}
 	}
 
-	/* Shutdown the channel. */
+	/* Cancel any in-progress job and dispose of the threadpool. */
 	ata_channel_lock(chp);
 	chp->ch_flags |= ATACH_SHUTDOWN;
-	while (chp->ch_thread != NULL) {
-		cv_signal(&chp->ch_thr_idle);
-		cv_wait(&chp->ch_thr_idle, &chp->ch_lock);
-	}
+	threadpool_cancel_job(chp->ch_tp, &chp->ch_tp_job);
 	ata_channel_unlock(chp);
 
 	atabus_free_drives(chp);
@@ -1588,7 +1602,7 @@ ata_thread_run(struct ata_channel *chp, 
 		ata_channel_freeze_locked(chp);
 		chp->ch_flags |= type;
 
-		cv_signal(&chp->ch_thr_idle);
+		threadpool_schedule_job(chp->ch_tp, &chp->ch_tp_job);
 		return;
 	}
 
@@ -1654,7 +1668,7 @@ ata_thread_run(struct ata_channel *chp, 
 	ata_channel_thaw_locked(chp);
 
 	/* Signal the thread in case there is an xfer to run */
-	cv_signal(&chp->ch_thr_idle);
+	threadpool_schedule_job(chp->ch_tp, &chp->ch_tp_job);
 }
 
 int
@@ -2285,7 +2299,7 @@ atabus_rescan(device_t self, const char 
 
 	ata_channel_lock(chp);
 	chp->ch_flags |= ATACH_TH_RESCAN;
-	cv_signal(&chp->ch_thr_idle);
+	threadpool_schedule_job(chp->ch_tp, &chp->ch_tp_job);
 	ata_channel_unlock(chp);
 
 	return 0;

Index: src/sys/dev/ata/ata_subr.c
diff -u src/sys/dev/ata/ata_subr.c:1.9 src/sys/dev/ata/ata_subr.c:1.10
--- src/sys/dev/ata/ata_subr.c:1.9	Sat Apr  4 22:30:02 2020
+++ src/sys/dev/ata/ata_subr.c	Sat Apr 25 00:07:27 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: ata_subr.c,v 1.9 2020/04/04 22:30:02 jdolecek Exp $	*/
+/*	$NetBSD: ata_subr.c,v 1.10 2020/04/25 00:07:27 thorpej Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.  All rights reserved.
@@ -25,7 +25,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.9 2020/04/04 22:30:02 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ata_subr.c,v 1.10 2020/04/25 00:07:27 thorpej Exp $");
 
 #include "opt_ata.h"
 
@@ -195,8 +195,11 @@ ata_queue_free(struct ata_queue *chq)
 void
 ata_channel_init(struct ata_channel *chp)
 {
+	int error __diagused;
+
 	mutex_init(&chp->ch_lock, MUTEX_DEFAULT, IPL_BIO);
-	cv_init(&chp->ch_thr_idle, "atath");
+	error = threadpool_get(&chp->ch_tp, PRI_NONE);
+	KASSERT(error == 0);			/* XXX */
 
 	callout_init(&chp->c_timo_callout, 0); 	/* XXX MPSAFE */
 
@@ -220,7 +223,7 @@ ata_channel_destroy(struct ata_channel *
 	mutex_exit(&chp->ch_lock);
 
 	mutex_destroy(&chp->ch_lock);
-	cv_destroy(&chp->ch_thr_idle);
+	threadpool_put(chp->ch_tp, PRI_NONE);
 }
 
 void

Index: src/sys/dev/ata/atavar.h
diff -u src/sys/dev/ata/atavar.h:1.105 src/sys/dev/ata/atavar.h:1.106
--- src/sys/dev/ata/atavar.h:1.105	Mon Apr 13 10:49:34 2020
+++ src/sys/dev/ata/atavar.h	Sat Apr 25 00:07:27 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: atavar.h,v 1.105 2020/04/13 10:49:34 jdolecek Exp $	*/
+/*	$NetBSD: atavar.h,v 1.106 2020/04/25 00:07:27 thorpej Exp $	*/
 
 /*
  * Copyright (c) 1998, 2001 Manuel Bouyer.
@@ -28,6 +28,7 @@
 #define	_DEV_ATA_ATAVAR_H_
 
 #include <sys/lock.h>
+#include <sys/threadpool.h>
 #include <sys/queue.h>
 
 #include <dev/ata/ataconf.h>
@@ -436,9 +437,14 @@ struct ata_channel {
 	 */
 	struct ata_queue *ch_queue;
 
-	/* The channel kernel thread */
-	struct lwp *ch_thread;
-	kcondvar_t ch_thr_idle;		/* thread waiting for work */
+	/*
+	 * Threadpool job scheduled whenever we need special work done in
+	 * thread context.
+	 */
+	struct threadpool *ch_tp;
+	struct threadpool_job ch_tp_job;
+	bool ch_initial_config_done;	/* XXX gross */
+	struct lwp *ch_job_thread;	/* XXX gross */
 
 	/* Number of sata PMP ports, if any */
 	int ch_satapmp_nports;

Reply via email to