]> git.proxmox.com Git - mirror_spl-debian.git/blame - module/splat/splat-taskq.c
Fix a typo referencing an incorrect symbol
[mirror_spl-debian.git] / module / splat / splat-taskq.c
CommitLineData
716154c5
BB
1/*****************************************************************************\
2 * Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3 * Copyright (C) 2007 The Regents of the University of California.
4 * Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5 * Written by Brian Behlendorf <behlendorf1@llnl.gov>.
715f6251 6 * UCRL-CODE-235197
7 *
716154c5
BB
8 * This file is part of the SPL, Solaris Porting Layer.
9 * For details, see <http://github.com/behlendorf/spl/>.
10 *
11 * The SPL is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
715f6251 15 *
716154c5 16 * The SPL is distributed in the hope that it will be useful, but WITHOUT
715f6251 17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
716154c5
BB
22 * with the SPL. If not, see <http://www.gnu.org/licenses/>.
23 *****************************************************************************
24 * Solaris Porting LAyer Tests (SPLAT) Task Queue Tests.
25\*****************************************************************************/
715f6251 26
7c50328b 27#include "splat-internal.h"
f1ca4da6 28
7c50328b 29#define SPLAT_TASKQ_NAME "taskq"
30#define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
f1ca4da6 31
7c50328b 32#define SPLAT_TASKQ_TEST1_ID 0x0201
33#define SPLAT_TASKQ_TEST1_NAME "single"
34#define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task"
f1ca4da6 35
5562e5d1 36#define SPLAT_TASKQ_TEST2_ID 0x0202
7c50328b 37#define SPLAT_TASKQ_TEST2_NAME "multiple"
38#define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
f1ca4da6 39
5562e5d1 40#define SPLAT_TASKQ_TEST3_ID 0x0203
e9cb2b4f
BB
41#define SPLAT_TASKQ_TEST3_NAME "system"
42#define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
43
5562e5d1 44#define SPLAT_TASKQ_TEST4_ID 0x0204
7257ec41
BB
45#define SPLAT_TASKQ_TEST4_NAME "wait"
46#define SPLAT_TASKQ_TEST4_DESC "Multiple task waiting"
47
5562e5d1
BB
48#define SPLAT_TASKQ_TEST5_ID 0x0205
49#define SPLAT_TASKQ_TEST5_NAME "order"
50#define SPLAT_TASKQ_TEST5_DESC "Correct task ordering"
51
55f10ae5
NB
52#define SPLAT_TASKQ_TEST6_ID 0x0206
53#define SPLAT_TASKQ_TEST6_NAME "front"
54#define SPLAT_TASKQ_TEST6_DESC "Correct ordering with TQ_FRONT flag"
55
5562e5d1
BB
56#define SPLAT_TASKQ_ORDER_MAX 8
57
7c50328b 58typedef struct splat_taskq_arg {
f1ca4da6 59 int flag;
60 int id;
7257ec41 61 atomic_t count;
5562e5d1
BB
62 int order[SPLAT_TASKQ_ORDER_MAX];
63 spinlock_t lock;
f1ca4da6 64 struct file *file;
65 const char *name;
7c50328b 66} splat_taskq_arg_t;
f1ca4da6 67
5562e5d1
BB
68typedef struct splat_taskq_id {
69 int id;
70 splat_taskq_arg_t *arg;
71} splat_taskq_id_t;
72
73/*
74 * Create a taskq, queue a task, wait until task completes, ensure
75 * task ran properly, cleanup taskq.
f1ca4da6 76 */
77static void
e9cb2b4f 78splat_taskq_test13_func(void *arg)
f1ca4da6 79{
7c50328b 80 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
f1ca4da6 81
82 ASSERT(tq_arg);
7c50328b 83 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 84 "Taskq '%s' function '%s' setting flag\n",
e9cb2b4f 85 tq_arg->name, sym2str(splat_taskq_test13_func));
f1ca4da6 86 tq_arg->flag = 1;
87}
88
89static int
7c50328b 90splat_taskq_test1(struct file *file, void *arg)
f1ca4da6 91{
92 taskq_t *tq;
93 taskqid_t id;
7c50328b 94 splat_taskq_arg_t tq_arg;
f1ca4da6 95
7c50328b 96 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n",
97 SPLAT_TASKQ_TEST1_NAME);
bcd68186 98 if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri,
99 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
7c50328b 100 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 101 "Taskq '%s' create failed\n",
7c50328b 102 SPLAT_TASKQ_TEST1_NAME);
f1ca4da6 103 return -EINVAL;
104 }
105
106 tq_arg.flag = 0;
107 tq_arg.id = 0;
108 tq_arg.file = file;
7c50328b 109 tq_arg.name = SPLAT_TASKQ_TEST1_NAME;
f1ca4da6 110
7c50328b 111 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 112 "Taskq '%s' function '%s' dispatching\n",
e9cb2b4f
BB
113 tq_arg.name, sym2str(splat_taskq_test13_func));
114 if ((id = taskq_dispatch(tq, splat_taskq_test13_func,
bcd68186 115 &tq_arg, TQ_SLEEP)) == 0) {
7c50328b 116 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
f1ca4da6 117 "Taskq '%s' function '%s' dispatch failed\n",
e9cb2b4f 118 tq_arg.name, sym2str(splat_taskq_test13_func));
4098c921 119 taskq_destroy(tq);
f1ca4da6 120 return -EINVAL;
121 }
122
7c50328b 123 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
f1ca4da6 124 tq_arg.name);
125 taskq_wait(tq);
7c50328b 126 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
f1ca4da6 127 tq_arg.name);
4098c921 128 taskq_destroy(tq);
f1ca4da6 129
130 return (tq_arg.flag) ? 0 : -EINVAL;
131}
132
5562e5d1
BB
133/*
134 * Create multiple taskq's, each with multiple tasks, wait until
135 * all tasks complete, ensure all tasks ran properly and in the
136 * correct order. Run order must be the same as the order submitted
137 * because we only have 1 thread per taskq. Finally cleanup the taskq.
f1ca4da6 138 */
139static void
7c50328b 140splat_taskq_test2_func1(void *arg)
f1ca4da6 141{
7c50328b 142 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
f1ca4da6 143
144 ASSERT(tq_arg);
7c50328b 145 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 146 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
147 tq_arg->name, tq_arg->id,
7c50328b 148 sym2str(splat_taskq_test2_func1),
f1ca4da6 149 tq_arg->flag * 2, tq_arg->flag);
150 tq_arg->flag *= 2;
151}
152
153static void
7c50328b 154splat_taskq_test2_func2(void *arg)
f1ca4da6 155{
7c50328b 156 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
f1ca4da6 157
158 ASSERT(tq_arg);
7c50328b 159 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 160 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
161 tq_arg->name, tq_arg->id,
7c50328b 162 sym2str(splat_taskq_test2_func2),
f1ca4da6 163 tq_arg->flag + 1, tq_arg->flag);
164 tq_arg->flag += 1;
165}
166
167#define TEST2_TASKQS 8
5562e5d1 168#define TEST2_THREADS_PER_TASKQ 1
bcd68186 169
f1ca4da6 170static int
7c50328b 171splat_taskq_test2(struct file *file, void *arg) {
f1ca4da6 172 taskq_t *tq[TEST2_TASKQS] = { NULL };
173 taskqid_t id;
7c50328b 174 splat_taskq_arg_t tq_args[TEST2_TASKQS];
f1ca4da6 175 int i, rc = 0;
176
177 for (i = 0; i < TEST2_TASKQS; i++) {
178
7c50328b 179 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' "
180 "creating\n", SPLAT_TASKQ_TEST2_NAME, i);
181 if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
bcd68186 182 TEST2_THREADS_PER_TASKQ,
183 maxclsyspri, 50, INT_MAX,
184 TASKQ_PREPOPULATE)) == NULL) {
7c50328b 185 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 186 "Taskq '%s/%d' create failed\n",
7c50328b 187 SPLAT_TASKQ_TEST2_NAME, i);
f1ca4da6 188 rc = -EINVAL;
189 break;
190 }
191
192 tq_args[i].flag = i;
193 tq_args[i].id = i;
194 tq_args[i].file = file;
7c50328b 195 tq_args[i].name = SPLAT_TASKQ_TEST2_NAME;
f1ca4da6 196
7c50328b 197 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 198 "Taskq '%s/%d' function '%s' dispatching\n",
7c50328b 199 tq_args[i].name, tq_args[i].id,
200 sym2str(splat_taskq_test2_func1));
f1ca4da6 201 if ((id = taskq_dispatch(
bcd68186 202 tq[i], splat_taskq_test2_func1,
203 &tq_args[i], TQ_SLEEP)) == 0) {
7c50328b 204 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 205 "Taskq '%s/%d' function '%s' dispatch "
206 "failed\n", tq_args[i].name, tq_args[i].id,
7c50328b 207 sym2str(splat_taskq_test2_func1));
f1ca4da6 208 rc = -EINVAL;
209 break;
210 }
211
7c50328b 212 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 213 "Taskq '%s/%d' function '%s' dispatching\n",
7c50328b 214 tq_args[i].name, tq_args[i].id,
215 sym2str(splat_taskq_test2_func2));
f1ca4da6 216 if ((id = taskq_dispatch(
bcd68186 217 tq[i], splat_taskq_test2_func2,
218 &tq_args[i], TQ_SLEEP)) == 0) {
7c50328b 219 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 220 "Taskq '%s/%d' function '%s' dispatch failed\n",
221 tq_args[i].name, tq_args[i].id,
7c50328b 222 sym2str(splat_taskq_test2_func2));
f1ca4da6 223 rc = -EINVAL;
224 break;
225 }
226 }
227
228 /* When rc is set we're effectively just doing cleanup here, so
229 * ignore new errors in that case. They just cause noise. */
230 for (i = 0; i < TEST2_TASKQS; i++) {
231 if (tq[i] != NULL) {
7c50328b 232 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 233 "Taskq '%s/%d' waiting\n",
234 tq_args[i].name, tq_args[i].id);
235 taskq_wait(tq[i]);
7c50328b 236 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 237 "Taskq '%s/%d; destroying\n",
238 tq_args[i].name, tq_args[i].id);
4098c921 239 taskq_destroy(tq[i]);
f1ca4da6 240
241 if (!rc && tq_args[i].flag != ((i * 2) + 1)) {
7c50328b 242 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 243 "Taskq '%s/%d' processed tasks "
244 "out of order; %d != %d\n",
245 tq_args[i].name, tq_args[i].id,
246 tq_args[i].flag, i * 2 + 1);
247 rc = -EINVAL;
248 } else {
7c50328b 249 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
f1ca4da6 250 "Taskq '%s/%d' processed tasks "
251 "in the correct order; %d == %d\n",
252 tq_args[i].name, tq_args[i].id,
253 tq_args[i].flag, i * 2 + 1);
254 }
255 }
256 }
257
258 return rc;
259}
260
5562e5d1
BB
261/*
262 * Use the global system task queue with a single task, wait until task
263 * completes, ensure task ran properly.
e9cb2b4f
BB
264 */
265static int
266splat_taskq_test3(struct file *file, void *arg)
267{
268 taskqid_t id;
269 splat_taskq_arg_t tq_arg;
270
271 tq_arg.flag = 0;
272 tq_arg.id = 0;
273 tq_arg.file = file;
274 tq_arg.name = SPLAT_TASKQ_TEST3_NAME;
275
276 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
277 "Taskq '%s' function '%s' dispatching\n",
278 tq_arg.name, sym2str(splat_taskq_test13_func));
279 if ((id = taskq_dispatch(system_taskq, splat_taskq_test13_func,
280 &tq_arg, TQ_SLEEP)) == 0) {
281 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
282 "Taskq '%s' function '%s' dispatch failed\n",
283 tq_arg.name, sym2str(splat_taskq_test13_func));
284 return -EINVAL;
285 }
286
287 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n",
288 tq_arg.name);
289 taskq_wait(system_taskq);
290
291 return (tq_arg.flag) ? 0 : -EINVAL;
292}
293
5562e5d1
BB
294/*
295 * Create a taskq and dispatch a large number of tasks to the queue.
296 * Then use taskq_wait() to block until all the tasks complete, then
297 * cross check that all the tasks ran by checking tg_arg->count which
298 * is incremented in the task function. Finally cleanup the taskq.
26f7245c
RC
299 *
300 * First we try with a large 'maxalloc' value, then we try with a small one.
301 * We should not drop tasks when TQ_SLEEP is used in taskq_dispatch(), even
302 * if the number of pending tasks is above maxalloc.
5562e5d1 303 */
7257ec41
BB
304static void
305splat_taskq_test4_func(void *arg)
306{
307 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
308 ASSERT(tq_arg);
309
310 atomic_inc(&tq_arg->count);
311}
312
313static int
26f7245c
RC
314splat_taskq_test4_common(struct file *file, void *arg, int minalloc,
315 int maxalloc, int nr_tasks)
7257ec41
BB
316{
317 taskq_t *tq;
318 splat_taskq_arg_t tq_arg;
319 int i, j, rc = 0;
320
26f7245c
RC
321 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' creating "
322 "(%d/%d/%d)\n", SPLAT_TASKQ_TEST4_NAME, minalloc, maxalloc,
323 nr_tasks);
7257ec41 324 if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, maxclsyspri,
26f7245c 325 minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) {
7257ec41
BB
326 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
327 "Taskq '%s' create failed\n",
328 SPLAT_TASKQ_TEST4_NAME);
329 return -EINVAL;
330 }
331
332 tq_arg.file = file;
333 tq_arg.name = SPLAT_TASKQ_TEST4_NAME;
334
26f7245c 335 for (i = 1; i <= nr_tasks; i *= 2) {
7257ec41
BB
336 atomic_set(&tq_arg.count, 0);
337 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
338 "Taskq '%s' function '%s' dispatched %d times\n",
339 tq_arg.name, sym2str(splat_taskq_test4_func), i);
340
341 for (j = 0; j < i; j++) {
342 if ((taskq_dispatch(tq, splat_taskq_test4_func,
343 &tq_arg, TQ_SLEEP)) == 0) {
344 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME,
345 "Taskq '%s' function '%s' dispatch "
346 "%d failed\n", tq_arg.name,
e05bec80 347 sym2str(splat_taskq_test4_func), j);
7257ec41
BB
348 rc = -EINVAL;
349 goto out;
350 }
351 }
352
353 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
354 "waiting for %d dispatches\n", tq_arg.name, i);
355 taskq_wait(tq);
356 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' "
357 "%d/%d dispatches finished\n", tq_arg.name,
358 atomic_read(&tq_arg.count), i);
359 if (atomic_read(&tq_arg.count) != i) {
360 rc = -ERANGE;
361 goto out;
362
363 }
364 }
365out:
366 splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' destroying\n",
367 tq_arg.name);
368 taskq_destroy(tq);
369
370 return rc;
371}
372
26f7245c
RC
373static int splat_taskq_test4(struct file *file, void *arg)
374{
375 int rc;
376
377 rc = splat_taskq_test4_common(file, arg, 50, INT_MAX, 1024);
378 if (rc)
379 return rc;
380
381 rc = splat_taskq_test4_common(file, arg, 1, 1, 32);
382
383 return rc;
384}
385
5562e5d1
BB
386/*
387 * Create a taskq and dispatch a specific sequence of tasks carefully
388 * crafted to validate the order in which tasks are processed. When
389 * there are multiple worker threads each thread will process the
390 * next pending task as soon as it completes its current task. This
391 * means that tasks do not strictly complete in order in which they
392 * were dispatched (increasing task id). This is fine but we need to
393 * verify that taskq_wait_id() blocks until the passed task id and all
394 * lower task ids complete. We do this by dispatching the following
395 * specific sequence of tasks each of which block for N time units.
396 * We then use taskq_wait_id() to unblock at specific task id and
397 * verify the only the expected task ids have completed and in the
398 * correct order. The two cases of interest are:
399 *
400 * 1) Task ids larger than the waited for task id can run and
401 * complete as long as there is an available worker thread.
402 * 2) All task ids lower than the waited one must complete before
403 * unblocking even if the waited task id itself has completed.
404 *
405 * The following table shows each task id and how they will be
406 * scheduled. Each rows represent one time unit and each column
407 * one of the three worker threads. The places taskq_wait_id()
408 * must unblock for a specific id are identified as well as the
409 * task ids which must have completed and their order.
410 *
411 * +-----+ <--- taskq_wait_id(tq, 8) unblocks
55f10ae5 412 * | | Required Completion Order: 1,2,4,5,3,8,6,7
5562e5d1
BB
413 * +-----+ |
414 * | | |
415 * | | +-----+
416 * | | | 8 |
417 * | | +-----+ <--- taskq_wait_id(tq, 3) unblocks
55f10ae5 418 * | | 7 | | Required Completion Order: 1,2,4,5,3
5562e5d1
BB
419 * | +-----+ |
420 * | 6 | | |
421 * +-----+ | |
422 * | | 5 | |
423 * | +-----+ |
424 * | 4 | | |
425 * +-----+ | |
426 * | 1 | 2 | 3 |
427 * +-----+-----+-----+
428 *
429 */
430static void
431splat_taskq_test5_func(void *arg)
432{
433 splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
434 splat_taskq_arg_t *tq_arg = tq_id->arg;
435 int factor;
436
437 /* Delays determined by above table */
438 switch (tq_id->id) {
439 default: factor = 0; break;
440 case 1: case 8: factor = 1; break;
441 case 2: case 4: case 5: factor = 2; break;
442 case 6: case 7: factor = 4; break;
443 case 3: factor = 5; break;
444 }
445
446 msleep(factor * 100);
447 splat_vprint(tq_arg->file, tq_arg->name,
448 "Taskqid %d complete for taskq '%s'\n",
449 tq_id->id, tq_arg->name);
450
451 spin_lock(&tq_arg->lock);
452 tq_arg->order[tq_arg->flag] = tq_id->id;
453 tq_arg->flag++;
454 spin_unlock(&tq_arg->lock);
455}
456
457static int
55f10ae5 458splat_taskq_test_order(splat_taskq_arg_t *tq_arg, int *order)
5562e5d1
BB
459{
460 int i, j;
461
462 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
463 if (tq_arg->order[i] != order[i]) {
55f10ae5 464 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
465 "Taskq '%s' incorrect completion "
466 "order\n", tq_arg->name);
55f10ae5 467 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
468 "%s", "Expected { ");
469
470 for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
471 splat_print(tq_arg->file, "%d ", order[j]);
472
473 splat_print(tq_arg->file, "%s", "}\n");
55f10ae5 474 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
475 "%s", "Got { ");
476
477 for (j = 0; j < SPLAT_TASKQ_ORDER_MAX; j++)
478 splat_print(tq_arg->file, "%d ",
479 tq_arg->order[j]);
480
481 splat_print(tq_arg->file, "%s", "}\n");
482 return -EILSEQ;
483 }
484 }
485
55f10ae5 486 splat_vprint(tq_arg->file, tq_arg->name,
5562e5d1
BB
487 "Taskq '%s' validated correct completion order\n",
488 tq_arg->name);
489
490 return 0;
491}
492
493static int
494splat_taskq_test5(struct file *file, void *arg)
495{
496 taskq_t *tq;
497 taskqid_t id;
498 splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
499 splat_taskq_arg_t tq_arg;
500 int order1[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,0,0,0 };
501 int order2[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,8,6,7 };
502 int i, rc = 0;
503
504 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' creating\n",
505 SPLAT_TASKQ_TEST5_NAME);
506 if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, maxclsyspri,
507 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
508 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
509 "Taskq '%s' create failed\n",
510 SPLAT_TASKQ_TEST5_NAME);
511 return -EINVAL;
512 }
513
514 tq_arg.flag = 0;
515 memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
516 spin_lock_init(&tq_arg.lock);
517 tq_arg.file = file;
518 tq_arg.name = SPLAT_TASKQ_TEST5_NAME;
519
520 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
521 tq_id[i].id = i + 1;
522 tq_id[i].arg = &tq_arg;
523
524 if ((id = taskq_dispatch(tq, splat_taskq_test5_func,
525 &tq_id[i], TQ_SLEEP)) == 0) {
526 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
527 "Taskq '%s' function '%s' dispatch failed\n",
528 tq_arg.name, sym2str(splat_taskq_test5_func));
529 rc = -EINVAL;
530 goto out;
531 }
532
533 if (tq_id[i].id != id) {
534 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
535 "Taskq '%s' expected taskqid %d got %d\n",
536 tq_arg.name, (int)tq_id[i].id, (int)id);
537 rc = -EINVAL;
538 goto out;
539 }
540 }
541
542 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
543 "waiting for taskqid %d completion\n", tq_arg.name, 3);
544 taskq_wait_id(tq, 3);
55f10ae5 545 if ((rc = splat_taskq_test_order(&tq_arg, order1)))
5562e5d1
BB
546 goto out;
547
548 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' "
549 "waiting for taskqid %d completion\n", tq_arg.name, 8);
550 taskq_wait_id(tq, 8);
55f10ae5 551 rc = splat_taskq_test_order(&tq_arg, order2);
5562e5d1
BB
552
553out:
554 splat_vprint(file, SPLAT_TASKQ_TEST5_NAME,
555 "Taskq '%s' destroying\n", tq_arg.name);
556 taskq_destroy(tq);
557
558 return rc;
559}
560
55f10ae5
NB
561/*
562 * Create a single task queue with three threads. Dispatch 8 tasks,
563 * setting TQ_FRONT on only the last three. Sleep after
564 * dispatching tasks 1-3 to ensure they will run and hold the threads
565 * busy while we dispatch the remaining tasks. Verify that tasks 6-8
566 * run before task 4-5.
567 *
568 * The following table shows each task id and how they will be
569 * scheduled. Each rows represent one time unit and each column
570 * one of the three worker threads.
571 *
572 * +-----+
573 * | |
574 * +-----+ |
575 * | | 5 +-----+
576 * | | | |
577 * | +-----| |
578 * | 4 | | |
579 * +-----+ | 8 |
580 * | | | |
581 * | | 7 +-----+
582 * | | | |
583 * | |-----+ |
584 * | 6 | | |
585 * +-----+ | |
586 * | | | |
587 * | 1 | 2 | 3 |
588 * +-----+-----+-----+
589 *
590 */
591static void
592splat_taskq_test6_func(void *arg)
593{
594 splat_taskq_id_t *tq_id = (splat_taskq_id_t *)arg;
595 splat_taskq_arg_t *tq_arg = tq_id->arg;
596 int factor;
597
598 /* Delays determined by above table */
599 switch (tq_id->id) {
600 default: factor = 0; break;
601 case 1: factor = 2; break;
602 case 2: case 4: case 5: factor = 4; break;
603 case 6: case 7: case 8: factor = 5; break;
604 case 3: factor = 6; break;
605 }
606
607 msleep(factor * 100);
608
609 splat_vprint(tq_arg->file, tq_arg->name,
610 "Taskqid %d complete for taskq '%s'\n",
611 tq_id->id, tq_arg->name);
612
613 spin_lock(&tq_arg->lock);
614 tq_arg->order[tq_arg->flag] = tq_id->id;
615 tq_arg->flag++;
616 spin_unlock(&tq_arg->lock);
617}
618
619static int
620splat_taskq_test6(struct file *file, void *arg)
621{
622 taskq_t *tq;
623 taskqid_t id;
624 splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX];
625 splat_taskq_arg_t tq_arg;
626 int order[SPLAT_TASKQ_ORDER_MAX] = { 1,2,3,6,7,8,4,5 };
627 int i, rc = 0;
628 uint_t tflags;
629
630 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' creating\n",
631 SPLAT_TASKQ_TEST6_NAME);
632 if ((tq = taskq_create(SPLAT_TASKQ_TEST6_NAME, 3, maxclsyspri,
633 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
634 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
635 "Taskq '%s' create failed\n",
636 SPLAT_TASKQ_TEST6_NAME);
637 return -EINVAL;
638 }
639
640 tq_arg.flag = 0;
641 memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX);
642 spin_lock_init(&tq_arg.lock);
643 tq_arg.file = file;
644 tq_arg.name = SPLAT_TASKQ_TEST6_NAME;
645
646 for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) {
647 tq_id[i].id = i + 1;
648 tq_id[i].arg = &tq_arg;
649 tflags = TQ_SLEEP;
650 if (i > 4)
651 tflags |= TQ_FRONT;
652
653 if ((id = taskq_dispatch(tq, splat_taskq_test6_func,
654 &tq_id[i], tflags)) == 0) {
655 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
656 "Taskq '%s' function '%s' dispatch failed\n",
657 tq_arg.name, sym2str(splat_taskq_test6_func));
658 rc = -EINVAL;
659 goto out;
660 }
661
662 if (tq_id[i].id != id) {
663 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
664 "Taskq '%s' expected taskqid %d got %d\n",
665 tq_arg.name, (int)tq_id[i].id, (int)id);
666 rc = -EINVAL;
667 goto out;
668 }
669 /* Sleep to let tasks 1-3 start executing. */
670 if ( i == 2 )
671 msleep(100);
672 }
673
674 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' "
675 "waiting for taskqid %d completion\n", tq_arg.name,
676 SPLAT_TASKQ_ORDER_MAX);
677 taskq_wait_id(tq, SPLAT_TASKQ_ORDER_MAX);
678 rc = splat_taskq_test_order(&tq_arg, order);
679
680out:
681 splat_vprint(file, SPLAT_TASKQ_TEST6_NAME,
682 "Taskq '%s' destroying\n", tq_arg.name);
683 taskq_destroy(tq);
684
685 return rc;
686}
687
7c50328b 688splat_subsystem_t *
689splat_taskq_init(void)
f1ca4da6 690{
7c50328b 691 splat_subsystem_t *sub;
f1ca4da6 692
693 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
694 if (sub == NULL)
695 return NULL;
696
697 memset(sub, 0, sizeof(*sub));
7c50328b 698 strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE);
699 strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE);
f1ca4da6 700 INIT_LIST_HEAD(&sub->subsystem_list);
701 INIT_LIST_HEAD(&sub->test_list);
702 spin_lock_init(&sub->test_lock);
7c50328b 703 sub->desc.id = SPLAT_SUBSYSTEM_TASKQ;
f1ca4da6 704
7c50328b 705 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC,
706 SPLAT_TASKQ_TEST1_ID, splat_taskq_test1);
707 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC,
708 SPLAT_TASKQ_TEST2_ID, splat_taskq_test2);
e9cb2b4f
BB
709 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC,
710 SPLAT_TASKQ_TEST3_ID, splat_taskq_test3);
7257ec41
BB
711 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST4_NAME, SPLAT_TASKQ_TEST4_DESC,
712 SPLAT_TASKQ_TEST4_ID, splat_taskq_test4);
5562e5d1
BB
713 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST5_NAME, SPLAT_TASKQ_TEST5_DESC,
714 SPLAT_TASKQ_TEST5_ID, splat_taskq_test5);
55f10ae5
NB
715 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST6_NAME, SPLAT_TASKQ_TEST6_DESC,
716 SPLAT_TASKQ_TEST6_ID, splat_taskq_test6);
f1ca4da6 717
718 return sub;
719}
720
721void
7c50328b 722splat_taskq_fini(splat_subsystem_t *sub)
f1ca4da6 723{
724 ASSERT(sub);
5562e5d1 725 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST5_ID);
7257ec41 726 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST4_ID);
e9cb2b4f 727 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST3_ID);
7c50328b 728 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID);
729 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID);
f1ca4da6 730
731 kfree(sub);
732}
733
734int
7c50328b 735splat_taskq_id(void) {
736 return SPLAT_SUBSYSTEM_TASKQ;
f1ca4da6 737}