]> git.proxmox.com Git - mirror_spl-debian.git/blob - src/splat/splat-rwlock.c
Initial commit. All spl source written up to this point wrapped
[mirror_spl-debian.git] / src / splat / splat-rwlock.c
1 #include <sys/zfs_context.h>
2 #include <sys/splat-ctl.h>
3
4 #define KZT_SUBSYSTEM_RWLOCK 0x0700
5 #define KZT_RWLOCK_NAME "rwlock"
6 #define KZT_RWLOCK_DESC "Kernel RW Lock Tests"
7
8 #define KZT_RWLOCK_TEST1_ID 0x0701
9 #define KZT_RWLOCK_TEST1_NAME "rwtest1"
10 #define KZT_RWLOCK_TEST1_DESC "Multiple Readers One Writer"
11
12 #define KZT_RWLOCK_TEST2_ID 0x0702
13 #define KZT_RWLOCK_TEST2_NAME "rwtest2"
14 #define KZT_RWLOCK_TEST2_DESC "Multiple Writers"
15
16 #define KZT_RWLOCK_TEST3_ID 0x0703
17 #define KZT_RWLOCK_TEST3_NAME "rwtest3"
18 #define KZT_RWLOCK_TEST3_DESC "Owner Verification"
19
20 #define KZT_RWLOCK_TEST4_ID 0x0704
21 #define KZT_RWLOCK_TEST4_NAME "rwtest4"
22 #define KZT_RWLOCK_TEST4_DESC "Trylock Test"
23
24 #define KZT_RWLOCK_TEST5_ID 0x0705
25 #define KZT_RWLOCK_TEST5_NAME "rwtest5"
26 #define KZT_RWLOCK_TEST5_DESC "Write Downgrade Test"
27
28 #define KZT_RWLOCK_TEST6_ID 0x0706
29 #define KZT_RWLOCK_TEST6_NAME "rwtest6"
30 #define KZT_RWLOCK_TEST6_DESC "Read Upgrade Test"
31
32 #define KZT_RWLOCK_TEST_MAGIC 0x115599DDUL
33 #define KZT_RWLOCK_TEST_NAME "rwlock_test"
34 #define KZT_RWLOCK_TEST_COUNT 8
35
36 #define KZT_RWLOCK_RELEASE_INIT 0
37 #define KZT_RWLOCK_RELEASE_WRITERS 1
38 #define KZT_RWLOCK_RELEASE_READERS 2
39
40 typedef struct rw_priv {
41 unsigned long rw_magic;
42 struct file *rw_file;
43 krwlock_t rwl;
44 spinlock_t rw_priv_lock;
45 wait_queue_head_t rw_waitq;
46 atomic_t rw_completed;
47 atomic_t rw_acquired;
48 atomic_t rw_waiters;
49 atomic_t rw_release;
50 } rw_priv_t;
51
52 typedef struct rw_thr {
53 int rwt_id;
54 const char *rwt_name;
55 rw_priv_t *rwt_rwp;
56 int rwt_rc;
57 } rw_thr_t;
58
59 static inline void
60 kzt_rwlock_sleep(signed long delay)
61 {
62 set_current_state(TASK_INTERRUPTIBLE);
63 schedule_timeout(delay);
64 }
65
66 #define kzt_rwlock_lock_and_test(lock,test) \
67 ({ \
68 int ret = 0; \
69 \
70 spin_lock(lock); \
71 ret = (test) ? 1 : 0; \
72 spin_unlock(lock); \
73 ret; \
74 })
75
76 void kzt_init_rw_priv(rw_priv_t *rwv, struct file *file)
77 {
78 rwv->rw_magic = KZT_RWLOCK_TEST_MAGIC;
79 rwv->rw_file = file;
80 spin_lock_init(&rwv->rw_priv_lock);
81 init_waitqueue_head(&rwv->rw_waitq);
82 atomic_set(&rwv->rw_completed, 0);
83 atomic_set(&rwv->rw_acquired, 0);
84 atomic_set(&rwv->rw_waiters, 0);
85 atomic_set(&rwv->rw_release, KZT_RWLOCK_RELEASE_INIT);
86
87 /* Initialize the read/write lock */
88 rw_init(&rwv->rwl, KZT_RWLOCK_TEST_NAME, RW_DEFAULT, NULL);
89 }
90
91 int
92 kzt_rwlock_test1_writer_thread(void *arg)
93 {
94 rw_thr_t *rwt = (rw_thr_t *)arg;
95 rw_priv_t *rwv = rwt->rwt_rwp;
96 uint8_t rnd = 0;
97 char name[16];
98
99 ASSERT(rwv->rw_magic == KZT_RWLOCK_TEST_MAGIC);
100 snprintf(name, sizeof(name), "%s%d",
101 KZT_RWLOCK_TEST_NAME, rwt->rwt_id);
102 daemonize(name);
103 get_random_bytes((void *)&rnd, 1);
104 kzt_rwlock_sleep(rnd * HZ / 1000);
105
106 spin_lock(&rwv->rw_priv_lock);
107 kzt_vprint(rwv->rw_file, rwt->rwt_name,
108 "%s writer thread trying to acquire rwlock with "
109 "%d holding lock and %d waiting\n",
110 name, atomic_read(&rwv->rw_acquired),
111 atomic_read(&rwv->rw_waiters));
112 atomic_inc(&rwv->rw_waiters);
113 spin_unlock(&rwv->rw_priv_lock);
114
115 /* Take the semaphore for writing
116 * release it when we are told to */
117 rw_enter(&rwv->rwl, RW_WRITER);
118
119 spin_lock(&rwv->rw_priv_lock);
120 atomic_dec(&rwv->rw_waiters);
121 atomic_inc(&rwv->rw_acquired);
122 kzt_vprint(rwv->rw_file, rwt->rwt_name,
123 "%s writer thread acquired rwlock with "
124 "%d holding lock and %d waiting\n",
125 name, atomic_read(&rwv->rw_acquired),
126 atomic_read(&rwv->rw_waiters));
127 spin_unlock(&rwv->rw_priv_lock);
128
129 /* Wait here until the control thread
130 * says we can release the write lock */
131 wait_event_interruptible(rwv->rw_waitq,
132 kzt_rwlock_lock_and_test(&rwv->rw_priv_lock,
133 atomic_read(&rwv->rw_release) ==
134 KZT_RWLOCK_RELEASE_WRITERS));
135 spin_lock(&rwv->rw_priv_lock);
136 atomic_inc(&rwv->rw_completed);
137 atomic_dec(&rwv->rw_acquired);
138 kzt_vprint(rwv->rw_file, rwt->rwt_name,
139 "%s writer thread dropped rwlock with "
140 "%d holding lock and %d waiting\n",
141 name, atomic_read(&rwv->rw_acquired),
142 atomic_read(&rwv->rw_waiters));
143 spin_unlock(&rwv->rw_priv_lock);
144
145 /* Release the semaphore */
146 rw_exit(&rwv->rwl);
147 return 0;
148 }
149
150 int
151 kzt_rwlock_test1_reader_thread(void *arg)
152 {
153 rw_thr_t *rwt = (rw_thr_t *)arg;
154 rw_priv_t *rwv = rwt->rwt_rwp;
155 uint8_t rnd = 0;
156 char name[16];
157
158 ASSERT(rwv->rw_magic == KZT_RWLOCK_TEST_MAGIC);
159 snprintf(name, sizeof(name), "%s%d",
160 KZT_RWLOCK_TEST_NAME, rwt->rwt_id);
161 daemonize(name);
162 get_random_bytes((void *)&rnd, 1);
163 kzt_rwlock_sleep(rnd * HZ / 1000);
164
165 /* Don't try and and take the semaphore until
166 * someone else has already acquired it */
167 wait_event_interruptible(rwv->rw_waitq,
168 kzt_rwlock_lock_and_test(&rwv->rw_priv_lock,
169 atomic_read(&rwv->rw_acquired) > 0));
170
171 spin_lock(&rwv->rw_priv_lock);
172 kzt_vprint(rwv->rw_file, rwt->rwt_name,
173 "%s reader thread trying to acquire rwlock with "
174 "%d holding lock and %d waiting\n",
175 name, atomic_read(&rwv->rw_acquired),
176 atomic_read(&rwv->rw_waiters));
177 atomic_inc(&rwv->rw_waiters);
178 spin_unlock(&rwv->rw_priv_lock);
179
180 /* Take the semaphore for reading
181 * release it when we are told to */
182 rw_enter(&rwv->rwl, RW_READER);
183
184 spin_lock(&rwv->rw_priv_lock);
185 atomic_dec(&rwv->rw_waiters);
186 atomic_inc(&rwv->rw_acquired);
187 kzt_vprint(rwv->rw_file, rwt->rwt_name,
188 "%s reader thread acquired rwlock with "
189 "%d holding lock and %d waiting\n",
190 name, atomic_read(&rwv->rw_acquired),
191 atomic_read(&rwv->rw_waiters));
192 spin_unlock(&rwv->rw_priv_lock);
193
194 /* Wait here until the control thread
195 * says we can release the read lock */
196 wait_event_interruptible(rwv->rw_waitq,
197 kzt_rwlock_lock_and_test(&rwv->rw_priv_lock,
198 atomic_read(&rwv->rw_release) ==
199 KZT_RWLOCK_RELEASE_READERS));
200
201 spin_lock(&rwv->rw_priv_lock);
202 atomic_inc(&rwv->rw_completed);
203 atomic_dec(&rwv->rw_acquired);
204 kzt_vprint(rwv->rw_file, rwt->rwt_name,
205 "%s reader thread dropped rwlock with "
206 "%d holding lock and %d waiting\n",
207 name, atomic_read(&rwv->rw_acquired),
208 atomic_read(&rwv->rw_waiters));
209 spin_unlock(&rwv->rw_priv_lock);
210
211 /* Release the semaphore */
212 rw_exit(&rwv->rwl);
213 return 0;
214 }
215
216 static int
217 kzt_rwlock_test1(struct file *file, void *arg)
218 {
219 int i, count = 0, rc = 0;
220 long pids[KZT_RWLOCK_TEST_COUNT];
221 rw_thr_t rwt[KZT_RWLOCK_TEST_COUNT];
222 rw_priv_t rwv;
223
224 /* Initialize private data
225 * including the rwlock */
226 kzt_init_rw_priv(&rwv, file);
227
228 /* Create some threads, the exact number isn't important just as
229 * long as we know how many we managed to create and should expect. */
230 for (i = 0; i < KZT_RWLOCK_TEST_COUNT; i++) {
231 rwt[i].rwt_rwp = &rwv;
232 rwt[i].rwt_id = i;
233 rwt[i].rwt_name = KZT_RWLOCK_TEST1_NAME;
234 rwt[i].rwt_rc = 0;
235
236 /* The first thread will be a writer */
237 if (i == 0) {
238 pids[i] = kernel_thread(kzt_rwlock_test1_writer_thread,
239 &rwt[i], 0);
240 } else {
241 pids[i] = kernel_thread(kzt_rwlock_test1_reader_thread,
242 &rwt[i], 0);
243 }
244
245 if (pids[i] >= 0) {
246 count++;
247 }
248 }
249
250 /* Once the writer has the lock, release the readers */
251 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock, atomic_read(&rwv.rw_acquired) <= 0)) {
252 kzt_rwlock_sleep(1 * HZ);
253 }
254 wake_up_interruptible(&rwv.rw_waitq);
255
256 /* Ensure that there is only 1 writer and all readers are waiting */
257 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
258 atomic_read(&rwv.rw_acquired) != 1 ||
259 atomic_read(&rwv.rw_waiters) !=
260 KZT_RWLOCK_TEST_COUNT - 1)) {
261
262 kzt_rwlock_sleep(1 * HZ);
263 }
264 /* Relase the writer */
265 spin_lock(&rwv.rw_priv_lock);
266 atomic_set(&rwv.rw_release, KZT_RWLOCK_RELEASE_WRITERS);
267 spin_unlock(&rwv.rw_priv_lock);
268 wake_up_interruptible(&rwv.rw_waitq);
269
270 /* Now ensure that there are multiple reader threads holding the lock */
271 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
272 atomic_read(&rwv.rw_acquired) <= 1)) {
273 kzt_rwlock_sleep(1 * HZ);
274 }
275 /* Release the readers */
276 spin_lock(&rwv.rw_priv_lock);
277 atomic_set(&rwv.rw_release, KZT_RWLOCK_RELEASE_READERS);
278 spin_unlock(&rwv.rw_priv_lock);
279 wake_up_interruptible(&rwv.rw_waitq);
280
281 /* Wait for the test to complete */
282 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
283 atomic_read(&rwv.rw_acquired) != 0 ||
284 atomic_read(&rwv.rw_waiters) != 0)) {
285 kzt_rwlock_sleep(1 * HZ);
286
287 }
288
289 rw_destroy(&rwv.rwl);
290 return rc;
291 }
292
293 int
294 kzt_rwlock_test2_writer_thread(void *arg)
295 {
296 rw_thr_t *rwt = (rw_thr_t *)arg;
297 rw_priv_t *rwv = rwt->rwt_rwp;
298 uint8_t rnd = 0;
299 char name[16];
300
301 ASSERT(rwv->rw_magic == KZT_RWLOCK_TEST_MAGIC);
302 snprintf(name, sizeof(name), "%s%d",
303 KZT_RWLOCK_TEST_NAME, rwt->rwt_id);
304 daemonize(name);
305 get_random_bytes((void *)&rnd, 1);
306 kzt_rwlock_sleep(rnd * HZ / 1000);
307
308 /* Here just increment the waiters count even if we are not
309 * exactly about to call rw_enter(). Not really a big deal
310 * since more than likely will be true when we simulate work
311 * later on */
312 spin_lock(&rwv->rw_priv_lock);
313 kzt_vprint(rwv->rw_file, rwt->rwt_name,
314 "%s writer thread trying to acquire rwlock with "
315 "%d holding lock and %d waiting\n",
316 name, atomic_read(&rwv->rw_acquired),
317 atomic_read(&rwv->rw_waiters));
318 atomic_inc(&rwv->rw_waiters);
319 spin_unlock(&rwv->rw_priv_lock);
320
321 /* Wait here until the control thread
322 * says we can acquire the write lock */
323 wait_event_interruptible(rwv->rw_waitq,
324 kzt_rwlock_lock_and_test(&rwv->rw_priv_lock,
325 atomic_read(&rwv->rw_release) ==
326 KZT_RWLOCK_RELEASE_WRITERS));
327
328 /* Take the semaphore for writing */
329 rw_enter(&rwv->rwl, RW_WRITER);
330
331 spin_lock(&rwv->rw_priv_lock);
332 atomic_dec(&rwv->rw_waiters);
333 atomic_inc(&rwv->rw_acquired);
334 kzt_vprint(rwv->rw_file, rwt->rwt_name,
335 "%s writer thread acquired rwlock with "
336 "%d holding lock and %d waiting\n",
337 name, atomic_read(&rwv->rw_acquired),
338 atomic_read(&rwv->rw_waiters));
339 spin_unlock(&rwv->rw_priv_lock);
340
341 /* Give up the processor for a bit to simulate
342 * doing some work while taking the write lock */
343 kzt_rwlock_sleep(rnd * HZ / 1000);
344
345 /* Ensure that we are the only one writing */
346 if (atomic_read(&rwv->rw_acquired) > 1) {
347 rwt->rwt_rc = 1;
348 } else {
349 rwt->rwt_rc = 0;
350 }
351
352 spin_lock(&rwv->rw_priv_lock);
353 atomic_inc(&rwv->rw_completed);
354 atomic_dec(&rwv->rw_acquired);
355 kzt_vprint(rwv->rw_file, rwt->rwt_name,
356 "%s writer thread dropped rwlock with "
357 "%d holding lock and %d waiting\n",
358 name, atomic_read(&rwv->rw_acquired),
359 atomic_read(&rwv->rw_waiters));
360 spin_unlock(&rwv->rw_priv_lock);
361
362 rw_exit(&rwv->rwl);
363
364
365 return 0;
366 }
367
368 static int
369 kzt_rwlock_test2(struct file *file, void *arg)
370 {
371 int i, count = 0, rc = 0;
372 long pids[KZT_RWLOCK_TEST_COUNT];
373 rw_thr_t rwt[KZT_RWLOCK_TEST_COUNT];
374 rw_priv_t rwv;
375
376 /* Initialize private data
377 * including the rwlock */
378 kzt_init_rw_priv(&rwv, file);
379
380 /* Create some threads, the exact number isn't important just as
381 * long as we know how many we managed to create and should expect. */
382 for (i = 0; i < KZT_RWLOCK_TEST_COUNT; i++) {
383 rwt[i].rwt_rwp = &rwv;
384 rwt[i].rwt_id = i;
385 rwt[i].rwt_name = KZT_RWLOCK_TEST2_NAME;
386 rwt[i].rwt_rc = 0;
387
388 /* The first thread will be a writer */
389 pids[i] = kernel_thread(kzt_rwlock_test2_writer_thread,
390 &rwt[i], 0);
391
392 if (pids[i] >= 0) {
393 count++;
394 }
395 }
396
397 /* Wait for writers to get queued up */
398 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
399 atomic_read(&rwv.rw_waiters) < KZT_RWLOCK_TEST_COUNT)) {
400 kzt_rwlock_sleep(1 * HZ);
401 }
402 /* Relase the writers */
403 spin_lock(&rwv.rw_priv_lock);
404 atomic_set(&rwv.rw_release, KZT_RWLOCK_RELEASE_WRITERS);
405 spin_unlock(&rwv.rw_priv_lock);
406 wake_up_interruptible(&rwv.rw_waitq);
407
408 /* Wait for the test to complete */
409 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
410 atomic_read(&rwv.rw_acquired) != 0 ||
411 atomic_read(&rwv.rw_waiters) != 0)) {
412 kzt_rwlock_sleep(1 * HZ);
413 }
414
415 /* If any of the write threads ever acquired the lock
416 * while another thread had it, make sure we return
417 * an error */
418 for (i = 0; i < KZT_RWLOCK_TEST_COUNT; i++) {
419 if (rwt[i].rwt_rc) {
420 rc++;
421 }
422 }
423
424 rw_destroy(&rwv.rwl);
425 return rc;
426 }
427
428 static int
429 kzt_rwlock_test3(struct file *file, void *arg)
430 {
431 kthread_t *owner;
432 rw_priv_t rwv;
433 int rc = 0;
434
435 /* Initialize private data
436 * including the rwlock */
437 kzt_init_rw_priv(&rwv, file);
438
439 /* Take the rwlock for writing */
440 rw_enter(&rwv.rwl, RW_WRITER);
441 owner = rw_owner(&rwv.rwl);
442 if (current != owner) {
443 kzt_vprint(file, KZT_RWLOCK_TEST3_NAME, "rwlock should "
444 "be owned by pid %d but is owned by pid %d\n",
445 current->pid, owner ? owner->pid : -1);
446 rc = -EINVAL;
447 goto out;
448 }
449
450 /* Release the rwlock */
451 rw_exit(&rwv.rwl);
452 owner = rw_owner(&rwv.rwl);
453 if (owner) {
454 kzt_vprint(file, KZT_RWLOCK_TEST3_NAME, "rwlock should not "
455 "be owned but is owned by pid %d\n", owner->pid);
456 rc = -EINVAL;
457 goto out;
458 }
459
460 /* Take the rwlock for reading.
461 * Should not have an owner */
462 rw_enter(&rwv.rwl, RW_READER);
463 owner = rw_owner(&rwv.rwl);
464 if (owner) {
465 kzt_vprint(file, KZT_RWLOCK_TEST3_NAME, "rwlock should not "
466 "be owned but is owned by pid %d\n", owner->pid);
467 /* Release the rwlock */
468 rw_exit(&rwv.rwl);
469 rc = -EINVAL;
470 goto out;
471 }
472
473 /* Release the rwlock */
474 rw_exit(&rwv.rwl);
475
476 out:
477 rw_destroy(&rwv.rwl);
478 return rc;
479 }
480
481 int
482 kzt_rwlock_test4_reader_thread(void *arg)
483 {
484 rw_thr_t *rwt = (rw_thr_t *)arg;
485 rw_priv_t *rwv = rwt->rwt_rwp;
486 uint8_t rnd = 0;
487 char name[16];
488
489 ASSERT(rwv->rw_magic == KZT_RWLOCK_TEST_MAGIC);
490 snprintf(name, sizeof(name), "%s%d",
491 KZT_RWLOCK_TEST_NAME, rwt->rwt_id);
492 daemonize(name);
493 get_random_bytes((void *)&rnd, 1);
494 kzt_rwlock_sleep(rnd * HZ / 1000);
495
496 /* Don't try and and take the semaphore until
497 * someone else has already acquired it */
498 wait_event_interruptible(rwv->rw_waitq,
499 kzt_rwlock_lock_and_test(&rwv->rw_priv_lock,
500 atomic_read(&rwv->rw_acquired) > 0));
501
502 spin_lock(&rwv->rw_priv_lock);
503 kzt_vprint(rwv->rw_file, rwt->rwt_name,
504 "%s reader thread trying to acquire rwlock with "
505 "%d holding lock and %d waiting\n",
506 name, atomic_read(&rwv->rw_acquired),
507 atomic_read(&rwv->rw_waiters));
508 spin_unlock(&rwv->rw_priv_lock);
509
510 /* Take the semaphore for reading
511 * release it when we are told to */
512 rwt->rwt_rc = rw_tryenter(&rwv->rwl, RW_READER);
513
514 /* Here we acquired the lock this is a
515 * failure since the writer should be
516 * holding the lock */
517 if (rwt->rwt_rc == 1) {
518 spin_lock(&rwv->rw_priv_lock);
519 atomic_inc(&rwv->rw_acquired);
520 kzt_vprint(rwv->rw_file, rwt->rwt_name,
521 "%s reader thread acquired rwlock with "
522 "%d holding lock and %d waiting\n",
523 name, atomic_read(&rwv->rw_acquired),
524 atomic_read(&rwv->rw_waiters));
525 spin_unlock(&rwv->rw_priv_lock);
526
527 spin_lock(&rwv->rw_priv_lock);
528 atomic_dec(&rwv->rw_acquired);
529 kzt_vprint(rwv->rw_file, rwt->rwt_name,
530 "%s reader thread dropped rwlock with "
531 "%d holding lock and %d waiting\n",
532 name, atomic_read(&rwv->rw_acquired),
533 atomic_read(&rwv->rw_waiters));
534 spin_unlock(&rwv->rw_priv_lock);
535
536 /* Release the semaphore */
537 rw_exit(&rwv->rwl);
538 }
539 /* Here we know we didn't block and didn't
540 * acquire the rwlock for reading */
541 else {
542 spin_lock(&rwv->rw_priv_lock);
543 atomic_inc(&rwv->rw_completed);
544 kzt_vprint(rwv->rw_file, rwt->rwt_name,
545 "%s reader thread could not acquire rwlock with "
546 "%d holding lock and %d waiting\n",
547 name, atomic_read(&rwv->rw_acquired),
548 atomic_read(&rwv->rw_waiters));
549 spin_unlock(&rwv->rw_priv_lock);
550 }
551
552 return 0;
553 }
554
555 static int
556 kzt_rwlock_test4(struct file *file, void *arg)
557 {
558 int i, count = 0, rc = 0;
559 long pids[KZT_RWLOCK_TEST_COUNT];
560 rw_thr_t rwt[KZT_RWLOCK_TEST_COUNT];
561 rw_priv_t rwv;
562
563 /* Initialize private data
564 * including the rwlock */
565 kzt_init_rw_priv(&rwv, file);
566
567 /* Create some threads, the exact number isn't important just as
568 * long as we know how many we managed to create and should expect. */
569 for (i = 0; i < KZT_RWLOCK_TEST_COUNT; i++) {
570 rwt[i].rwt_rwp = &rwv;
571 rwt[i].rwt_id = i;
572 rwt[i].rwt_name = KZT_RWLOCK_TEST4_NAME;
573 rwt[i].rwt_rc = 0;
574
575 /* The first thread will be a writer */
576 if (i == 0) {
577 /* We can reuse the test1 writer thread here */
578 pids[i] = kernel_thread(kzt_rwlock_test1_writer_thread,
579 &rwt[i], 0);
580 } else {
581 pids[i] = kernel_thread(kzt_rwlock_test4_reader_thread,
582 &rwt[i], 0);
583 }
584
585 if (pids[i] >= 0) {
586 count++;
587 }
588 }
589
590 /* Once the writer has the lock, release the readers */
591 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
592 atomic_read(&rwv.rw_acquired) <= 0)) {
593 kzt_rwlock_sleep(1 * HZ);
594 }
595 wake_up_interruptible(&rwv.rw_waitq);
596
597 /* Make sure that the reader threads complete */
598 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
599 atomic_read(&rwv.rw_completed) != KZT_RWLOCK_TEST_COUNT - 1)) {
600 kzt_rwlock_sleep(1 * HZ);
601 }
602 /* Release the writer */
603 spin_lock(&rwv.rw_priv_lock);
604 atomic_set(&rwv.rw_release, KZT_RWLOCK_RELEASE_WRITERS);
605 spin_unlock(&rwv.rw_priv_lock);
606 wake_up_interruptible(&rwv.rw_waitq);
607
608 /* Wait for the test to complete */
609 while (kzt_rwlock_lock_and_test(&rwv.rw_priv_lock,
610 atomic_read(&rwv.rw_acquired) != 0 ||
611 atomic_read(&rwv.rw_waiters) != 0)) {
612 kzt_rwlock_sleep(1 * HZ);
613 }
614
615 /* If any of the reader threads ever acquired the lock
616 * while another thread had it, make sure we return
617 * an error since the rw_tryenter() should have failed */
618 for (i = 0; i < KZT_RWLOCK_TEST_COUNT; i++) {
619 if (rwt[i].rwt_rc) {
620 rc++;
621 }
622 }
623
624 rw_destroy(&rwv.rwl);
625 return rc;
626 }
627
628 static int
629 kzt_rwlock_test5(struct file *file, void *arg)
630 {
631 kthread_t *owner;
632 rw_priv_t rwv;
633 int rc = 0;
634
635 /* Initialize private data
636 * including the rwlock */
637 kzt_init_rw_priv(&rwv, file);
638
639 /* Take the rwlock for writing */
640 rw_enter(&rwv.rwl, RW_WRITER);
641 owner = rw_owner(&rwv.rwl);
642 if (current != owner) {
643 kzt_vprint(file, KZT_RWLOCK_TEST5_NAME, "rwlock should "
644 "be owned by pid %d but is owned by pid %d\n",
645 current->pid, owner ? owner->pid : -1);
646 rc = -EINVAL;
647 goto out;
648 }
649
650 /* Make sure that the downgrade
651 * worked properly */
652 rw_downgrade(&rwv.rwl);
653
654 owner = rw_owner(&rwv.rwl);
655 if (owner) {
656 kzt_vprint(file, KZT_RWLOCK_TEST5_NAME, "rwlock should not "
657 "be owned but is owned by pid %d\n", owner->pid);
658 /* Release the rwlock */
659 rw_exit(&rwv.rwl);
660 rc = -EINVAL;
661 goto out;
662 }
663
664 /* Release the rwlock */
665 rw_exit(&rwv.rwl);
666
667 out:
668 rw_destroy(&rwv.rwl);
669 return rc;
670 }
671
672 static int
673 kzt_rwlock_test6(struct file *file, void *arg)
674 {
675 kthread_t *owner;
676 rw_priv_t rwv;
677 int rc = 0;
678
679 /* Initialize private data
680 * including the rwlock */
681 kzt_init_rw_priv(&rwv, file);
682
683 /* Take the rwlock for reading */
684 rw_enter(&rwv.rwl, RW_READER);
685 owner = rw_owner(&rwv.rwl);
686 if (owner) {
687 kzt_vprint(file, KZT_RWLOCK_TEST6_NAME, "rwlock should not "
688 "be owned but is owned by pid %d\n", owner->pid);
689 rc = -EINVAL;
690 goto out;
691 }
692
693 /* Make sure that the upgrade
694 * worked properly */
695 rc = !rw_tryupgrade(&rwv.rwl);
696
697 owner = rw_owner(&rwv.rwl);
698 if (rc || current != owner) {
699 kzt_vprint(file, KZT_RWLOCK_TEST6_NAME, "rwlock should "
700 "be owned by pid %d but is owned by pid %d "
701 "trylock rc %d\n",
702 current->pid, owner ? owner->pid : -1, rc);
703 rc = -EINVAL;
704 goto out;
705 }
706
707 /* Release the rwlock */
708 rw_exit(&rwv.rwl);
709
710 out:
711 rw_destroy(&rwv.rwl);
712 return rc;
713 }
714
715 kzt_subsystem_t *
716 kzt_rwlock_init(void)
717 {
718 kzt_subsystem_t *sub;
719
720 sub = kmalloc(sizeof(*sub), GFP_KERNEL);
721 if (sub == NULL)
722 return NULL;
723
724 memset(sub, 0, sizeof(*sub));
725 strncpy(sub->desc.name, KZT_RWLOCK_NAME, KZT_NAME_SIZE);
726 strncpy(sub->desc.desc, KZT_RWLOCK_DESC, KZT_DESC_SIZE);
727 INIT_LIST_HEAD(&sub->subsystem_list);
728 INIT_LIST_HEAD(&sub->test_list);
729 spin_lock_init(&sub->test_lock);
730 sub->desc.id = KZT_SUBSYSTEM_RWLOCK;
731
732 KZT_TEST_INIT(sub, KZT_RWLOCK_TEST1_NAME, KZT_RWLOCK_TEST1_DESC,
733 KZT_RWLOCK_TEST1_ID, kzt_rwlock_test1);
734 KZT_TEST_INIT(sub, KZT_RWLOCK_TEST2_NAME, KZT_RWLOCK_TEST2_DESC,
735 KZT_RWLOCK_TEST2_ID, kzt_rwlock_test2);
736 KZT_TEST_INIT(sub, KZT_RWLOCK_TEST3_NAME, KZT_RWLOCK_TEST3_DESC,
737 KZT_RWLOCK_TEST3_ID, kzt_rwlock_test3);
738 KZT_TEST_INIT(sub, KZT_RWLOCK_TEST4_NAME, KZT_RWLOCK_TEST4_DESC,
739 KZT_RWLOCK_TEST4_ID, kzt_rwlock_test4);
740 KZT_TEST_INIT(sub, KZT_RWLOCK_TEST5_NAME, KZT_RWLOCK_TEST5_DESC,
741 KZT_RWLOCK_TEST5_ID, kzt_rwlock_test5);
742 KZT_TEST_INIT(sub, KZT_RWLOCK_TEST6_NAME, KZT_RWLOCK_TEST6_DESC,
743 KZT_RWLOCK_TEST6_ID, kzt_rwlock_test6);
744
745 return sub;
746 }
747
748 void
749 kzt_rwlock_fini(kzt_subsystem_t *sub)
750 {
751 ASSERT(sub);
752 KZT_TEST_FINI(sub, KZT_RWLOCK_TEST6_ID);
753 KZT_TEST_FINI(sub, KZT_RWLOCK_TEST5_ID);
754 KZT_TEST_FINI(sub, KZT_RWLOCK_TEST4_ID);
755 KZT_TEST_FINI(sub, KZT_RWLOCK_TEST3_ID);
756 KZT_TEST_FINI(sub, KZT_RWLOCK_TEST2_ID);
757 KZT_TEST_FINI(sub, KZT_RWLOCK_TEST1_ID);
758 kfree(sub);
759 }
760
761 int
762 kzt_rwlock_id(void) {
763 return KZT_SUBSYSTEM_RWLOCK;
764 }