]> git.proxmox.com Git - mirror_spl-debian.git/blame - modules/splat/splat-mutex.c
Make the splat load message caps just for consistency
[mirror_spl-debian.git] / modules / splat / splat-mutex.c
CommitLineData
715f6251 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
7c50328b 27#include "splat-internal.h"
f1ca4da6 28
7c50328b 29#define SPLAT_SUBSYSTEM_MUTEX 0x0400
30#define SPLAT_MUTEX_NAME "mutex"
31#define SPLAT_MUTEX_DESC "Kernel Mutex Tests"
f1ca4da6 32
7c50328b 33#define SPLAT_MUTEX_TEST1_ID 0x0401
34#define SPLAT_MUTEX_TEST1_NAME "tryenter"
35#define SPLAT_MUTEX_TEST1_DESC "Validate mutex_tryenter() correctness"
f1ca4da6 36
7c50328b 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"
f1ca4da6 40
7c50328b 41#define SPLAT_MUTEX_TEST3_ID 0x0403
42#define SPLAT_MUTEX_TEST3_NAME "owned"
43#define SPLAT_MUTEX_TEST3_DESC "Validate mutex_owned() correctness"
f1ca4da6 44
7c50328b 45#define SPLAT_MUTEX_TEST4_ID 0x0404
46#define SPLAT_MUTEX_TEST4_NAME "owner"
47#define SPLAT_MUTEX_TEST4_DESC "Validate mutex_owner() correctness"
f1ca4da6 48
7c50328b 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
f1ca4da6 53
54typedef struct mutex_priv {
55 unsigned long mp_magic;
56 struct file *mp_file;
7c50328b 57 struct work_struct mp_work[SPLAT_MUTEX_TEST_COUNT];
f1ca4da6 58 kmutex_t mp_mtx;
59 int mp_rc;
60} mutex_priv_t;
61
57d86234 62#ifdef HAVE_3ARGS_INIT_WORK
f1ca4da6 63static void
7c50328b 64splat_mutex_test1_work(void *priv)
f1ca4da6 65{
66 mutex_priv_t *mp = (mutex_priv_t *)priv;
67
7c50328b 68 ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
f1ca4da6 69 mp->mp_rc = 0;
70
71 if (!mutex_tryenter(&mp->mp_mtx))
72 mp->mp_rc = -EBUSY;
73}
57d86234 74#endif
f1ca4da6 75
76static int
7c50328b 77splat_mutex_test1(struct file *file, void *arg)
f1ca4da6 78{
57d86234 79 int rc = 0;
80#ifdef HAVE_3ARGS_INIT_WORK
f1ca4da6 81 struct workqueue_struct *wq;
82 struct work_struct work;
83 mutex_priv_t *mp;
f1ca4da6 84
85 mp = (mutex_priv_t *)kmalloc(sizeof(*mp), GFP_KERNEL);
86 if (mp == NULL)
87 return -ENOMEM;
88
7c50328b 89 wq = create_singlethread_workqueue(SPLAT_MUTEX_TEST_WORKQ);
f1ca4da6 90 if (wq == NULL) {
91 rc = -ENOMEM;
92 goto out2;
93 }
94
7c50328b 95 mutex_init(&(mp->mp_mtx), SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
f1ca4da6 96 mutex_enter(&(mp->mp_mtx));
97
7c50328b 98 mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC;
f1ca4da6 99 mp->mp_file = file;
7c50328b 100 INIT_WORK(&work, splat_mutex_test1_work, mp);
f1ca4da6 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
7c50328b 120 splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
f1ca4da6 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
7c50328b 139 splat_vprint(file, SPLAT_MUTEX_TEST1_NAME, "%s",
f1ca4da6 140 "mutex_trylock() correctly succeeded when mutex unheld\n");
141out:
142 mutex_destroy(&(mp->mp_mtx));
143 destroy_workqueue(wq);
144out2:
145 kfree(mp);
57d86234 146#endif
f1ca4da6 147 return rc;
148}
149
57d86234 150#ifdef HAVE_3ARGS_INIT_WORK
f1ca4da6 151static void
7c50328b 152splat_mutex_test2_work(void *priv)
f1ca4da6 153{
154 mutex_priv_t *mp = (mutex_priv_t *)priv;
155 int rc;
156
7c50328b 157 ASSERT(mp->mp_magic == SPLAT_MUTEX_TEST_MAGIC);
f1ca4da6 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}
57d86234 168#endif
f1ca4da6 169
170static int
7c50328b 171splat_mutex_test2(struct file *file, void *arg)
f1ca4da6 172{
57d86234 173 int rc = 0;
174#ifdef HAVE_3ARGS_INIT_WORK
f1ca4da6 175 struct workqueue_struct *wq;
176 mutex_priv_t *mp;
57d86234 177 int i;
f1ca4da6 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 */
7c50328b 184 wq = create_workqueue(SPLAT_MUTEX_TEST_WORKQ);
f1ca4da6 185 if (wq == NULL) {
186 rc = -ENOMEM;
187 goto out;
188 }
189
7c50328b 190 mutex_init(&(mp->mp_mtx), SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
f1ca4da6 191
7c50328b 192 mp->mp_magic = SPLAT_MUTEX_TEST_MAGIC;
f1ca4da6 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. */
7c50328b 202 for (i = 0; i < SPLAT_MUTEX_TEST_COUNT; i++) {
203 INIT_WORK(&(mp->mp_work[i]), splat_mutex_test2_work, mp);
f1ca4da6 204
205 if (!queue_work(wq, &(mp->mp_work[i]))) {
7c50328b 206 splat_vprint(file, SPLAT_MUTEX_TEST2_NAME,
f1ca4da6 207 "Failed to queue work id %d\n", i);
208 rc = -EINVAL;
209 }
210 }
211
212 flush_workqueue(wq);
213
7c50328b 214 if (mp->mp_rc == SPLAT_MUTEX_TEST_COUNT) {
215 splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads "
f1ca4da6 216 "correctly entered/exited the mutex %d times\n",
217 num_online_cpus(), mp->mp_rc);
218 } else {
7c50328b 219 splat_vprint(file, SPLAT_MUTEX_TEST2_NAME, "%d racing threads "
f1ca4da6 220 "only processed %d/%d mutex work items\n",
7c50328b 221 num_online_cpus(), mp->mp_rc, SPLAT_MUTEX_TEST_COUNT);
f1ca4da6 222 rc = -EINVAL;
223 }
224
225 mutex_destroy(&(mp->mp_mtx));
226 destroy_workqueue(wq);
227out:
228 kfree(mp);
57d86234 229#endif
f1ca4da6 230 return rc;
231}
232
233static int
7c50328b 234splat_mutex_test3(struct file *file, void *arg)
f1ca4da6 235{
236 kmutex_t mtx;
237 int rc = 0;
238
7c50328b 239 mutex_init(&mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
f1ca4da6 240
241 mutex_enter(&mtx);
242
243 /* Mutex should be owned by current */
244 if (!mutex_owned(&mtx)) {
7c50328b 245 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should "
f1ca4da6 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)) {
7c50328b 256 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should "
f1ca4da6 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
7c50328b 263 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s",
f1ca4da6 264 "Correct mutex_owned() behavior\n");
265out:
266 mutex_destroy(&mtx);
267
268 return rc;
269}
270
271static int
7c50328b 272splat_mutex_test4(struct file *file, void *arg)
f1ca4da6 273{
274 kmutex_t mtx;
275 kthread_t *owner;
276 int rc = 0;
277
7c50328b 278 mutex_init(&mtx, SPLAT_MUTEX_TEST_NAME, MUTEX_DEFAULT, NULL);
f1ca4da6 279
280 mutex_enter(&mtx);
281
282 /* Mutex should be owned by current */
283 owner = mutex_owner(&mtx);
284 if (current != owner) {
7c50328b 285 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should "
f1ca4da6 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) {
7c50328b 297 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "Mutex should not "
f1ca4da6 298 "be owned but is owned by pid %d\n", owner->pid);
299 rc = -EINVAL;
300 goto out;
301 }
302
7c50328b 303 splat_vprint(file, SPLAT_MUTEX_TEST3_NAME, "%s",
f1ca4da6 304 "Correct mutex_owner() behavior\n");
305out:
306 mutex_destroy(&mtx);
307
308 return rc;
309}
310
7c50328b 311splat_subsystem_t *
312splat_mutex_init(void)
f1ca4da6 313{
7c50328b 314 splat_subsystem_t *sub;
f1ca4da6 315
316 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
317 if (sub == NULL)
318 return NULL;
319
320 memset(sub, 0, sizeof(*sub));
7c50328b 321 strncpy(sub->desc.name, SPLAT_MUTEX_NAME, SPLAT_NAME_SIZE);
322 strncpy(sub->desc.desc, SPLAT_MUTEX_DESC, SPLAT_DESC_SIZE);
f1ca4da6 323 INIT_LIST_HEAD(&sub->subsystem_list);
324 INIT_LIST_HEAD(&sub->test_list);
325 spin_lock_init(&sub->test_lock);
7c50328b 326 sub->desc.id = SPLAT_SUBSYSTEM_MUTEX;
f1ca4da6 327
7c50328b 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);
f1ca4da6 336
337 return sub;
338}
339
340void
7c50328b 341splat_mutex_fini(splat_subsystem_t *sub)
f1ca4da6 342{
343 ASSERT(sub);
7c50328b 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);
f1ca4da6 348
349 kfree(sub);
350}
351
352int
7c50328b 353splat_mutex_id(void) {
354 return SPLAT_SUBSYSTEM_MUTEX;
f1ca4da6 355}