]> git.proxmox.com Git - mirror_spl-debian.git/blob - modules/splat/splat-mutex.c
640f8f407154dc004d37c7fae8d74a0bd4193d37
[mirror_spl-debian.git] / modules / splat / splat-mutex.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_MUTEX 0x0400
30 #define SPLAT_MUTEX_NAME "mutex"
31 #define SPLAT_MUTEX_DESC "Kernel Mutex Tests"
32
33 #define SPLAT_MUTEX_TEST1_ID 0x0401
34 #define SPLAT_MUTEX_TEST1_NAME "tryenter"
35 #define SPLAT_MUTEX_TEST1_DESC "Validate mutex_tryenter() correctness"
36
37 #define SPLAT_MUTEX_TEST2_ID 0x0402
38 #define SPLAT_MUTEX_TEST2_NAME "race"
39 #define SPLAT_MUTEX_TEST2_DESC "Many threads entering/exiting the mutex"
40
41 #define SPLAT_MUTEX_TEST3_ID 0x0403
42 #define SPLAT_MUTEX_TEST3_NAME "owned"
43 #define SPLAT_MUTEX_TEST3_DESC "Validate mutex_owned() correctness"
44
45 #define SPLAT_MUTEX_TEST4_ID 0x0404
46 #define SPLAT_MUTEX_TEST4_NAME "owner"
47 #define SPLAT_MUTEX_TEST4_DESC "Validate mutex_owner() correctness"
48
49 #define SPLAT_MUTEX_TEST_MAGIC 0x115599DDUL
50 #define SPLAT_MUTEX_TEST_NAME "mutex_test"
51 #define SPLAT_MUTEX_TEST_WORKQ "mutex_wq"
52 #define SPLAT_MUTEX_TEST_COUNT 128
53
54 typedef struct mutex_priv {
55 unsigned long mp_magic;
56 struct file *mp_file;
57 struct work_struct mp_work[SPLAT_MUTEX_TEST_COUNT];
58 kmutex_t mp_mtx;
59 int mp_rc;
60 } mutex_priv_t;
61
62 #ifdef HAVE_3ARGS_INIT_WORK
63 static void
64 splat_mutex_test1_work(void *priv)
65 {
66 mutex_priv_t *mp = (mutex_priv_t *)priv;
67
68 ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
69 mp->mp_rc = 0;
70
71 if (!mutex_tryenter(&mp->mp_mtx))
72 mp->mp_rc = -EBUSY;
73 }
74 #endif
75
76 static int
77 splat_mutex_test1(struct file *file, void *arg)
78 {
79 int rc = 0;
80 #ifdef HAVE_3ARGS_INIT_WORK
81 struct workqueue_struct *wq;
82 struct work_struct work;
83 mutex_priv_t *mp;
84
85 mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL);
86 if (mp == NULL)
87 return -ENOMEM;
88
89 wq = create_singlethread_workqueue(SPLAT_MUTEX_TEST_WORKQ);
90 if (wq == NULL) {
91 rc = -ENOMEM;
92 goto out2;
93 }
94
95 mutex_init(&(mp->mp_mtx), SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
96 mutex_enter(&(mp->mp_mtx));
97
98 mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC;
99 mp->mp_file = file;
100 INIT_WORK(&work, splat_mutex_test1_work, mp);
101
102 /* Schedule a work item which will try and aquire the mutex via
103 * mutex_tryenter() while its held. This should fail and the work
104 * item will indicte this status in the passed private data. */
105 if (!queue_work(wq, &work)) {
106 mutex_exit(&(mp->mp_mtx));
107 rc = -EINVAL;
108 goto out;
109 }
110
111 flush_workqueue(wq);
112 mutex_exit(&(mp->mp_mtx));
113
114 /* Work item successfully aquired mutex, very bad! */
115 if (mp->mp_rc != -EBUSY) {
116 rc = -EINVAL;
117 goto out;
118 }
119
120 splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
121 "mutex_trylock() correctly failed when mutex held\n");
122
123 /* Schedule a work item which will try and aquire the mutex via
124 * mutex_tryenter() while it is not held. This should work and
125 * the item will indicte this status in the passed private data. */
126 if (!queue_work(wq, &work)) {
127 rc = -EINVAL;
128 goto out;
129 }
130
131 flush_workqueue(wq);
132
133 /* Work item failed to aquire mutex, very bad! */
134 if (mp->mp_rc != 0) {
135 rc = -EINVAL;
136 goto out;
137 }
138
139 splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
140 "mutex_trylock() correctly succeeded when mutex unheld\n");
141 out:
142 mutex_destroy(&(mp->mp_mtx));
143 destroy_workqueue(wq);
144 out2:
145 kfree(mp);
146 #endif
147 return rc;
148 }
149
150 #ifdef HAVE_3ARGS_INIT_WORK
151 static void
152 splat_mutex_test2_work(void *priv)
153 {
154 mutex_priv_t *mp = (mutex_priv_t *)priv;
155 int rc;
156
157 ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
158
159 /* Read the value before sleeping and write it after we wake up to
160 * maximize the chance of a race if mutexs are not working properly */
161 mutex_enter(&mp->mp_mtx);
162 rc = mp->mp_rc;
163 set_current_state(TASK_INTERRUPTIBLE);
164 schedule_timeout(HZ / 100); /* 1/100 of a second */
165 mp->mp_rc = rc + 1;
166 mutex_exit(&mp->mp_mtx);
167 }
168 #endif
169
170 static int
171 splat_mutex_test2(struct file *file, void *arg)
172 {
173 int rc = 0;
174 #ifdef HAVE_3ARGS_INIT_WORK
175 struct workqueue_struct *wq;
176 mutex_priv_t *mp;
177 int i;
178
179 mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL);
180 if (mp == NULL)
181 return -ENOMEM;
182
183 /* Create a thread per CPU items on queue will race */
184 wq = create_workqueue(SPLAT_MUTEX_TEST_WORKQ);
185 if (wq == NULL) {
186 rc = -ENOMEM;
187 goto out;
188 }
189
190 mutex_init(&(mp->mp_mtx), SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
191
192 mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC;
193 mp->mp_file = file;
194 mp->mp_rc = 0;
195
196 /* Schedule N work items to the work queue each of which enters the
197 * mutex, sleeps briefly, then exits the mutex. On a multiprocessor
198 * box these work items will be handled by all available CPUs. The
199 * mutex is instrumented such that if any two processors are in the
200 * critical region at the same time the system will panic. If the
201 * mutex is implemented right this will never happy, that's a pass. */
202 for (i = 0; i < SPLAT_MUTEX_TEST_COUNT; i++) {
203 INIT_WORK(&(mp->mp_work[i]), splat_mutex_test2_work, mp);
204
205 if (!queue_work(wq, &(mp->mp_work[i]))) {
206 splat_vprint(file, SPLAT_MUTEX_TEST2_NAME,
207 "Failed to queue work id %d\n", i);
208 rc = -EINVAL;
209 }
210 }
211
212 flush_workqueue(wq);
213
214 if (mp->mp_rc == SPLAT_MUTEX_TEST_COUNT) {
215 splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads "
216 "correctly entered/exited the mutex %d times\n",
217 num_online_cpus(), mp->mp_rc);
218 } else {
219 splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads "
220 "only processed %d/%d mutex work items\n",
221 num_online_cpus(), mp->mp_rc, SPLAT_MUTEX_TEST_COUNT);
222 rc = -EINVAL;
223 }
224
225 mutex_destroy(&(mp->mp_mtx));
226 destroy_workqueue(wq);
227 out:
228 kfree(mp);
229 #endif
230 return rc;
231 }
232
233 static int
234 splat_mutex_test3(struct file *file, void *arg)
235 {
236 kmutex_t mtx;
237 int rc = 0;
238
239 mutex_init(&mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
240
241 mutex_enter(&mtx);
242
243 /* Mutex should be owned by current */
244 if (!mutex_owned(&mtx)) {
245 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should "
246 "be owned by pid %d but is owned by pid %d\n",
247 current->pid, mtx.km_owner ? mtx.km_owner->pid : -1);
248 rc = -EINVAL;
249 goto out;
250 }
251
252 mutex_exit(&mtx);
253
254 /* Mutex should not be owned by any task */
255 if (mutex_owned(&mtx)) {
256 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should "
257 "not be owned but is owned by pid %d\n",
258 mtx.km_owner ? mtx.km_owner->pid : -1);
259 rc = -EINVAL;
260 goto out;
261 }
262
263 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s",
264 "Correct mutex_owned() behavior\n");
265 out:
266 mutex_destroy(&mtx);
267
268 return rc;
269 }
270
271 static int
272 splat_mutex_test4(struct file *file, void *arg)
273 {
274 kmutex_t mtx;
275 kthread_t *owner;
276 int rc = 0;
277
278 mutex_init(&mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
279
280 mutex_enter(&mtx);
281
282 /* Mutex should be owned by current */
283 owner = mutex_owner(&mtx);
284 if (current != owner) {
285 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should "
286 "be owned by pid %d but is owned by pid %d\n",
287 current->pid, owner ? owner->pid : -1);
288 rc = -EINVAL;
289 goto out;
290 }
291
292 mutex_exit(&mtx);
293
294 /* Mutex should not be owned by any task */
295 owner = mutex_owner(&mtx);
296 if (owner) {
297 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should not "
298 "be owned but is owned by pid %d\n", owner->pid);
299 rc = -EINVAL;
300 goto out;
301 }
302
303 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s",
304 "Correct mutex_owner() behavior\n");
305 out:
306 mutex_destroy(&mtx);
307
308 return rc;
309 }
310
311 splat_subsystem_t *
312 splat_mutex_init(void)
313 {
314 splat_subsystem_t *sub;
315
316 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
317 if (sub == NULL)
318 return NULL;
319
320 memset(sub, 0, sizeof(*sub));
321 strncpy(sub->desc.name, SPLAT_MUTEX_NAME, SPLAT_NAME_SIZE);
322 strncpy(sub->desc.desc, SPLAT_MUTEX_DESC, SPLAT_DESC_SIZE);
323 INIT_LIST_HEAD(&sub->subsystem_list);
324 INIT_LIST_HEAD(&sub->test_list);
325 spin_lock_init(&sub->test_lock);
326 sub->desc.id = SPLAT_SUBSYSTEM_MUTEX;
327
328 SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST1_NAME, SPLAT_MUTEX_TEST1_DESC,
329 SPLAT_MUTEX_TEST1_ID, splat_mutex_test1);
330 SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST2_NAME, SPLAT_MUTEX_TEST2_DESC,
331 SPLAT_MUTEX_TEST2_ID, splat_mutex_test2);
332 SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST3_NAME, SPLAT_MUTEX_TEST3_DESC,
333 SPLAT_MUTEX_TEST3_ID, splat_mutex_test3);
334 SPLAT_TEST_INIT(sub, SPLAT_MUTEX_TEST4_NAME, SPLAT_MUTEX_TEST4_DESC,
335 SPLAT_MUTEX_TEST4_ID, splat_mutex_test4);
336
337 return sub;
338 }
339
340 void
341 splat_mutex_fini(splat_subsystem_t *sub)
342 {
343 ASSERT(sub);
344 SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST4_ID);
345 SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST3_ID);
346 SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST2_ID);
347 SPLAT_TEST_FINI(sub, SPLAT_MUTEX_TEST1_ID);
348
349 kfree(sub);
350 }
351
352 int
353 splat_mutex_id(void) {
354 return SPLAT_SUBSYSTEM_MUTEX;
355 }