]> granicus.if.org Git - zfs/blob - module/splat/splat-rwlock.c
Add TASKQID_INVALID and TASKQID_INITIAL macros
[zfs] / module / splat / splat-rwlock.c
1 /*****************************************************************************\
2  *  Copyright (C) 2007-2010 Lawrence Livermore National Security, LLC.
3  *  Copyright (C) 2007 The Regents of the University of California.
4  *  Produced at Lawrence Livermore National Laboratory (cf, DISCLAIMER).
5  *  Written by Brian Behlendorf <behlendorf1@llnl.gov>.
6  *  UCRL-CODE-235197
7  *
8  *  This file is part of the SPL, Solaris Porting Layer.
9  *  For details, see <http://zfsonlinux.org/>.
10  *
11  *  The SPL is free software; you can redistribute it and/or modify it
12  *  under the terms of the GNU General Public License as published by the
13  *  Free Software Foundation; either version 2 of the License, or (at your
14  *  option) any later version.
15  *
16  *  The SPL is distributed in the hope that it will be useful, but WITHOUT
17  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19  *  for more details.
20  *
21  *  You should have received a copy of the GNU General Public License along
22  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
23  *****************************************************************************
24  *  Solaris Porting LAyer Tests (SPLAT) Read/Writer Lock Tests.
25 \*****************************************************************************/
26
27 #include <sys/random.h>
28 #include <sys/rwlock.h>
29 #include <sys/taskq.h>
30 #include <linux/delay.h>
31 #include <linux/mm_compat.h>
32 #include "splat-internal.h"
33
34 #define SPLAT_RWLOCK_NAME               "rwlock"
35 #define SPLAT_RWLOCK_DESC               "Kernel RW Lock Tests"
36
37 #define SPLAT_RWLOCK_TEST1_ID           0x0701
38 #define SPLAT_RWLOCK_TEST1_NAME         "N-rd/1-wr"
39 #define SPLAT_RWLOCK_TEST1_DESC         "Multiple readers one writer"
40
41 #define SPLAT_RWLOCK_TEST2_ID           0x0702
42 #define SPLAT_RWLOCK_TEST2_NAME         "0-rd/N-wr"
43 #define SPLAT_RWLOCK_TEST2_DESC         "Multiple writers"
44
45 #define SPLAT_RWLOCK_TEST3_ID           0x0703
46 #define SPLAT_RWLOCK_TEST3_NAME         "held"
47 #define SPLAT_RWLOCK_TEST3_DESC         "RW_{LOCK|READ|WRITE}_HELD"
48
49 #define SPLAT_RWLOCK_TEST4_ID           0x0704
50 #define SPLAT_RWLOCK_TEST4_NAME         "tryenter"
51 #define SPLAT_RWLOCK_TEST4_DESC         "Tryenter"
52
53 #define SPLAT_RWLOCK_TEST5_ID           0x0705
54 #define SPLAT_RWLOCK_TEST5_NAME         "rw_downgrade"
55 #define SPLAT_RWLOCK_TEST5_DESC         "Write downgrade"
56
57 #define SPLAT_RWLOCK_TEST6_ID           0x0706
58 #define SPLAT_RWLOCK_TEST6_NAME         "rw_tryupgrade-1"
59 #define SPLAT_RWLOCK_TEST6_DESC         "rwsem->count value"
60
61 #define SPLAT_RWLOCK_TEST7_ID           0x0707
62 #define SPLAT_RWLOCK_TEST7_NAME         "rw_tryupgrade-2"
63 #define SPLAT_RWLOCK_TEST7_DESC         "Read upgrade"
64
65 #define SPLAT_RWLOCK_TEST_MAGIC         0x115599DDUL
66 #define SPLAT_RWLOCK_TEST_NAME          "rwlock_test"
67 #define SPLAT_RWLOCK_TEST_TASKQ         "rwlock_taskq"
68 #define SPLAT_RWLOCK_TEST_COUNT         8
69
70 #define SPLAT_RWLOCK_RELEASE_INIT       0
71 #define SPLAT_RWLOCK_RELEASE_WR         1
72 #define SPLAT_RWLOCK_RELEASE_RD         2
73
74 typedef struct rw_priv {
75         unsigned long rw_magic;
76         struct file *rw_file;
77         krwlock_t rw_rwlock;
78         spinlock_t rw_lock;
79         wait_queue_head_t rw_waitq;
80         int rw_completed;
81         int rw_holders;
82         int rw_waiters;
83         int rw_release;
84         int rw_rc;
85         krw_t rw_type;
86 } rw_priv_t;
87
88 typedef struct rw_thr {
89         const char *rwt_name;
90         rw_priv_t *rwt_rwp;
91         struct task_struct *rwt_thread;
92 } rw_thr_t;
93
94 void splat_init_rw_priv(rw_priv_t *rwp, struct file *file)
95 {
96         rwp->rw_magic = SPLAT_RWLOCK_TEST_MAGIC;
97         rwp->rw_file = file;
98         rw_init(&rwp->rw_rwlock, SPLAT_RWLOCK_TEST_NAME, RW_DEFAULT, NULL);
99         spin_lock_init(&rwp->rw_lock);
100         init_waitqueue_head(&rwp->rw_waitq);
101         rwp->rw_completed = 0;
102         rwp->rw_holders = 0;
103         rwp->rw_waiters = 0;
104         rwp->rw_release = SPLAT_RWLOCK_RELEASE_INIT;
105         rwp->rw_rc = 0;
106         rwp->rw_type = 0;
107 }
108
109 static int
110 splat_rwlock_wr_thr(void *arg)
111 {
112         rw_thr_t *rwt = (rw_thr_t *)arg;
113         rw_priv_t *rwp = rwt->rwt_rwp;
114         uint8_t rnd;
115
116         ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
117
118         get_random_bytes((void *)&rnd, 1);
119         msleep((unsigned int)rnd);
120
121         splat_vprint(rwp->rw_file, rwt->rwt_name,
122             "%s trying to acquire rwlock (%d holding/%d waiting)\n",
123             rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
124         spin_lock(&rwp->rw_lock);
125         rwp->rw_waiters++;
126         spin_unlock(&rwp->rw_lock);
127         rw_enter(&rwp->rw_rwlock, RW_WRITER);
128
129         spin_lock(&rwp->rw_lock);
130         rwp->rw_waiters--;
131         rwp->rw_holders++;
132         spin_unlock(&rwp->rw_lock);
133         splat_vprint(rwp->rw_file, rwt->rwt_name,
134             "%s acquired rwlock (%d holding/%d waiting)\n",
135             rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
136
137         /* Wait for control thread to signal we can release the write lock */
138         wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
139             rwp->rw_release == SPLAT_RWLOCK_RELEASE_WR));
140
141         spin_lock(&rwp->rw_lock);
142         rwp->rw_completed++;
143         rwp->rw_holders--;
144         spin_unlock(&rwp->rw_lock);
145         splat_vprint(rwp->rw_file, rwt->rwt_name,
146             "%s dropped rwlock (%d holding/%d waiting)\n",
147             rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
148
149         rw_exit(&rwp->rw_rwlock);
150
151         return 0;
152 }
153
154 static int
155 splat_rwlock_rd_thr(void *arg)
156 {
157         rw_thr_t *rwt = (rw_thr_t *)arg;
158         rw_priv_t *rwp = rwt->rwt_rwp;
159         uint8_t rnd;
160
161         ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
162
163         get_random_bytes((void *)&rnd, 1);
164         msleep((unsigned int)rnd);
165
166         /* Don't try and take the semaphore until after someone has it */
167         wait_event_interruptible(rwp->rw_waitq,
168             splat_locked_test(&rwp->rw_lock, rwp->rw_holders > 0));
169
170         splat_vprint(rwp->rw_file, rwt->rwt_name,
171             "%s trying to acquire rwlock (%d holding/%d waiting)\n",
172             rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
173         spin_lock(&rwp->rw_lock);
174         rwp->rw_waiters++;
175         spin_unlock(&rwp->rw_lock);
176         rw_enter(&rwp->rw_rwlock, RW_READER);
177
178         spin_lock(&rwp->rw_lock);
179         rwp->rw_waiters--;
180         rwp->rw_holders++;
181         spin_unlock(&rwp->rw_lock);
182         splat_vprint(rwp->rw_file, rwt->rwt_name,
183             "%s acquired rwlock (%d holding/%d waiting)\n",
184             rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
185
186         /* Wait for control thread to signal we can release the read lock */
187         wait_event_interruptible(rwp->rw_waitq, splat_locked_test(&rwp->rw_lock,
188             rwp->rw_release == SPLAT_RWLOCK_RELEASE_RD));
189
190         spin_lock(&rwp->rw_lock);
191         rwp->rw_completed++;
192         rwp->rw_holders--;
193         spin_unlock(&rwp->rw_lock);
194         splat_vprint(rwp->rw_file, rwt->rwt_name,
195             "%s dropped rwlock (%d holding/%d waiting)\n",
196             rwt->rwt_thread->comm, rwp->rw_holders, rwp->rw_waiters);
197
198         rw_exit(&rwp->rw_rwlock);
199
200         return 0;
201 }
202
203 static int
204 splat_rwlock_test1(struct file *file, void *arg)
205 {
206         int i, count = 0, rc = 0;
207         rw_thr_t rwt[SPLAT_RWLOCK_TEST_COUNT];
208         rw_priv_t *rwp;
209
210         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
211         if (rwp == NULL)
212                 return -ENOMEM;
213
214         splat_init_rw_priv(rwp, file);
215
216         /* Create some threads, the exact number isn't important just as
217          * long as we know how many we managed to create and should expect. */
218         for (i = 0; i < SPLAT_RWLOCK_TEST_COUNT; i++) {
219                 rwt[i].rwt_rwp = rwp;
220                 rwt[i].rwt_name = SPLAT_RWLOCK_TEST1_NAME;
221
222                 /* The first thread will be the writer */
223                 if (i == 0)
224                         rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_wr_thr,
225                             &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i);
226                 else
227                         rwt[i].rwt_thread = spl_kthread_create(splat_rwlock_rd_thr,
228                             &rwt[i], "%s/%d", SPLAT_RWLOCK_TEST_NAME, i);
229
230                 if (!IS_ERR(rwt[i].rwt_thread)) {
231                         wake_up_process(rwt[i].rwt_thread);
232                         count++;
233                 }
234         }
235
236         /* Wait for the writer */
237         while (splat_locked_test(&rwp->rw_lock, rwp->rw_holders == 0)) {
238                 wake_up_interruptible(&rwp->rw_waitq);
239                 msleep(100);
240         }
241
242         /* Wait for 'count-1' readers */
243         while (splat_locked_test(&rwp->rw_lock, rwp->rw_waiters < count - 1)) {
244                 wake_up_interruptible(&rwp->rw_waitq);
245                 msleep(100);
246         }
247
248         /* Verify there is only one lock holder */
249         if (splat_locked_test(&rwp->rw_lock, rwp->rw_holders) != 1) {
250                 splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only 1 holder "
251                              "expected for rwlock (%d holding/%d waiting)\n",
252                              rwp->rw_holders, rwp->rw_waiters);
253                 rc = -EINVAL;
254         }
255
256         /* Verify 'count-1' readers */
257         if (splat_locked_test(&rwp->rw_lock, rwp->rw_waiters != count - 1)) {
258                 splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only %d waiters "
259                              "expected for rwlock (%d holding/%d waiting)\n",
260                              count - 1, rwp->rw_holders, rwp->rw_waiters);
261                 rc = -EINVAL;
262         }
263
264         /* Signal the writer to release, allows readers to acquire */
265         spin_lock(&rwp->rw_lock);
266         rwp->rw_release = SPLAT_RWLOCK_RELEASE_WR;
267         wake_up_interruptible(&rwp->rw_waitq);
268         spin_unlock(&rwp->rw_lock);
269
270         /* Wait for 'count-1' readers to hold the lock */
271         while (splat_locked_test(&rwp->rw_lock, rwp->rw_holders < count - 1)) {
272                 wake_up_interruptible(&rwp->rw_waitq);
273                 msleep(100);
274         }
275
276         /* Verify there are 'count-1' readers */
277         if (splat_locked_test(&rwp->rw_lock, rwp->rw_holders != count - 1)) {
278                 splat_vprint(file, SPLAT_RWLOCK_TEST1_NAME, "Only %d holders "
279                              "expected for rwlock (%d holding/%d waiting)\n",
280                              count - 1, rwp->rw_holders, rwp->rw_waiters);
281                 rc = -EINVAL;
282         }
283
284         /* Release 'count-1' readers */
285         spin_lock(&rwp->rw_lock);
286         rwp->rw_release = SPLAT_RWLOCK_RELEASE_RD;
287         wake_up_interruptible(&rwp->rw_waitq);
288         spin_unlock(&rwp->rw_lock);
289
290         /* Wait for the test to complete */
291         while (splat_locked_test(&rwp->rw_lock,
292                                  rwp->rw_holders>0 || rwp->rw_waiters>0))
293                 msleep(100);
294
295         rw_destroy(&(rwp->rw_rwlock));
296         kfree(rwp);
297
298         return rc;
299 }
300
301 static void
302 splat_rwlock_test2_func(void *arg)
303 {
304         rw_priv_t *rwp = (rw_priv_t *)arg;
305         int rc;
306         ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
307
308         /* Read the value before sleeping and write it after we wake up to
309          * maximize the chance of a race if rwlocks are not working properly */
310         rw_enter(&rwp->rw_rwlock, RW_WRITER);
311         rc = rwp->rw_rc;
312         set_current_state(TASK_INTERRUPTIBLE);
313         schedule_timeout(HZ / 100);  /* 1/100 of a second */
314         VERIFY(rwp->rw_rc == rc);
315         rwp->rw_rc = rc + 1;
316         rw_exit(&rwp->rw_rwlock);
317 }
318
319 static int
320 splat_rwlock_test2(struct file *file, void *arg)
321 {
322         rw_priv_t *rwp;
323         taskq_t *tq;
324         int i, rc = 0, tq_count = 256;
325
326         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
327         if (rwp == NULL)
328                 return -ENOMEM;
329
330         splat_init_rw_priv(rwp, file);
331
332         /* Create several threads allowing tasks to race with each other */
333         tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, num_online_cpus(),
334                           defclsyspri, 50, INT_MAX, TASKQ_PREPOPULATE);
335         if (tq == NULL) {
336                 rc = -ENOMEM;
337                 goto out;
338         }
339
340         /*
341          * Schedule N work items to the work queue each of which enters the
342          * writer rwlock, sleeps briefly, then exits the writer rwlock.  On a
343          * multiprocessor box these work items will be handled by all available
344          * CPUs.  The task function checks to ensure the tracked shared variable
345          * is always only incremented by one.  Additionally, the rwlock itself
346          * is instrumented such that if any two processors are in the
347          * critical region at the same time the system will panic.  If the
348          * rwlock is implemented right this will never happy, that's a pass.
349          */
350         for (i = 0; i < tq_count; i++) {
351                 if (taskq_dispatch(tq, splat_rwlock_test2_func, rwp,
352                     TQ_SLEEP) == TASKQID_INVALID) {
353                         splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME,
354                                      "Failed to queue task %d\n", i);
355                         rc = -EINVAL;
356                 }
357         }
358
359         taskq_wait(tq);
360
361         if (rwp->rw_rc == tq_count) {
362                 splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, "%d racing threads "
363                              "correctly entered/exited the rwlock %d times\n",
364                              num_online_cpus(), rwp->rw_rc);
365         } else {
366                 splat_vprint(file, SPLAT_RWLOCK_TEST2_NAME, "%d racing threads "
367                              "only processed %d/%d w rwlock work items\n",
368                              num_online_cpus(), rwp->rw_rc, tq_count);
369                 rc = -EINVAL;
370         }
371
372         taskq_destroy(tq);
373         rw_destroy(&(rwp->rw_rwlock));
374 out:
375         kfree(rwp);
376         return rc;
377 }
378
379 #define splat_rwlock_test3_helper(rwp,rex1,rex2,wex1,wex2,held_func,rc) \
380 do {                                                                    \
381         int result, _rc1_, _rc2_, _rc3_, _rc4_;                         \
382                                                                         \
383         rc = 0;                                                         \
384         rw_enter(&(rwp)->rw_rwlock, RW_READER);                         \
385         _rc1_ = ((result = held_func(&(rwp)->rw_rwlock)) != rex1);      \
386         splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
387                      " returned %d (expected %d) when RW_READER\n",     \
388                      _rc1_ ? "Fail " : "", result, rex1);               \
389         rw_exit(&(rwp)->rw_rwlock);                                     \
390         _rc2_ = ((result = held_func(&(rwp)->rw_rwlock)) != rex2);      \
391         splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
392                      " returned %d (expected %d) when !RW_READER\n",    \
393                      _rc2_ ? "Fail " : "", result, rex2);               \
394                                                                         \
395         rw_enter(&(rwp)->rw_rwlock, RW_WRITER);                         \
396         _rc3_ = ((result = held_func(&(rwp)->rw_rwlock)) != wex1);      \
397         splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
398                      " returned %d (expected %d) when RW_WRITER\n",     \
399                      _rc3_ ? "Fail " : "", result, wex1);               \
400         rw_exit(&(rwp)->rw_rwlock);                                     \
401         _rc4_ = ((result = held_func(&(rwp)->rw_rwlock)) != wex2);      \
402         splat_vprint(file, SPLAT_RWLOCK_TEST3_NAME, "%s" #held_func     \
403                      " returned %d (expected %d) when !RW_WRITER\n",    \
404                      _rc4_ ? "Fail " : "", result, wex2);               \
405                                                                         \
406         rc = ((_rc1_ ||  _rc2_ || _rc3_ || _rc4_) ? -EINVAL : 0);       \
407 } while(0);
408
409 static int
410 splat_rwlock_test3(struct file *file, void *arg)
411 {
412         rw_priv_t *rwp;
413         int rc1, rc2, rc3;
414
415         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
416         if (rwp == NULL)
417                 return -ENOMEM;
418
419         splat_init_rw_priv(rwp, file);
420
421         splat_rwlock_test3_helper(rwp, 1, 0, 1, 0, RW_LOCK_HELD, rc1);
422         splat_rwlock_test3_helper(rwp, 1, 0, 0, 0, RW_READ_HELD, rc2);
423         splat_rwlock_test3_helper(rwp, 0, 0, 1, 0, RW_WRITE_HELD, rc3);
424
425         rw_destroy(&rwp->rw_rwlock);
426         kfree(rwp);
427
428         return ((rc1 || rc2 || rc3) ? -EINVAL : 0);
429 }
430
431 static void
432 splat_rwlock_test4_func(void *arg)
433 {
434         rw_priv_t *rwp = (rw_priv_t *)arg;
435         ASSERT(rwp->rw_magic == SPLAT_RWLOCK_TEST_MAGIC);
436
437         if (rw_tryenter(&rwp->rw_rwlock, rwp->rw_type)) {
438                 rwp->rw_rc = 0;
439                 rw_exit(&rwp->rw_rwlock);
440         } else {
441                 rwp->rw_rc = -EBUSY;
442         }
443 }
444
445 static char *
446 splat_rwlock_test4_name(krw_t type)
447 {
448         switch (type) {
449                 case RW_NONE: return "RW_NONE";
450                 case RW_WRITER: return "RW_WRITER";
451                 case RW_READER: return "RW_READER";
452         }
453
454         return NULL;
455 }
456
457 static int
458 splat_rwlock_test4_type(taskq_t *tq, rw_priv_t *rwp, int expected_rc,
459                         krw_t holder_type, krw_t try_type)
460 {
461         int id, rc = 0;
462
463         /* Schedule a task function which will try and acquire the rwlock
464          * using type try_type while the rwlock is being held as holder_type.
465          * The result must match expected_rc for the test to pass */
466         rwp->rw_rc = -EINVAL;
467         rwp->rw_type = try_type;
468
469         if (holder_type == RW_WRITER || holder_type == RW_READER)
470                 rw_enter(&rwp->rw_rwlock, holder_type);
471
472         id = taskq_dispatch(tq, splat_rwlock_test4_func, rwp, TQ_SLEEP);
473         if (id == TASKQID_INVALID) {
474                 splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME, "%s",
475                              "taskq_dispatch() failed\n");
476                 rc = -EINVAL;
477                 goto out;
478         }
479
480         taskq_wait_id(tq, id);
481
482         if (rwp->rw_rc != expected_rc)
483                 rc = -EINVAL;
484
485         splat_vprint(rwp->rw_file, SPLAT_RWLOCK_TEST4_NAME,
486                      "%srw_tryenter(%s) returned %d (expected %d) when %s\n",
487                      rc ? "Fail " : "", splat_rwlock_test4_name(try_type),
488                      rwp->rw_rc, expected_rc,
489                      splat_rwlock_test4_name(holder_type));
490 out:
491         if (holder_type == RW_WRITER || holder_type == RW_READER)
492                 rw_exit(&rwp->rw_rwlock);
493
494         return rc;
495 }
496
497 static int
498 splat_rwlock_test4(struct file *file, void *arg)
499 {
500         rw_priv_t *rwp;
501         taskq_t *tq;
502         int rc = 0, rc1, rc2, rc3, rc4, rc5, rc6;
503
504         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
505         if (rwp == NULL)
506                 return -ENOMEM;
507
508         tq = taskq_create(SPLAT_RWLOCK_TEST_TASKQ, 1, defclsyspri,
509                           50, INT_MAX, TASKQ_PREPOPULATE);
510         if (tq == NULL) {
511                 rc = -ENOMEM;
512                 goto out;
513         }
514
515         splat_init_rw_priv(rwp, file);
516
517         /* Validate all combinations of rw_tryenter() contention */
518         rc1 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_WRITER, RW_WRITER);
519         rc2 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_WRITER, RW_READER);
520         rc3 = splat_rwlock_test4_type(tq, rwp, -EBUSY, RW_READER, RW_WRITER);
521         rc4 = splat_rwlock_test4_type(tq, rwp, 0,      RW_READER, RW_READER);
522         rc5 = splat_rwlock_test4_type(tq, rwp, 0,      RW_NONE,   RW_WRITER);
523         rc6 = splat_rwlock_test4_type(tq, rwp, 0,      RW_NONE,   RW_READER);
524
525         if (rc1 || rc2 || rc3 || rc4 || rc5 || rc6)
526                 rc = -EINVAL;
527
528         taskq_destroy(tq);
529 out:
530         rw_destroy(&(rwp->rw_rwlock));
531         kfree(rwp);
532
533         return rc;
534 }
535
536 static int
537 splat_rwlock_test5(struct file *file, void *arg)
538 {
539         rw_priv_t *rwp;
540         int rc = -EINVAL;
541
542         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
543         if (rwp == NULL)
544                 return -ENOMEM;
545
546         splat_init_rw_priv(rwp, file);
547
548         rw_enter(&rwp->rw_rwlock, RW_WRITER);
549         if (!RW_WRITE_HELD(&rwp->rw_rwlock)) {
550                 splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME,
551                              "rwlock should be write lock: %d\n",
552                              RW_WRITE_HELD(&rwp->rw_rwlock));
553                 goto out;
554         }
555
556         rw_downgrade(&rwp->rw_rwlock);
557         if (!RW_READ_HELD(&rwp->rw_rwlock)) {
558                 splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME,
559                              "rwlock should be read lock: %d\n",
560                              RW_READ_HELD(&rwp->rw_rwlock));
561                 goto out;
562         }
563
564         rc = 0;
565         splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME, "%s",
566                      "rwlock properly downgraded\n");
567 out:
568         rw_exit(&rwp->rw_rwlock);
569         rw_destroy(&rwp->rw_rwlock);
570         kfree(rwp);
571
572         return rc;
573 }
574
575 static int
576 splat_rwlock_test6(struct file *file, void *arg)
577 {
578         rw_priv_t *rwp;
579         int rc;
580
581         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
582         if (rwp == NULL)
583                 return -ENOMEM;
584
585         splat_init_rw_priv(rwp, file);
586
587         rw_enter(&rwp->rw_rwlock, RW_READER);
588         if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) !=
589             SPL_RWSEM_SINGLE_READER_VALUE) {
590                 splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
591                     "We assumed single reader rwsem->count "
592                     "should be %ld, but is %ld\n",
593                     (long int)SPL_RWSEM_SINGLE_READER_VALUE,
594                     (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock)));
595                 rc = -ENOLCK;
596                 goto out;
597         }
598         rw_exit(&rwp->rw_rwlock);
599
600         rw_enter(&rwp->rw_rwlock, RW_WRITER);
601         if (RWSEM_COUNT(SEM(&rwp->rw_rwlock)) !=
602             SPL_RWSEM_SINGLE_WRITER_VALUE) {
603                 splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME,
604                     "We assumed single writer rwsem->count "
605                     "should be %ld, but is %ld\n",
606                     (long int)SPL_RWSEM_SINGLE_WRITER_VALUE,
607                     (long int)RWSEM_COUNT(SEM(&rwp->rw_rwlock)));
608                 rc = -ENOLCK;
609                 goto out;
610         }
611         rc = 0;
612         splat_vprint(file, SPLAT_RWLOCK_TEST6_NAME, "%s",
613                      "rwsem->count same as we assumed\n");
614 out:
615         rw_exit(&rwp->rw_rwlock);
616         rw_destroy(&rwp->rw_rwlock);
617         kfree(rwp);
618
619         return rc;
620 }
621
622 static int
623 splat_rwlock_test7(struct file *file, void *arg)
624 {
625         rw_priv_t *rwp;
626         int rc;
627
628         rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
629         if (rwp == NULL)
630                 return -ENOMEM;
631
632         splat_init_rw_priv(rwp, file);
633
634         rw_enter(&rwp->rw_rwlock, RW_READER);
635         if (!RW_READ_HELD(&rwp->rw_rwlock)) {
636                 splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME,
637                              "rwlock should be read lock: %d\n",
638                              RW_READ_HELD(&rwp->rw_rwlock));
639                 rc = -ENOLCK;
640                 goto out;
641         }
642
643         /* With one reader upgrade should never fail. */
644         rc = rw_tryupgrade(&rwp->rw_rwlock);
645         if (!rc) {
646                 splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME,
647                              "rwlock failed upgrade from reader: %d\n",
648                              RW_READ_HELD(&rwp->rw_rwlock));
649                 rc = -ENOLCK;
650                 goto out;
651         }
652
653         if (RW_READ_HELD(&rwp->rw_rwlock) || !RW_WRITE_HELD(&rwp->rw_rwlock)) {
654                 splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "rwlock should "
655                            "have 0 (not %d) reader and 1 (not %d) writer\n",
656                            RW_READ_HELD(&rwp->rw_rwlock),
657                            RW_WRITE_HELD(&rwp->rw_rwlock));
658                 goto out;
659         }
660
661         rc = 0;
662         splat_vprint(file, SPLAT_RWLOCK_TEST7_NAME, "%s",
663                      "rwlock properly upgraded\n");
664 out:
665         rw_exit(&rwp->rw_rwlock);
666         rw_destroy(&rwp->rw_rwlock);
667         kfree(rwp);
668
669         return rc;
670 }
671
672 splat_subsystem_t *
673 splat_rwlock_init(void)
674 {
675         splat_subsystem_t *sub;
676
677         sub = kmalloc(sizeof(*sub), GFP_KERNEL);
678         if (sub == NULL)
679                 return NULL;
680
681         memset(sub, 0, sizeof(*sub));
682         strncpy(sub->desc.name, SPLAT_RWLOCK_NAME, SPLAT_NAME_SIZE);
683         strncpy(sub->desc.desc, SPLAT_RWLOCK_DESC, SPLAT_DESC_SIZE);
684         INIT_LIST_HEAD(&sub->subsystem_list);
685         INIT_LIST_HEAD(&sub->test_list);
686         spin_lock_init(&sub->test_lock);
687         sub->desc.id = SPLAT_SUBSYSTEM_RWLOCK;
688
689         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST1_NAME, SPLAT_RWLOCK_TEST1_DESC,
690                       SPLAT_RWLOCK_TEST1_ID, splat_rwlock_test1);
691         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST2_NAME, SPLAT_RWLOCK_TEST2_DESC,
692                       SPLAT_RWLOCK_TEST2_ID, splat_rwlock_test2);
693         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST3_NAME, SPLAT_RWLOCK_TEST3_DESC,
694                       SPLAT_RWLOCK_TEST3_ID, splat_rwlock_test3);
695         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST4_NAME, SPLAT_RWLOCK_TEST4_DESC,
696                       SPLAT_RWLOCK_TEST4_ID, splat_rwlock_test4);
697         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST5_NAME, SPLAT_RWLOCK_TEST5_DESC,
698                       SPLAT_RWLOCK_TEST5_ID, splat_rwlock_test5);
699         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST6_NAME, SPLAT_RWLOCK_TEST6_DESC,
700                       SPLAT_RWLOCK_TEST6_ID, splat_rwlock_test6);
701         SPLAT_TEST_INIT(sub, SPLAT_RWLOCK_TEST7_NAME, SPLAT_RWLOCK_TEST7_DESC,
702                       SPLAT_RWLOCK_TEST7_ID, splat_rwlock_test7);
703
704         return sub;
705 }
706
707 void
708 splat_rwlock_fini(splat_subsystem_t *sub)
709 {
710         ASSERT(sub);
711         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST7_ID);
712         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST6_ID);
713         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST5_ID);
714         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST4_ID);
715         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST3_ID);
716         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST2_ID);
717         SPLAT_TEST_FINI(sub, SPLAT_RWLOCK_TEST1_ID);
718         kfree(sub);
719 }
720
721 int
722 splat_rwlock_id(void) {
723         return SPLAT_SUBSYSTEM_RWLOCK;
724 }