diff options
Diffstat (limited to 'module/splat/splat-taskq.c')
-rw-r--r-- | module/splat/splat-taskq.c | 329 |
1 files changed, 280 insertions, 49 deletions
diff --git a/module/splat/splat-taskq.c b/module/splat/splat-taskq.c index cc054548b..b89b495f1 100644 --- a/module/splat/splat-taskq.c +++ b/module/splat/splat-taskq.c @@ -67,6 +67,7 @@ typedef struct splat_taskq_arg { int order[SPLAT_TASKQ_ORDER_MAX]; unsigned int depth; taskq_t *tq; + taskq_ent_t *tqe; spinlock_t lock; struct file *file; const char *name; @@ -94,14 +95,19 @@ splat_taskq_test13_func(void *arg) } static int -splat_taskq_test1(struct file *file, void *arg) +splat_taskq_test1_impl(struct file *file, void *arg, boolean_t prealloc) { taskq_t *tq; taskqid_t id; splat_taskq_arg_t tq_arg; + taskq_ent_t tqe; + + taskq_init_ent(&tqe); - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n", - SPLAT_TASKQ_TEST1_NAME); + splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, + "Taskq '%s' creating (%s dispatch)\n", + SPLAT_TASKQ_TEST1_NAME, + prealloc ? "prealloc" : "dynamic"); if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, @@ -118,11 +124,19 @@ splat_taskq_test1(struct file *file, void *arg) splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' function '%s' dispatching\n", tq_arg.name, sym2str(splat_taskq_test13_func)); - if ((id = taskq_dispatch(tq, splat_taskq_test13_func, - &tq_arg, TQ_SLEEP)) == 0) { + if (prealloc) { + taskq_dispatch_ent(tq, splat_taskq_test13_func, + &tq_arg, TQ_SLEEP, &tqe); + id = tqe.tqent_id; + } else { + id = taskq_dispatch(tq, splat_taskq_test13_func, + &tq_arg, TQ_SLEEP); + } + + if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, - "Taskq '%s' function '%s' dispatch failed\n", - tq_arg.name, sym2str(splat_taskq_test13_func)); + "Taskq '%s' function '%s' dispatch failed\n", + tq_arg.name, sym2str(splat_taskq_test13_func)); taskq_destroy(tq); return -EINVAL; } @@ -132,11 +146,26 @@ splat_taskq_test1(struct file *file, void *arg) taskq_wait(tq); splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n", tq_arg.name); + taskq_destroy(tq); return (tq_arg.flag) ? 0 : -EINVAL; } +static int +splat_taskq_test1(struct file *file, void *arg) +{ + int rc; + + rc = splat_taskq_test1_impl(file, arg, B_FALSE); + if (rc) + return rc; + + rc = splat_taskq_test1_impl(file, arg, B_TRUE); + + return rc; +} + /* * Create multiple taskq's, each with multiple tasks, wait until * all tasks complete, ensure all tasks ran properly and in the @@ -175,16 +204,34 @@ splat_taskq_test2_func2(void *arg) #define TEST2_THREADS_PER_TASKQ 1 static int -splat_taskq_test2(struct file *file, void *arg) { +splat_taskq_test2_impl(struct file *file, void *arg, boolean_t prealloc) { taskq_t *tq[TEST2_TASKQS] = { NULL }; taskqid_t id; splat_taskq_arg_t tq_args[TEST2_TASKQS]; + taskq_ent_t *func1_tqes = NULL; + taskq_ent_t *func2_tqes = NULL; int i, rc = 0; + func1_tqes = kmalloc(sizeof(*func1_tqes) * TEST2_TASKQS, GFP_KERNEL); + if (func1_tqes == NULL) { + rc = -ENOMEM; + goto out; + } + + func2_tqes = kmalloc(sizeof(*func2_tqes) * TEST2_TASKQS, GFP_KERNEL); + if (func2_tqes == NULL) { + rc = -ENOMEM; + goto out; + } + for (i = 0; i < TEST2_TASKQS; i++) { + taskq_init_ent(&func1_tqes[i]); + taskq_init_ent(&func2_tqes[i]); - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' " - "creating\n", SPLAT_TASKQ_TEST2_NAME, i); + splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, + "Taskq '%s/%d' creating (%s dispatch)\n", + SPLAT_TASKQ_TEST2_NAME, i, + prealloc ? "prealloc" : "dynamic"); if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME, TEST2_THREADS_PER_TASKQ, maxclsyspri, 50, INT_MAX, @@ -205,9 +252,16 @@ splat_taskq_test2(struct file *file, void *arg) { "Taskq '%s/%d' function '%s' dispatching\n", tq_args[i].name, tq_args[i].id, sym2str(splat_taskq_test2_func1)); - if ((id = taskq_dispatch( - tq[i], splat_taskq_test2_func1, - &tq_args[i], TQ_SLEEP)) == 0) { + if (prealloc) { + taskq_dispatch_ent(tq[i], splat_taskq_test2_func1, + &tq_args[i], TQ_SLEEP, &func1_tqes[i]); + id = func1_tqes[i].tqent_id; + } else { + id = taskq_dispatch(tq[i], splat_taskq_test2_func1, + &tq_args[i], TQ_SLEEP); + } + + if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' function '%s' dispatch " "failed\n", tq_args[i].name, tq_args[i].id, @@ -220,13 +274,20 @@ splat_taskq_test2(struct file *file, void *arg) { "Taskq '%s/%d' function '%s' dispatching\n", tq_args[i].name, tq_args[i].id, sym2str(splat_taskq_test2_func2)); - if ((id = taskq_dispatch( - tq[i], splat_taskq_test2_func2, - &tq_args[i], TQ_SLEEP)) == 0) { - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, - "Taskq '%s/%d' function '%s' dispatch failed\n", - tq_args[i].name, tq_args[i].id, - sym2str(splat_taskq_test2_func2)); + if (prealloc) { + taskq_dispatch_ent(tq[i], splat_taskq_test2_func2, + &tq_args[i], TQ_SLEEP, &func2_tqes[i]); + id = func2_tqes[i].tqent_id; + } else { + id = taskq_dispatch(tq[i], splat_taskq_test2_func2, + &tq_args[i], TQ_SLEEP); + } + + if (id == 0) { + splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq " + "'%s/%d' function '%s' dispatch failed\n", + tq_args[i].name, tq_args[i].id, + sym2str(splat_taskq_test2_func2)); rc = -EINVAL; break; } @@ -243,6 +304,7 @@ splat_taskq_test2(struct file *file, void *arg) { splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d; destroying\n", tq_args[i].name, tq_args[i].id); + taskq_destroy(tq[i]); if (!rc && tq_args[i].flag != ((i * 2) + 1)) { @@ -261,6 +323,25 @@ splat_taskq_test2(struct file *file, void *arg) { } } } +out: + if (func1_tqes) + kfree(func1_tqes); + + if (func2_tqes) + kfree(func2_tqes); + + return rc; +} + +static int +splat_taskq_test2(struct file *file, void *arg) { + int rc; + + rc = splat_taskq_test2_impl(file, arg, B_FALSE); + if (rc) + return rc; + + rc = splat_taskq_test2_impl(file, arg, B_TRUE); return rc; } @@ -270,10 +351,13 @@ splat_taskq_test2(struct file *file, void *arg) { * completes, ensure task ran properly. */ static int -splat_taskq_test3(struct file *file, void *arg) +splat_taskq_test3_impl(struct file *file, void *arg, boolean_t prealloc) { taskqid_t id; splat_taskq_arg_t tq_arg; + taskq_ent_t tqe; + + taskq_init_ent(&tqe); tq_arg.flag = 0; tq_arg.id = 0; @@ -281,10 +365,19 @@ splat_taskq_test3(struct file *file, void *arg) tq_arg.name = SPLAT_TASKQ_TEST3_NAME; splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, - "Taskq '%s' function '%s' dispatching\n", - tq_arg.name, sym2str(splat_taskq_test13_func)); - if ((id = taskq_dispatch(system_taskq, splat_taskq_test13_func, - &tq_arg, TQ_SLEEP)) == 0) { + "Taskq '%s' function '%s' %s dispatch\n", + tq_arg.name, sym2str(splat_taskq_test13_func), + prealloc ? "prealloc" : "dynamic"); + if (prealloc) { + taskq_dispatch_ent(system_taskq, splat_taskq_test13_func, + &tq_arg, TQ_SLEEP, &tqe); + id = tqe.tqent_id; + } else { + id = taskq_dispatch(system_taskq, splat_taskq_test13_func, + &tq_arg, TQ_SLEEP); + } + + if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' function '%s' dispatch failed\n", tq_arg.name, sym2str(splat_taskq_test13_func)); @@ -298,6 +391,20 @@ splat_taskq_test3(struct file *file, void *arg) return (tq_arg.flag) ? 0 : -EINVAL; } +static int +splat_taskq_test3(struct file *file, void *arg) +{ + int rc; + + rc = splat_taskq_test3_impl(file, arg, B_FALSE); + if (rc) + return rc; + + rc = splat_taskq_test3_impl(file, arg, B_TRUE); + + return rc; +} + /* * Create a taskq and dispatch a large number of tasks to the queue. * Then use taskq_wait() to block until all the tasks complete, then @@ -319,21 +426,30 @@ splat_taskq_test4_func(void *arg) static int splat_taskq_test4_common(struct file *file, void *arg, int minalloc, - int maxalloc, int nr_tasks) + int maxalloc, int nr_tasks, boolean_t prealloc) { taskq_t *tq; + taskqid_t id; splat_taskq_arg_t tq_arg; + taskq_ent_t *tqes; int i, j, rc = 0; - splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' creating " - "(%d/%d/%d)\n", SPLAT_TASKQ_TEST4_NAME, minalloc, maxalloc, - nr_tasks); + tqes = kmalloc(sizeof(*tqes) * nr_tasks, GFP_KERNEL); + if (tqes == NULL) + return -ENOMEM; + + splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, + "Taskq '%s' creating (%s dispatch) (%d/%d/%d)\n", + SPLAT_TASKQ_TEST4_NAME, + prealloc ? "prealloc" : "dynamic", + minalloc, maxalloc, nr_tasks); if ((tq = taskq_create(SPLAT_TASKQ_TEST4_NAME, 1, maxclsyspri, minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST4_NAME); - return -EINVAL; + rc = -EINVAL; + goto out_free; } tq_arg.file = file; @@ -346,8 +462,18 @@ splat_taskq_test4_common(struct file *file, void *arg, int minalloc, tq_arg.name, sym2str(splat_taskq_test4_func), i); for (j = 0; j < i; j++) { - if ((taskq_dispatch(tq, splat_taskq_test4_func, - &tq_arg, TQ_SLEEP)) == 0) { + taskq_init_ent(&tqes[j]); + + if (prealloc) { + taskq_dispatch_ent(tq, splat_taskq_test4_func, + &tq_arg, TQ_SLEEP, &tqes[j]); + id = tqes[j].tqent_id; + } else { + id = taskq_dispatch(tq, splat_taskq_test4_func, + &tq_arg, TQ_SLEEP); + } + + if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' function '%s' dispatch " "%d failed\n", tq_arg.name, @@ -374,18 +500,36 @@ out: tq_arg.name); taskq_destroy(tq); +out_free: + kfree(tqes); + return rc; } -static int splat_taskq_test4(struct file *file, void *arg) +static int +splat_taskq_test4_impl(struct file *file, void *arg, boolean_t prealloc) +{ + int rc; + + rc = splat_taskq_test4_common(file, arg, 50, INT_MAX, 1024, prealloc); + if (rc) + return rc; + + rc = splat_taskq_test4_common(file, arg, 1, 1, 32, prealloc); + + 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); + rc = splat_taskq_test4_impl(file, arg, B_FALSE); if (rc) return rc; - rc = splat_taskq_test4_common(file, arg, 1, 1, 32); + rc = splat_taskq_test4_impl(file, arg, B_TRUE); return rc; } @@ -498,7 +642,7 @@ splat_taskq_test_order(splat_taskq_arg_t *tq_arg, int *order) } static int -splat_taskq_test5(struct file *file, void *arg) +splat_taskq_test5_impl(struct file *file, void *arg, boolean_t prealloc) { taskq_t *tq; taskqid_t id; @@ -506,10 +650,13 @@ splat_taskq_test5(struct file *file, void *arg) splat_taskq_arg_t tq_arg; int order1[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,0,0,0 }; int order2[SPLAT_TASKQ_ORDER_MAX] = { 1,2,4,5,3,8,6,7 }; + taskq_ent_t tqes[SPLAT_TASKQ_ORDER_MAX]; int i, rc = 0; - splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' creating\n", - SPLAT_TASKQ_TEST5_NAME); + splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, + "Taskq '%s' creating (%s dispatch)\n", + SPLAT_TASKQ_TEST5_NAME, + prealloc ? "prealloc" : "dynamic"); if ((tq = taskq_create(SPLAT_TASKQ_TEST5_NAME, 3, maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, @@ -525,11 +672,21 @@ splat_taskq_test5(struct file *file, void *arg) tq_arg.name = SPLAT_TASKQ_TEST5_NAME; for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) { + taskq_init_ent(&tqes[i]); + tq_id[i].id = i + 1; tq_id[i].arg = &tq_arg; - if ((id = taskq_dispatch(tq, splat_taskq_test5_func, - &tq_id[i], TQ_SLEEP)) == 0) { + if (prealloc) { + taskq_dispatch_ent(tq, splat_taskq_test5_func, + &tq_id[i], TQ_SLEEP, &tqes[i]); + id = tqes[i].tqent_id; + } else { + id = taskq_dispatch(tq, splat_taskq_test5_func, + &tq_id[i], TQ_SLEEP); + } + + if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' function '%s' dispatch failed\n", tq_arg.name, sym2str(splat_taskq_test5_func)); @@ -565,6 +722,20 @@ out: return rc; } +static int +splat_taskq_test5(struct file *file, void *arg) +{ + int rc; + + rc = splat_taskq_test5_impl(file, arg, B_FALSE); + if (rc) + return rc; + + rc = splat_taskq_test5_impl(file, arg, B_TRUE); + + return rc; +} + /* * Create a single task queue with three threads. Dispatch 8 tasks, * setting TQ_FRONT on only the last three. Sleep after @@ -624,18 +795,21 @@ splat_taskq_test6_func(void *arg) } static int -splat_taskq_test6(struct file *file, void *arg) +splat_taskq_test6_impl(struct file *file, void *arg, boolean_t prealloc) { taskq_t *tq; taskqid_t id; splat_taskq_id_t tq_id[SPLAT_TASKQ_ORDER_MAX]; splat_taskq_arg_t tq_arg; int order[SPLAT_TASKQ_ORDER_MAX] = { 1,2,3,6,7,8,4,5 }; + taskq_ent_t tqes[SPLAT_TASKQ_ORDER_MAX]; int i, rc = 0; uint_t tflags; - splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' creating\n", - SPLAT_TASKQ_TEST6_NAME); + splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, + "Taskq '%s' creating (%s dispatch)\n", + SPLAT_TASKQ_TEST6_NAME, + prealloc ? "prealloc" : "dynamic"); if ((tq = taskq_create(SPLAT_TASKQ_TEST6_NAME, 3, maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, @@ -651,14 +825,24 @@ splat_taskq_test6(struct file *file, void *arg) tq_arg.name = SPLAT_TASKQ_TEST6_NAME; for (i = 0; i < SPLAT_TASKQ_ORDER_MAX; i++) { + taskq_init_ent(&tqes[i]); + tq_id[i].id = i + 1; tq_id[i].arg = &tq_arg; tflags = TQ_SLEEP; if (i > 4) tflags |= TQ_FRONT; - if ((id = taskq_dispatch(tq, splat_taskq_test6_func, - &tq_id[i], tflags)) == 0) { + if (prealloc) { + taskq_dispatch_ent(tq, splat_taskq_test6_func, + &tq_id[i], tflags, &tqes[i]); + id = tqes[i].tqent_id; + } else { + id = taskq_dispatch(tq, splat_taskq_test6_func, + &tq_id[i], tflags); + } + + if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' function '%s' dispatch failed\n", tq_arg.name, sym2str(splat_taskq_test6_func)); @@ -692,6 +876,20 @@ out: return rc; } +static int +splat_taskq_test6(struct file *file, void *arg) +{ + int rc; + + rc = splat_taskq_test6_impl(file, arg, B_FALSE); + if (rc) + return rc; + + rc = splat_taskq_test6_impl(file, arg, B_TRUE); + + return rc; +} + static void splat_taskq_test7_func(void *arg) { @@ -710,8 +908,17 @@ splat_taskq_test7_func(void *arg) tq_arg->name, sym2str(splat_taskq_test7_func), tq_arg->depth); - if ((id = taskq_dispatch(tq_arg->tq, splat_taskq_test7_func, - tq_arg, TQ_SLEEP)) == 0) { + if (tq_arg->tqe) { + VERIFY(taskq_empty_ent(tq_arg->tqe)); + taskq_dispatch_ent(tq_arg->tq, splat_taskq_test7_func, + tq_arg, TQ_SLEEP, tq_arg->tqe); + id = tq_arg->tqe->tqent_id; + } else { + id = taskq_dispatch(tq_arg->tq, splat_taskq_test7_func, + tq_arg, TQ_SLEEP); + } + + if (id == 0) { splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST7_NAME, "Taskq '%s' function '%s' dispatch failed " "(depth = %u)\n", tq_arg->name, @@ -722,13 +929,16 @@ splat_taskq_test7_func(void *arg) } static int -splat_taskq_test7(struct file *file, void *arg) +splat_taskq_test7_impl(struct file *file, void *arg, boolean_t prealloc) { taskq_t *tq; + taskq_ent_t tqe; splat_taskq_arg_t tq_arg; splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, - "Taskq '%s' creating\n", SPLAT_TASKQ_TEST7_NAME); + "Taskq '%s' creating (%s dispatch)\n", + SPLAT_TASKQ_TEST7_NAME, + prealloc ? "prealloc" : "dynamic"); if ((tq = taskq_create(SPLAT_TASKQ_TEST7_NAME, 1, maxclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, @@ -744,6 +954,13 @@ splat_taskq_test7(struct file *file, void *arg) tq_arg.name = SPLAT_TASKQ_TEST7_NAME; tq_arg.tq = tq; + if (prealloc) { + taskq_init_ent(&tqe); + tq_arg.tqe = &tqe; + } else { + tq_arg.tqe = NULL; + } + splat_taskq_test7_func(&tq_arg); if (tq_arg.flag == 0) { @@ -759,6 +976,20 @@ splat_taskq_test7(struct file *file, void *arg) return tq_arg.depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL; } +static int +splat_taskq_test7(struct file *file, void *arg) +{ + int rc; + + rc = splat_taskq_test7_impl(file, arg, B_FALSE); + if (rc) + return rc; + + rc = splat_taskq_test7_impl(file, arg, B_TRUE); + + return rc; +} + splat_subsystem_t * splat_taskq_init(void) { |