]> git.proxmox.com Git - mirror_spl-debian.git/blob - module/splat/splat-taskq.c
Rename modules to module and update references
[mirror_spl-debian.git] / module / splat / splat-taskq.c
1 /*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2008 Lawrence Livermore National Security, LLC.
5 * Produced at Lawrence Livermore National Laboratory
6 * Written by:
7 * Brian Behlendorf <behlendorf1@llnl.gov>,
8 * Herb Wartens <wartens2@llnl.gov>,
9 * Jim Garlick <garlick@llnl.gov>
10 * UCRL-CODE-235197
11 *
12 * This is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License along
23 * with this program; if not, write to the Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 */
26
27 #include "splat-internal.h"
28
29 #define SPLAT_SUBSYSTEM_TASKQ 0x0200
30 #define SPLAT_TASKQ_NAME "taskq"
31 #define SPLAT_TASKQ_DESC "Kernel Task Queue Tests"
32
33 #define SPLAT_TASKQ_TEST1_ID 0x0201
34 #define SPLAT_TASKQ_TEST1_NAME "single"
35 #define SPLAT_TASKQ_TEST1_DESC "Single task queue, single task"
36
37 #define SPLAT_TASKQ_TEST2_ID 0x0202
38 #define SPLAT_TASKQ_TEST2_NAME "multiple"
39 #define SPLAT_TASKQ_TEST2_DESC "Multiple task queues, multiple tasks"
40
41 #define SPLAT_TASKQ_TEST3_ID 0x0203
42 #define SPLAT_TASKQ_TEST3_NAME "system"
43 #define SPLAT_TASKQ_TEST3_DESC "System task queue, multiple tasks"
44
45 typedef struct splat_taskq_arg {
46 int flag;
47 int id;
48 struct file *file;
49 const char *name;
50 } splat_taskq_arg_t;
51
52 /* Validation Test 1 - Create a taskq, queue a task, wait until
53 * task completes, ensure task ran properly, cleanup taskq,
54 */
55 static void
56 splat_taskq_test13_func(void *arg)
57 {
58 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
59
60 ASSERT(tq_arg);
61 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME,
62 "Taskq '%s' function '%s' setting flag\n",
63 tq_arg->name, sym2str(splat_taskq_test13_func));
64 tq_arg->flag = 1;
65 }
66
67 static int
68 splat_taskq_test1(struct file *file, void *arg)
69 {
70 taskq_t *tq;
71 taskqid_t id;
72 splat_taskq_arg_t tq_arg;
73
74 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n",
75 SPLAT_TASKQ_TEST1_NAME);
76 if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri,
77 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
78 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
79 "Taskq '%s' create failed\n",
80 SPLAT_TASKQ_TEST1_NAME);
81 return -EINVAL;
82 }
83
84 tq_arg.flag = 0;
85 tq_arg.id = 0;
86 tq_arg.file = file;
87 tq_arg.name = SPLAT_TASKQ_TEST1_NAME;
88
89 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
90 "Taskq '%s' function '%s' dispatching\n",
91 tq_arg.name, sym2str(splat_taskq_test13_func));
92 if ((id = taskq_dispatch(tq, splat_taskq_test13_func,
93 &tq_arg, TQ_SLEEP)) == 0) {
94 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
95 "Taskq '%s' function '%s' dispatch failed\n",
96 tq_arg.name, sym2str(splat_taskq_test13_func));
97 taskq_destroy(tq);
98 return -EINVAL;
99 }
100
101 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
102 tq_arg.name);
103 taskq_wait(tq);
104 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
105 tq_arg.name);
106 taskq_destroy(tq);
107
108 return (tq_arg.flag) ? 0 : -EINVAL;
109 }
110
111 /* Validation Test 2 - Create multiple taskq's, each with multiple tasks,
112 * wait until all tasks complete, ensure all tasks ran properly and in the
113 * the correct order, cleanup taskq's
114 */
115 static void
116 splat_taskq_test2_func1(void *arg)
117 {
118 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
119
120 ASSERT(tq_arg);
121 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
122 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
123 tq_arg->name, tq_arg->id,
124 sym2str(splat_taskq_test2_func1),
125 tq_arg->flag * 2, tq_arg->flag);
126 tq_arg->flag *= 2;
127 }
128
129 static void
130 splat_taskq_test2_func2(void *arg)
131 {
132 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
133
134 ASSERT(tq_arg);
135 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
136 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
137 tq_arg->name, tq_arg->id,
138 sym2str(splat_taskq_test2_func2),
139 tq_arg->flag + 1, tq_arg->flag);
140 tq_arg->flag += 1;
141 }
142
143 #define TEST2_TASKQS 8
144 #define TEST2_THREADS_PER_TASKQ 4
145
146 static int
147 splat_taskq_test2(struct file *file, void *arg) {
148 taskq_t *tq[TEST2_TASKQS] = { NULL };
149 taskqid_t id;
150 splat_taskq_arg_t tq_args[TEST2_TASKQS];
151 int i, rc = 0;
152
153 for (i = 0; i < TEST2_TASKQS; i++) {
154
155 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' "
156 "creating\n", SPLAT_TASKQ_TEST2_NAME, i);
157 if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
158 TEST2_THREADS_PER_TASKQ,
159 maxclsyspri, 50, INT_MAX,
160 TASKQ_PREPOPULATE)) == NULL) {
161 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
162 "Taskq '%s/%d' create failed\n",
163 SPLAT_TASKQ_TEST2_NAME, i);
164 rc = -EINVAL;
165 break;
166 }
167
168 tq_args[i].flag = i;
169 tq_args[i].id = i;
170 tq_args[i].file = file;
171 tq_args[i].name = SPLAT_TASKQ_TEST2_NAME;
172
173 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
174 "Taskq '%s/%d' function '%s' dispatching\n",
175 tq_args[i].name, tq_args[i].id,
176 sym2str(splat_taskq_test2_func1));
177 if ((id = taskq_dispatch(
178 tq[i], splat_taskq_test2_func1,
179 &tq_args[i], TQ_SLEEP)) == 0) {
180 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
181 "Taskq '%s/%d' function '%s' dispatch "
182 "failed\n", tq_args[i].name, tq_args[i].id,
183 sym2str(splat_taskq_test2_func1));
184 rc = -EINVAL;
185 break;
186 }
187
188 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
189 "Taskq '%s/%d' function '%s' dispatching\n",
190 tq_args[i].name, tq_args[i].id,
191 sym2str(splat_taskq_test2_func2));
192 if ((id = taskq_dispatch(
193 tq[i], splat_taskq_test2_func2,
194 &tq_args[i], TQ_SLEEP)) == 0) {
195 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
196 "Taskq '%s/%d' function '%s' dispatch failed\n",
197 tq_args[i].name, tq_args[i].id,
198 sym2str(splat_taskq_test2_func2));
199 rc = -EINVAL;
200 break;
201 }
202 }
203
204 /* When rc is set we're effectively just doing cleanup here, so
205 * ignore new errors in that case. They just cause noise. */
206 for (i = 0; i < TEST2_TASKQS; i++) {
207 if (tq[i] != NULL) {
208 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
209 "Taskq '%s/%d' waiting\n",
210 tq_args[i].name, tq_args[i].id);
211 taskq_wait(tq[i]);
212 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
213 "Taskq '%s/%d; destroying\n",
214 tq_args[i].name, tq_args[i].id);
215 taskq_destroy(tq[i]);
216
217 if (!rc && tq_args[i].flag != ((i * 2) + 1)) {
218 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
219 "Taskq '%s/%d' processed tasks "
220 "out of order; %d != %d\n",
221 tq_args[i].name, tq_args[i].id,
222 tq_args[i].flag, i * 2 + 1);
223 rc = -EINVAL;
224 } else {
225 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
226 "Taskq '%s/%d' processed tasks "
227 "in the correct order; %d == %d\n",
228 tq_args[i].name, tq_args[i].id,
229 tq_args[i].flag, i * 2 + 1);
230 }
231 }
232 }
233
234 return rc;
235 }
236
237 /* Validation Test 3 - Use the global system task queue with a single
238 * task, * wait until task completes, ensure task ran properly.
239 */
240 static int
241 splat_taskq_test3(struct file *file, void *arg)
242 {
243 taskqid_t id;
244 splat_taskq_arg_t tq_arg;
245
246 tq_arg.flag = 0;
247 tq_arg.id = 0;
248 tq_arg.file = file;
249 tq_arg.name = SPLAT_TASKQ_TEST3_NAME;
250
251 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
252 "Taskq '%s' function '%s' dispatching\n",
253 tq_arg.name, sym2str(splat_taskq_test13_func));
254 if ((id = taskq_dispatch(system_taskq, splat_taskq_test13_func,
255 &tq_arg, TQ_SLEEP)) == 0) {
256 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME,
257 "Taskq '%s' function '%s' dispatch failed\n",
258 tq_arg.name, sym2str(splat_taskq_test13_func));
259 return -EINVAL;
260 }
261
262 splat_vprint(file, SPLAT_TASKQ_TEST3_NAME, "Taskq '%s' waiting\n",
263 tq_arg.name);
264 taskq_wait(system_taskq);
265
266 return (tq_arg.flag) ? 0 : -EINVAL;
267 }
268
269 splat_subsystem_t *
270 splat_taskq_init(void)
271 {
272 splat_subsystem_t *sub;
273
274 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
275 if (sub == NULL)
276 return NULL;
277
278 memset(sub, 0, sizeof(*sub));
279 strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE);
280 strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE);
281 INIT_LIST_HEAD(&sub->subsystem_list);
282 INIT_LIST_HEAD(&sub->test_list);
283 spin_lock_init(&sub->test_lock);
284 sub->desc.id = SPLAT_SUBSYSTEM_TASKQ;
285
286 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC,
287 SPLAT_TASKQ_TEST1_ID, splat_taskq_test1);
288 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC,
289 SPLAT_TASKQ_TEST2_ID, splat_taskq_test2);
290 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST3_NAME, SPLAT_TASKQ_TEST3_DESC,
291 SPLAT_TASKQ_TEST3_ID, splat_taskq_test3);
292
293 return sub;
294 }
295
296 void
297 splat_taskq_fini(splat_subsystem_t *sub)
298 {
299 ASSERT(sub);
300 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST3_ID);
301 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID);
302 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID);
303
304 kfree(sub);
305 }
306
307 int
308 splat_taskq_id(void) {
309 return SPLAT_SUBSYSTEM_TASKQ;
310 }