]> git.proxmox.com Git - mirror_spl.git/blame - src/splat/splat-taskq.c
Initial commit. All spl source written up to this point wrapped
[mirror_spl.git] / src / splat / splat-taskq.c
CommitLineData
f1ca4da6 1#include <sys/zfs_context.h>
2#include <sys/splat-ctl.h>
3
4#define KZT_SUBSYSTEM_TASKQ 0x0200
5#define KZT_TASKQ_NAME "taskq"
6#define KZT_TASKQ_DESC "Kernel Task Queue Tests"
7
8#define KZT_TASKQ_TEST1_ID 0x0201
9#define KZT_TASKQ_TEST1_NAME "single"
10#define KZT_TASKQ_TEST1_DESC "Single task queue, single task"
11
12#define KZT_TASKQ_TEST2_ID 0x0202
13#define KZT_TASKQ_TEST2_NAME "multiple"
14#define KZT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
15
16typedef struct kzt_taskq_arg {
17 int flag;
18 int id;
19 struct file *file;
20 const char *name;
21} kzt_taskq_arg_t;
22
23/* Validation Test 1 - Create a taskq, queue a task, wait until
24 * task completes, ensure task ran properly, cleanup taskq,
25 */
26static void
27kzt_taskq_test1_func(void *arg)
28{
29 kzt_taskq_arg_t *tq_arg = (kzt_taskq_arg_t *)arg;
30
31 ASSERT(tq_arg);
32 kzt_vprint(tq_arg->file, KZT_TASKQ_TEST1_NAME,
33 "Taskq '%s' function '%s' setting flag\n",
34 tq_arg->name, sym2str(kzt_taskq_test1_func));
35 tq_arg->flag = 1;
36}
37
38static int
39kzt_taskq_test1(struct file *file, void *arg)
40{
41 taskq_t *tq;
42 taskqid_t id;
43 kzt_taskq_arg_t tq_arg;
44
45 kzt_vprint(file, KZT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n",
46 KZT_TASKQ_TEST1_NAME);
47 if ((tq = taskq_create(KZT_TASKQ_TEST1_NAME, 1, 0, 0, 0, 0)) == NULL) {
48 kzt_vprint(file, KZT_TASKQ_TEST1_NAME,
49 "Taskq '%s' create failed\n",
50 KZT_TASKQ_TEST1_NAME);
51 return -EINVAL;
52 }
53
54 tq_arg.flag = 0;
55 tq_arg.id = 0;
56 tq_arg.file = file;
57 tq_arg.name = KZT_TASKQ_TEST1_NAME;
58
59 kzt_vprint(file, KZT_TASKQ_TEST1_NAME,
60 "Taskq '%s' function '%s' dispatching\n",
61 tq_arg.name, sym2str(kzt_taskq_test1_func));
62 if ((id = taskq_dispatch(tq, kzt_taskq_test1_func, &tq_arg, 0)) == 0) {
63 kzt_vprint(file, KZT_TASKQ_TEST1_NAME,
64 "Taskq '%s' function '%s' dispatch failed\n",
65 tq_arg.name, sym2str(kzt_taskq_test1_func));
66 taskq_destory(tq);
67 return -EINVAL;
68 }
69
70 kzt_vprint(file, KZT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
71 tq_arg.name);
72 taskq_wait(tq);
73 kzt_vprint(file, KZT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
74 tq_arg.name);
75 taskq_destory(tq);
76
77 return (tq_arg.flag) ? 0 : -EINVAL;
78}
79
80/* Validation Test 2 - Create multiple taskq's, each with multiple tasks,
81 * wait until all tasks complete, ensure all tasks ran properly and in the
82 * the correct order, cleanup taskq's
83 */
84static void
85kzt_taskq_test2_func1(void *arg)
86{
87 kzt_taskq_arg_t *tq_arg = (kzt_taskq_arg_t *)arg;
88
89 ASSERT(tq_arg);
90 kzt_vprint(tq_arg->file, KZT_TASKQ_TEST2_NAME,
91 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
92 tq_arg->name, tq_arg->id,
93 sym2str(kzt_taskq_test2_func1),
94 tq_arg->flag * 2, tq_arg->flag);
95 tq_arg->flag *= 2;
96}
97
98static void
99kzt_taskq_test2_func2(void *arg)
100{
101 kzt_taskq_arg_t *tq_arg = (kzt_taskq_arg_t *)arg;
102
103 ASSERT(tq_arg);
104 kzt_vprint(tq_arg->file, KZT_TASKQ_TEST2_NAME,
105 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
106 tq_arg->name, tq_arg->id,
107 sym2str(kzt_taskq_test2_func2),
108 tq_arg->flag + 1, tq_arg->flag);
109 tq_arg->flag += 1;
110}
111
112#define TEST2_TASKQS 8
113static int
114kzt_taskq_test2(struct file *file, void *arg) {
115 taskq_t *tq[TEST2_TASKQS] = { NULL };
116 taskqid_t id;
117 kzt_taskq_arg_t tq_args[TEST2_TASKQS];
118 int i, rc = 0;
119
120 for (i = 0; i < TEST2_TASKQS; i++) {
121
122 kzt_vprint(file, KZT_TASKQ_TEST2_NAME, "Taskq '%s/%d' "
123 "creating\n", KZT_TASKQ_TEST2_NAME, i);
124 if ((tq[i] = taskq_create(KZT_TASKQ_TEST2_NAME,
125 1, 0, 0, 0, 0)) == NULL) {
126 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
127 "Taskq '%s/%d' create failed\n",
128 KZT_TASKQ_TEST2_NAME, i);
129 rc = -EINVAL;
130 break;
131 }
132
133 tq_args[i].flag = i;
134 tq_args[i].id = i;
135 tq_args[i].file = file;
136 tq_args[i].name = KZT_TASKQ_TEST2_NAME;
137
138 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
139 "Taskq '%s/%d' function '%s' dispatching\n",
140 tq_args[i].name, tq_args[i].id,
141 sym2str(kzt_taskq_test2_func1));
142 if ((id = taskq_dispatch(
143 tq[i], kzt_taskq_test2_func1, &tq_args[i], 0)) == 0) {
144 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
145 "Taskq '%s/%d' function '%s' dispatch "
146 "failed\n", tq_args[i].name, tq_args[i].id,
147 sym2str(kzt_taskq_test2_func1));
148 rc = -EINVAL;
149 break;
150 }
151
152 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
153 "Taskq '%s/%d' function '%s' dispatching\n",
154 tq_args[i].name, tq_args[i].id,
155 sym2str(kzt_taskq_test2_func2));
156 if ((id = taskq_dispatch(
157 tq[i], kzt_taskq_test2_func2, &tq_args[i], 0)) == 0) {
158 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
159 "Taskq '%s/%d' function '%s' dispatch failed\n",
160 tq_args[i].name, tq_args[i].id,
161 sym2str(kzt_taskq_test2_func2));
162 rc = -EINVAL;
163 break;
164 }
165 }
166
167 /* When rc is set we're effectively just doing cleanup here, so
168 * ignore new errors in that case. They just cause noise. */
169 for (i = 0; i < TEST2_TASKQS; i++) {
170 if (tq[i] != NULL) {
171 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
172 "Taskq '%s/%d' waiting\n",
173 tq_args[i].name, tq_args[i].id);
174 taskq_wait(tq[i]);
175 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
176 "Taskq '%s/%d; destroying\n",
177 tq_args[i].name, tq_args[i].id);
178 taskq_destory(tq[i]);
179
180 if (!rc && tq_args[i].flag != ((i * 2) + 1)) {
181 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
182 "Taskq '%s/%d' processed tasks "
183 "out of order; %d != %d\n",
184 tq_args[i].name, tq_args[i].id,
185 tq_args[i].flag, i * 2 + 1);
186 rc = -EINVAL;
187 } else {
188 kzt_vprint(file, KZT_TASKQ_TEST2_NAME,
189 "Taskq '%s/%d' processed tasks "
190 "in the correct order; %d == %d\n",
191 tq_args[i].name, tq_args[i].id,
192 tq_args[i].flag, i * 2 + 1);
193 }
194 }
195 }
196
197 return rc;
198}
199
200kzt_subsystem_t *
201kzt_taskq_init(void)
202{
203 kzt_subsystem_t *sub;
204
205 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
206 if (sub == NULL)
207 return NULL;
208
209 memset(sub, 0, sizeof(*sub));
210 strncpy(sub->desc.name, KZT_TASKQ_NAME, KZT_NAME_SIZE);
211 strncpy(sub->desc.desc, KZT_TASKQ_DESC, KZT_DESC_SIZE);
212 INIT_LIST_HEAD(&sub->subsystem_list);
213 INIT_LIST_HEAD(&sub->test_list);
214 spin_lock_init(&sub->test_lock);
215 sub->desc.id = KZT_SUBSYSTEM_TASKQ;
216
217 KZT_TEST_INIT(sub, KZT_TASKQ_TEST1_NAME, KZT_TASKQ_TEST1_DESC,
218 KZT_TASKQ_TEST1_ID, kzt_taskq_test1);
219 KZT_TEST_INIT(sub, KZT_TASKQ_TEST2_NAME, KZT_TASKQ_TEST2_DESC,
220 KZT_TASKQ_TEST2_ID, kzt_taskq_test2);
221
222 return sub;
223}
224
225void
226kzt_taskq_fini(kzt_subsystem_t *sub)
227{
228 ASSERT(sub);
229 KZT_TEST_FINI(sub, KZT_TASKQ_TEST2_ID);
230 KZT_TEST_FINI(sub, KZT_TASKQ_TEST1_ID);
231
232 kfree(sub);
233}
234
235int
236kzt_taskq_id(void) {
237 return KZT_SUBSYSTEM_TASKQ;
238}