Fix taskq code to not drop tasks when TQ_SLEEP is used.

When TQ_SLEEP is used, taskq_dispatch() should always succeed even if the
number of pending tasks is above tq->tq_maxalloc. This semantic is similar
to KM_SLEEP in kmem allocations, which also always succeed.

However, we cannot block forever otherwise there is a risk of deadlock.
Therefore, we still allow the number of pending tasks to go above
tq->tq_maxalloc with TQ_SLEEP, but we may sleep up to 1 second per task
dispatch, thereby throttling the task dispatch rate.

One of the existing splat tests was also augmented to test for this scenario.
The test would fail with the previous implementation but now it succeeds.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
Ricardo M. Correia
2010-08-02 09:24:01 +00:00
committed by Brian Behlendorf
parent 41f84a8d56
commit 26f7245c7c
2 changed files with 48 additions and 28 deletions
+24 -5
View File
@@ -296,6 +296,10 @@ splat_taskq_test3(struct file *file, void *arg)
* Then use taskq_wait() to block until all the tasks complete, then
* cross check that all the tasks ran by checking tg_arg->count which
* is incremented in the task function. Finally cleanup the taskq.
*
* First we try with a large 'maxalloc' value, then we try with a small one.
* We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
* if the number of pending tasks is above maxalloc.
*/
static void
splat_taskq_test4_func(void *arg)
@@ -307,16 +311,18 @@ splat_taskq_test4_func(void *arg)
}
static int
splat_taskq_test4(struct file *file, void *arg)
splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
int maxalloc, int nr_tasks)
{
taskq_t *tq;
splat_taskq_arg_t tq_arg;
int i, j, rc = 0;
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' creating\n",
SPLAT_TASKQ_TEST4_NAME);
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' creating "
"(%d/%d/%d)\n", SPLAT_TASKQ_TEST4_NAME, minalloc, maxalloc,
nr_tasks);
if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, maxclsyspri,
50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
"Taskq '%s' create failed\n",
SPLAT_TASKQ_TEST4_NAME);
@@ -326,7 +332,7 @@ splat_taskq_test4(struct file *file, void *arg)
tq_arg.file = file;
tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
for (i = 1; i <= 1024; i *= 2) {
for (i = 1; i <= nr_tasks; i *= 2) {
atomic_set(&tq_arg.count, 0);
splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
"Taskq '%s' function '%s' dispatched %d times\n",
@@ -364,6 +370,19 @@ out:
return rc;
}
static int splat_taskq_test4(struct file *file, void *arg)
{
int rc;
rc = splat_taskq_test4_common(file, arg, 50, INT_MAX, 1024);
if (rc)
return rc;
rc = splat_taskq_test4_common(file, arg, 1, 1, 32);
return rc;
}
/*
* Create a taskq and dispatch a specific sequence of tasks carefully
* crafted to validate the order in which tasks are processed. When