]> git.proxmox.com Git - mirror_spl.git/blob - modules/splat/splat-taskq.c
Go through and add a header with the proper UCRL number.
[mirror_spl.git] / modules / 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 typedef struct splat_taskq_arg {
42 int flag;
43 int id;
44 struct file *file;
45 const char *name;
46 } splat_taskq_arg_t;
47
48 /* Validation Test 1 - Create a taskq, queue a task, wait until
49 * task completes, ensure task ran properly, cleanup taskq,
50 */
51 static void
52 splat_taskq_test1_func(void *arg)
53 {
54 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
55
56 ASSERT(tq_arg);
57 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST1_NAME,
58 "Taskq '%s' function '%s' setting flag\n",
59 tq_arg->name, sym2str(splat_taskq_test1_func));
60 tq_arg->flag = 1;
61 }
62
63 static int
64 splat_taskq_test1(struct file *file, void *arg)
65 {
66 taskq_t *tq;
67 taskqid_t id;
68 splat_taskq_arg_t tq_arg;
69
70 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' creating\n",
71 SPLAT_TASKQ_TEST1_NAME);
72 if ((tq = taskq_create(SPLAT_TASKQ_TEST1_NAME, 1, maxclsyspri,
73 50, INT_MAX, TASKQ_PREPOPULATE)) == NULL) {
74 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
75 "Taskq '%s' create failed\n",
76 SPLAT_TASKQ_TEST1_NAME);
77 return -EINVAL;
78 }
79
80 tq_arg.flag = 0;
81 tq_arg.id = 0;
82 tq_arg.file = file;
83 tq_arg.name = SPLAT_TASKQ_TEST1_NAME;
84
85 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
86 "Taskq '%s' function '%s' dispatching\n",
87 tq_arg.name, sym2str(splat_taskq_test1_func));
88 if ((id = taskq_dispatch(tq, splat_taskq_test1_func,
89 &tq_arg, TQ_SLEEP)) == 0) {
90 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME,
91 "Taskq '%s' function '%s' dispatch failed\n",
92 tq_arg.name, sym2str(splat_taskq_test1_func));
93 taskq_destroy(tq);
94 return -EINVAL;
95 }
96
97 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' waiting\n",
98 tq_arg.name);
99 taskq_wait(tq);
100 splat_vprint(file, SPLAT_TASKQ_TEST1_NAME, "Taskq '%s' destroying\n",
101 tq_arg.name);
102 taskq_destroy(tq);
103
104 return (tq_arg.flag) ? 0 : -EINVAL;
105 }
106
107 /* Validation Test 2 - Create multiple taskq's, each with multiple tasks,
108 * wait until all tasks complete, ensure all tasks ran properly and in the
109 * the correct order, cleanup taskq's
110 */
111 static void
112 splat_taskq_test2_func1(void *arg)
113 {
114 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
115
116 ASSERT(tq_arg);
117 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
118 "Taskq '%s/%d' function '%s' flag = %d = %d * 2\n",
119 tq_arg->name, tq_arg->id,
120 sym2str(splat_taskq_test2_func1),
121 tq_arg->flag * 2, tq_arg->flag);
122 tq_arg->flag *= 2;
123 }
124
125 static void
126 splat_taskq_test2_func2(void *arg)
127 {
128 splat_taskq_arg_t *tq_arg = (splat_taskq_arg_t *)arg;
129
130 ASSERT(tq_arg);
131 splat_vprint(tq_arg->file, SPLAT_TASKQ_TEST2_NAME,
132 "Taskq '%s/%d' function '%s' flag = %d = %d + 1\n",
133 tq_arg->name, tq_arg->id,
134 sym2str(splat_taskq_test2_func2),
135 tq_arg->flag + 1, tq_arg->flag);
136 tq_arg->flag += 1;
137 }
138
139 #define TEST2_TASKQS 8
140 #define TEST2_THREADS_PER_TASKQ 4
141
142 static int
143 splat_taskq_test2(struct file *file, void *arg) {
144 taskq_t *tq[TEST2_TASKQS] = { NULL };
145 taskqid_t id;
146 splat_taskq_arg_t tq_args[TEST2_TASKQS];
147 int i, rc = 0;
148
149 for (i = 0; i < TEST2_TASKQS; i++) {
150
151 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME, "Taskq '%s/%d' "
152 "creating\n", SPLAT_TASKQ_TEST2_NAME, i);
153 if ((tq[i] = taskq_create(SPLAT_TASKQ_TEST2_NAME,
154 TEST2_THREADS_PER_TASKQ,
155 maxclsyspri, 50, INT_MAX,
156 TASKQ_PREPOPULATE)) == NULL) {
157 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
158 "Taskq '%s/%d' create failed\n",
159 SPLAT_TASKQ_TEST2_NAME, i);
160 rc = -EINVAL;
161 break;
162 }
163
164 tq_args[i].flag = i;
165 tq_args[i].id = i;
166 tq_args[i].file = file;
167 tq_args[i].name = SPLAT_TASKQ_TEST2_NAME;
168
169 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
170 "Taskq '%s/%d' function '%s' dispatching\n",
171 tq_args[i].name, tq_args[i].id,
172 sym2str(splat_taskq_test2_func1));
173 if ((id = taskq_dispatch(
174 tq[i], splat_taskq_test2_func1,
175 &tq_args[i], TQ_SLEEP)) == 0) {
176 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
177 "Taskq '%s/%d' function '%s' dispatch "
178 "failed\n", tq_args[i].name, tq_args[i].id,
179 sym2str(splat_taskq_test2_func1));
180 rc = -EINVAL;
181 break;
182 }
183
184 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
185 "Taskq '%s/%d' function '%s' dispatching\n",
186 tq_args[i].name, tq_args[i].id,
187 sym2str(splat_taskq_test2_func2));
188 if ((id = taskq_dispatch(
189 tq[i], splat_taskq_test2_func2,
190 &tq_args[i], TQ_SLEEP)) == 0) {
191 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
192 "Taskq '%s/%d' function '%s' dispatch failed\n",
193 tq_args[i].name, tq_args[i].id,
194 sym2str(splat_taskq_test2_func2));
195 rc = -EINVAL;
196 break;
197 }
198 }
199
200 /* When rc is set we're effectively just doing cleanup here, so
201 * ignore new errors in that case. They just cause noise. */
202 for (i = 0; i < TEST2_TASKQS; i++) {
203 if (tq[i] != NULL) {
204 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
205 "Taskq '%s/%d' waiting\n",
206 tq_args[i].name, tq_args[i].id);
207 taskq_wait(tq[i]);
208 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
209 "Taskq '%s/%d; destroying\n",
210 tq_args[i].name, tq_args[i].id);
211 taskq_destroy(tq[i]);
212
213 if (!rc && tq_args[i].flag != ((i * 2) + 1)) {
214 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
215 "Taskq '%s/%d' processed tasks "
216 "out of order; %d != %d\n",
217 tq_args[i].name, tq_args[i].id,
218 tq_args[i].flag, i * 2 + 1);
219 rc = -EINVAL;
220 } else {
221 splat_vprint(file, SPLAT_TASKQ_TEST2_NAME,
222 "Taskq '%s/%d' processed tasks "
223 "in the correct order; %d == %d\n",
224 tq_args[i].name, tq_args[i].id,
225 tq_args[i].flag, i * 2 + 1);
226 }
227 }
228 }
229
230 return rc;
231 }
232
233 splat_subsystem_t *
234 splat_taskq_init(void)
235 {
236 splat_subsystem_t *sub;
237
238 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
239 if (sub == NULL)
240 return NULL;
241
242 memset(sub, 0, sizeof(*sub));
243 strncpy(sub->desc.name, SPLAT_TASKQ_NAME, SPLAT_NAME_SIZE);
244 strncpy(sub->desc.desc, SPLAT_TASKQ_DESC, SPLAT_DESC_SIZE);
245 INIT_LIST_HEAD(&sub->subsystem_list);
246 INIT_LIST_HEAD(&sub->test_list);
247 spin_lock_init(&sub->test_lock);
248 sub->desc.id = SPLAT_SUBSYSTEM_TASKQ;
249
250 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST1_NAME, SPLAT_TASKQ_TEST1_DESC,
251 SPLAT_TASKQ_TEST1_ID, splat_taskq_test1);
252 SPLAT_TEST_INIT(sub, SPLAT_TASKQ_TEST2_NAME, SPLAT_TASKQ_TEST2_DESC,
253 SPLAT_TASKQ_TEST2_ID, splat_taskq_test2);
254
255 return sub;
256 }
257
258 void
259 splat_taskq_fini(splat_subsystem_t *sub)
260 {
261 ASSERT(sub);
262 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST2_ID);
263 SPLAT_TEST_FINI(sub, SPLAT_TASKQ_TEST1_ID);
264
265 kfree(sub);
266 }
267
268 int
269 splat_taskq_id(void) {
270 return SPLAT_SUBSYSTEM_TASKQ;
271 }