From 03d0445c1692534218893d0f76a5232a12769935 Mon Sep 17 00:00:00 2001 From: ken Date: Wed, 3 Sep 2003 04:46:28 +0000 Subject: Move dynamic sysctl(8) variable creation for the cd(4) and da(4) drivers out of cdregister() and daregister(), which are run from interrupt context. The sysctl code does blocking mallocs (M_WAITOK), which causes problems if malloc(9) actually needs to sleep. The eventual fix for this issue will involve moving the CAM probe process inside a kernel thread. For now, though, I have fixed the issue by moving dynamic sysctl variable creation for these two drivers to a task queue running in a kernel thread. The existing task queues (taskqueue_swi and taskqueue_swi_giant) run in software interrupt handlers, which wouldn't fix the problem at hand. So I have created a new task queue, taskqueue_thread, that runs inside a kernel thread. (It also runs outside of Giant -- clients must explicitly acquire and release Giant in their taskqueue functions.) scsi_cd.c: Remove sysctl variable creation code from cdregister(), and move it to a new function, cdsysctlinit(). Queue cdsysctlinit() to the taskqueue_thread taskqueue once we have fully registered the cd(4) driver instance. scsi_da.c: Remove sysctl variable creation code from daregister(), and move it to move it to a new function, dasysctlinit(). Queue dasysctlinit() to the taskqueue_thread taskqueue once we have fully registered the da(4) instance. taskqueue.h: Declare the new taskqueue_thread taskqueue, update some comments. subr_taskqueue.c: Create the new kernel thread taskqueue. This taskqueue runs outside of Giant, so any functions queued to it would need to explicitly acquire/release Giant if they need it. cd.4: Update the cd(4) man page to talk about the minimum command size sysctl/loader tunable. Also note that the changer variables are available as loader tunables as well. da.4: Update the da(4) man page to cover the retry_count, default_timeout and minimum_cmd_size sysctl variables/loader tunables. Remove references to /dev/r???, they aren't used any longer. cd.9: Update the cd(9) man page to describe the CD_Q_10_BYTE_ONLY quirk. taskqueue.9: Update the taskqueue(9) man page to describe the new thread task queue, and the taskqueue_swi_giant queue. MFC after: 3 days --- sys/kern/subr_taskqueue.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'sys/kern/subr_taskqueue.c') diff --git a/sys/kern/subr_taskqueue.c b/sys/kern/subr_taskqueue.c index fa32be6..bb1f1b6 100644 --- a/sys/kern/subr_taskqueue.c +++ b/sys/kern/subr_taskqueue.c @@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include static MALLOC_DEFINE(M_TASKQUEUE, "taskqueue", "Task Queues"); @@ -44,6 +46,7 @@ static STAILQ_HEAD(taskqueue_list, taskqueue) taskqueue_queues; static void *taskqueue_ih; static void *taskqueue_giant_ih; static struct mtx taskqueue_queues_mutex; +static struct proc *taskqueue_thread_proc; struct taskqueue { STAILQ_ENTRY(taskqueue) tq_link; @@ -233,6 +236,31 @@ taskqueue_swi_giant_run(void *dummy) taskqueue_run(taskqueue_swi_giant); } +static void +taskqueue_kthread(void *arg) +{ + struct mtx kthread_mutex; + + bzero(&kthread_mutex, sizeof(kthread_mutex)); + + mtx_init(&kthread_mutex, "taskqueue kthread", NULL, MTX_DEF); + + mtx_lock(&kthread_mutex); + + for (;;) { + mtx_unlock(&kthread_mutex); + taskqueue_run(taskqueue_thread); + mtx_lock(&kthread_mutex); + msleep(&taskqueue_thread, &kthread_mutex, PWAIT, "tqthr", 0); + } +} + +static void +taskqueue_thread_enqueue(void *context) +{ + wakeup(&taskqueue_thread); +} + TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, 0, swi_add(NULL, "task queue", taskqueue_swi_run, NULL, SWI_TQ, INTR_MPSAFE, &taskqueue_ih)); @@ -240,3 +268,7 @@ TASKQUEUE_DEFINE(swi, taskqueue_swi_enqueue, 0, TASKQUEUE_DEFINE(swi_giant, taskqueue_swi_giant_enqueue, 0, swi_add(NULL, "Giant task queue", taskqueue_swi_giant_run, NULL, SWI_TQ_GIANT, 0, &taskqueue_giant_ih)); + +TASKQUEUE_DEFINE(thread, taskqueue_thread_enqueue, 0, + kthread_create(taskqueue_kthread, NULL, + &taskqueue_thread_proc, RFNOWAIT, 0, "taskqueue")); -- cgit v1.1