From 699d5ee8a99471b49b07e69108045301b865b0d6 Mon Sep 17 00:00:00 2001 From: Prakash Surya Date: Tue, 6 Dec 2011 10:11:36 -0800 Subject: [PATCH] Exercise new taskq interface in splat-taskq tests The splat-taskq test functions were slightly modified to exercise the new taskq interface in addition to the old interface. If the old interface passes each of its tests, the new interface is exercised. Both sub tests (old interface and new interface) must pass for each test as a whole to pass. Signed-off-by: Prakash Surya Signed-off-by: Brian Behlendorf Closes #65 --- module/splat/splat-taskq.c | 331 +++++++++++++++++++++++++++++++------ 1 file changed, 281 insertions(+), 50 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; - splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n", - SPLAT_TASKQ_TEST1_NAME); + taskq_init_ent(&tqe); + + 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; - for (i = 0; i < TEST2_TASKQS; i++) { + func1_tqes = kmalloc(sizeof(*func1_tqes) * TEST2_TASKQS, GFP_KERNEL); + if (func1_tqes == NULL) { + rc = -ENOMEM; + goto out; + } - splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' " - "creating\n", SPLAT_TASKQ_TEST2_NAME, i); + 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 (%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); + 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); + 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_impl(file, arg, B_FALSE); + if (rc) + return rc; + + 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) {