void vdev_queue_init(vdev_t *vd) { vdev_queue_t *vq = &vd->vdev_queue; zio_priority_t p; mutex_init(&vq->vq_lock, NULL, MUTEX_DEFAULT, NULL); vq->vq_vdev = vd; taskq_init_ent(&vd->vdev_queue.vq_io_search.io_tqent); avl_create(&vq->vq_active_tree, vdev_queue_offset_compare, sizeof (zio_t), offsetof(struct zio, io_queue_node)); avl_create(vdev_queue_type_tree(vq, ZIO_TYPE_READ), vdev_queue_offset_compare, sizeof (zio_t), offsetof(struct zio, io_offset_node)); avl_create(vdev_queue_type_tree(vq, ZIO_TYPE_WRITE), vdev_queue_offset_compare, sizeof (zio_t), offsetof(struct zio, io_offset_node)); for (p = 0; p < ZIO_PRIORITY_NUM_QUEUEABLE; p++) { int (*compfn) (const void *, const void *); /* * The synchronous i/o queues are dispatched in FIFO rather * than LBA order. This provides more consistent latency for * these i/os. */ if (p == ZIO_PRIORITY_SYNC_READ || p == ZIO_PRIORITY_SYNC_WRITE) compfn = vdev_queue_timestamp_compare; else compfn = vdev_queue_offset_compare; avl_create(vdev_queue_class_tree(vq, p), compfn, sizeof (zio_t), offsetof(struct zio, io_queue_node)); } }
static int 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 (%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, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST1_NAME); return -EINVAL; } tq_arg.flag = 0; tq_arg.id = 0; tq_arg.file = file; tq_arg.name = SPLAT_TASKQ_TEST1_NAME; splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' function '%s' dispatching\n", tq_arg.name, sym2str(splat_taskq_test13_func)); 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_destroy(tq); return -EINVAL; } splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n", tq_arg.name); 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_test7_impl(struct file *file, void *arg, boolean_t prealloc) { taskq_t *tq; splat_taskq_arg_t *tq_arg; taskq_ent_t *tqe; int error; splat_vprint(file, 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, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST7_NAME); return -EINVAL; } tq_arg = kmem_alloc(sizeof (splat_taskq_arg_t), KM_SLEEP); tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP); tq_arg->depth = 0; tq_arg->flag = 0; tq_arg->id = 0; tq_arg->file = file; 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) { splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, "Taskq '%s' waiting\n", tq_arg->name); taskq_wait_outstanding(tq, SPLAT_TASKQ_DEPTH_MAX); } error = (tq_arg->depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL); kmem_free(tqe, sizeof (taskq_ent_t)); kmem_free(tq_arg, sizeof (splat_taskq_arg_t)); splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, "Taskq '%s' destroying\n", tq_arg->name); taskq_destroy(tq); return (error); }
/* * Use the global system task queue with a single task, wait until task * completes, ensure task ran properly. */ static int 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; int error; tq_arg = kmem_alloc(sizeof (splat_taskq_arg_t), KM_SLEEP); tqe = kmem_alloc(sizeof (taskq_ent_t), KM_SLEEP); taskq_init_ent(tqe); tq_arg->flag = 0; tq_arg->id = 0; tq_arg->file = file; tq_arg->name = SPLAT_TASKQ_TEST3_NAME; splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "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)); kmem_free(tqe, sizeof (taskq_ent_t)); kmem_free(tq_arg, sizeof (splat_taskq_arg_t)); return -EINVAL; } splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n", tq_arg->name); taskq_wait(system_taskq); error = (tq_arg->flag) ? 0 : -EINVAL; kmem_free(tqe, sizeof (taskq_ent_t)); kmem_free(tq_arg, sizeof (splat_taskq_arg_t)); return (error); }
static int 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 (%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, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST7_NAME); return -EINVAL; } tq_arg.depth = 0; tq_arg.flag = 0; tq_arg.id = 0; tq_arg.file = file; 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) { splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, "Taskq '%s' waiting\n", tq_arg.name); taskq_wait_id(tq, SPLAT_TASKQ_DEPTH_MAX); } splat_vprint(file, SPLAT_TASKQ_TEST7_NAME, "Taskq '%s' destroying\n", tq_arg.name); taskq_destroy(tq); return tq_arg.depth == SPLAT_TASKQ_DEPTH_MAX ? 0 : -EINVAL; }
/* * Use the global system task queue with a single task, wait until task * completes, ensure task ran properly. */ static int 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; tq_arg.file = file; tq_arg.name = SPLAT_TASKQ_TEST3_NAME; splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "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)); return -EINVAL; } splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n", tq_arg.name); taskq_wait(system_taskq); return (tq_arg.flag) ? 0 : -EINVAL; }
static int 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 (%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, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST6_NAME); return -EINVAL; } tq_arg.flag = 0; memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX); spin_lock_init(&tq_arg.lock); tq_arg.file = file; 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 (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)); rc = -EINVAL; goto out; } if (tq_id[i].id != id) { splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' expected taskqid %d got %d\n", tq_arg.name, (int)tq_id[i].id, (int)id); rc = -EINVAL; goto out; } /* Sleep to let tasks 1-3 start executing. */ if ( i == 2 ) msleep(100); } splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' " "waiting for taskqid %d completion\n", tq_arg.name, SPLAT_TASKQ_ORDER_MAX); taskq_wait_id(tq, SPLAT_TASKQ_ORDER_MAX); rc = splat_taskq_test_order(&tq_arg, order); out: splat_vprint(file, SPLAT_TASKQ_TEST6_NAME, "Taskq '%s' destroying\n", tq_arg.name); taskq_destroy(tq); return rc; }
static int splat_taskq_test5_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 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 (%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, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST5_NAME); return -EINVAL; } tq_arg.flag = 0; memset(&tq_arg.order, 0, sizeof(int) * SPLAT_TASKQ_ORDER_MAX); spin_lock_init(&tq_arg.lock); tq_arg.file = file; 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 (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)); rc = -EINVAL; goto out; } if (tq_id[i].id != id) { splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' expected taskqid %d got %d\n", tq_arg.name, (int)tq_id[i].id, (int)id); rc = -EINVAL; goto out; } } splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' " "waiting for taskqid %d completion\n", tq_arg.name, 3); taskq_wait_id(tq, 3); if ((rc = splat_taskq_test_order(&tq_arg, order1))) goto out; splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' " "waiting for taskqid %d completion\n", tq_arg.name, 8); taskq_wait_id(tq, 8); rc = splat_taskq_test_order(&tq_arg, order2); out: splat_vprint(file, SPLAT_TASKQ_TEST5_NAME, "Taskq '%s' destroying\n", tq_arg.name); taskq_destroy(tq); return rc; }
static int splat_taskq_test4_common(struct file *file, void *arg, int minalloc, 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; 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); rc = -EINVAL; goto out_free; } tq_arg.file = file; tq_arg.name = SPLAT_TASKQ_TEST4_NAME; 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", tq_arg.name, sym2str(splat_taskq_test4_func), i); for (j = 0; j < i; j++) { 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, sym2str(splat_taskq_test4_func), j); rc = -EINVAL; goto out; } } splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' " "waiting for %d dispatches\n", tq_arg.name, i); taskq_wait(tq); splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' " "%d/%d dispatches finished\n", tq_arg.name, atomic_read(&tq_arg.count), i); if (atomic_read(&tq_arg.count) != i) { rc = -ERANGE; goto out; } } out: splat_vprint(file, SPLAT_TASKQ_TEST4_NAME, "Taskq '%s' destroying\n", tq_arg.name); taskq_destroy(tq); out_free: kfree(tqes); return rc; }
static int 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 (%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, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' create failed\n", SPLAT_TASKQ_TEST2_NAME, i); rc = -EINVAL; break; } tq_args[i].flag = i; tq_args[i].id = i; tq_args[i].file = file; tq_args[i].name = SPLAT_TASKQ_TEST2_NAME; splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' function '%s' dispatching\n", tq_args[i].name, tq_args[i].id, sym2str(splat_taskq_test2_func1)); 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, sym2str(splat_taskq_test2_func1)); rc = -EINVAL; break; } splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' function '%s' dispatching\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; } } /* When rc is set we're effectively just doing cleanup here, so * ignore new errors in that case. They just cause noise. */ for (i = 0; i < TEST2_TASKQS; i++) { if (tq[i] != NULL) { splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' waiting\n", tq_args[i].name, tq_args[i].id); taskq_wait(tq[i]); 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)) { splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' processed tasks " "out of order; %d != %d\n", tq_args[i].name, tq_args[i].id, tq_args[i].flag, i * 2 + 1); rc = -EINVAL; } else { splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' processed tasks " "in the correct order; %d == %d\n", tq_args[i].name, tq_args[i].id, tq_args[i].flag, i * 2 + 1); } } } out: if (func1_tqes) kfree(func1_tqes); if (func2_tqes) kfree(func2_tqes); return rc; }
static int splat_taskq_test8_common(struct file *file, void *arg, int minalloc, int maxalloc) { taskq_t *tq; taskqid_t id; splat_taskq_arg_t tq_arg; taskq_ent_t **tqes; int i, j, rc = 0; tqes = vmalloc(sizeof(*tqes) * TEST8_NUM_TASKS); if (tqes == NULL) return -ENOMEM; memset(tqes, 0, sizeof(*tqes) * TEST8_NUM_TASKS); splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' creating (%d/%d/%d)\n", SPLAT_TASKQ_TEST8_NAME, minalloc, maxalloc, TEST8_NUM_TASKS); if ((tq = taskq_create(SPLAT_TASKQ_TEST8_NAME, TEST8_THREADS_PER_TASKQ, maxclsyspri, minalloc, maxalloc, TASKQ_PREPOPULATE)) == NULL) { splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' create failed\n", SPLAT_TASKQ_TEST8_NAME); rc = -EINVAL; goto out_free; } tq_arg.file = file; tq_arg.name = SPLAT_TASKQ_TEST8_NAME; atomic_set(&tq_arg.count, 0); for (i = 0; i < TEST8_NUM_TASKS; i++) { tqes[i] = kmalloc(sizeof(taskq_ent_t), GFP_KERNEL); if (tqes[i] == NULL) { rc = -ENOMEM; goto out; } taskq_init_ent(tqes[i]); taskq_dispatch_ent(tq, splat_taskq_test8_func, &tq_arg, TQ_SLEEP, tqes[i]); id = tqes[i]->tqent_id; if (id == 0) { splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' function '%s' dispatch " "%d failed\n", tq_arg.name, sym2str(splat_taskq_test8_func), i); rc = -EINVAL; goto out; } } splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' " "waiting for %d dispatches\n", tq_arg.name, TEST8_NUM_TASKS); taskq_wait(tq); splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' " "%d/%d dispatches finished\n", tq_arg.name, atomic_read(&tq_arg.count), TEST8_NUM_TASKS); if (atomic_read(&tq_arg.count) != TEST8_NUM_TASKS) rc = -ERANGE; out: splat_vprint(file, SPLAT_TASKQ_TEST8_NAME, "Taskq '%s' destroying\n", tq_arg.name); taskq_destroy(tq); out_free: for (j = 0; j < TEST8_NUM_TASKS && tqes[j] != NULL; j++) kfree(tqes[j]); vfree(tqes); return rc; }
static int splat_taskq_throughput(struct file *file, void *arg, const char *name, int nthreads, int minalloc, int maxalloc, int flags, int tasks, struct timespec *delta) { taskq_t *tq; taskqid_t id; splat_taskq_arg_t tq_arg; taskq_ent_t **tqes; atomic_t count; struct timespec start, stop; int i, j, rc = 0; tqes = vmalloc(sizeof (*tqes) * tasks); if (tqes == NULL) return (-ENOMEM); memset(tqes, 0, sizeof (*tqes) * tasks); splat_vprint(file, name, "Taskq '%s' creating (%d/%d/%d/%d)\n", name, nthreads, minalloc, maxalloc, tasks); if ((tq = taskq_create(name, nthreads, maxclsyspri, minalloc, maxalloc, flags)) == NULL) { splat_vprint(file, name, "Taskq '%s' create failed\n", name); rc = -EINVAL; goto out_free; } tq_arg.file = file; tq_arg.name = name; tq_arg.count = &count; atomic_set(tq_arg.count, 0); getnstimeofday(&start); for (i = 0; i < tasks; i++) { tqes[i] = kmalloc(sizeof (taskq_ent_t), GFP_KERNEL); if (tqes[i] == NULL) { rc = -ENOMEM; goto out; } taskq_init_ent(tqes[i]); taskq_dispatch_ent(tq, splat_taskq_throughput_func, &tq_arg, TQ_SLEEP, tqes[i]); id = tqes[i]->tqent_id; if (id == 0) { splat_vprint(file, name, "Taskq '%s' function '%s' " "dispatch %d failed\n", tq_arg.name, sym2str(splat_taskq_throughput_func), i); rc = -EINVAL; goto out; } } splat_vprint(file, name, "Taskq '%s' waiting for %d dispatches\n", tq_arg.name, tasks); taskq_wait(tq); if (delta != NULL) { getnstimeofday(&stop); *delta = timespec_sub(stop, start); } splat_vprint(file, name, "Taskq '%s' %d/%d dispatches finished\n", tq_arg.name, atomic_read(tq_arg.count), tasks); if (atomic_read(tq_arg.count) != tasks) rc = -ERANGE; out: splat_vprint(file, name, "Taskq '%s' destroying\n", tq_arg.name); taskq_destroy(tq); out_free: for (j = 0; j < tasks && tqes[j] != NULL; j++) kfree(tqes[j]); vfree(tqes); return (rc); }