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