aboutsummaryrefslogtreecommitdiffstats
path: root/module/splat/splat-taskq.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/splat/splat-taskq.c')
-rw-r--r--module/splat/splat-taskq.c329
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)
{