Update OpenZFS to 2.0.0-rc3-gbd565f
[freebsd.git] / include / os / linux / spl / sys / rwlock.h
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  *
10  *  The SPL is free software; you can redistribute it and/or modify it
11  *  under the terms of the GNU General Public License as published by the
12  *  Free Software Foundation; either version 2 of the License, or (at your
13  *  option) any later version.
14  *
15  *  The SPL is distributed in the hope that it will be useful, but WITHOUT
16  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18  *  for more details.
19  *
20  *  You should have received a copy of the GNU General Public License along
21  *  with the SPL.  If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #ifndef _SPL_RWLOCK_H
25 #define _SPL_RWLOCK_H
26
27 #include <sys/types.h>
28 #include <linux/rwsem.h>
29 #include <linux/sched.h>
30
31 typedef enum {
32         RW_DRIVER       = 2,
33         RW_DEFAULT      = 4,
34         RW_NOLOCKDEP    = 5
35 } krw_type_t;
36
37 typedef enum {
38         RW_NONE         = 0,
39         RW_WRITER       = 1,
40         RW_READER       = 2
41 } krw_t;
42
43 typedef struct {
44         struct rw_semaphore rw_rwlock;
45         kthread_t *rw_owner;
46 #ifdef CONFIG_LOCKDEP
47         krw_type_t      rw_type;
48 #endif /* CONFIG_LOCKDEP */
49 } krwlock_t;
50
51 #define SEM(rwp)        (&(rwp)->rw_rwlock)
52
53 static inline void
54 spl_rw_set_owner(krwlock_t *rwp)
55 {
56         rwp->rw_owner = current;
57 }
58
59 static inline void
60 spl_rw_clear_owner(krwlock_t *rwp)
61 {
62         rwp->rw_owner = NULL;
63 }
64
65 static inline kthread_t *
66 rw_owner(krwlock_t *rwp)
67 {
68         return (rwp->rw_owner);
69 }
70
71 #ifdef CONFIG_LOCKDEP
72 static inline void
73 spl_rw_set_type(krwlock_t *rwp, krw_type_t type)
74 {
75         rwp->rw_type = type;
76 }
77 static inline void
78 spl_rw_lockdep_off_maybe(krwlock_t *rwp)                \
79 {                                                       \
80         if (rwp && rwp->rw_type == RW_NOLOCKDEP)        \
81                 lockdep_off();                          \
82 }
83 static inline void
84 spl_rw_lockdep_on_maybe(krwlock_t *rwp)                 \
85 {                                                       \
86         if (rwp && rwp->rw_type == RW_NOLOCKDEP)        \
87                 lockdep_on();                           \
88 }
89 #else  /* CONFIG_LOCKDEP */
90 #define spl_rw_set_type(rwp, type)
91 #define spl_rw_lockdep_off_maybe(rwp)
92 #define spl_rw_lockdep_on_maybe(rwp)
93 #endif /* CONFIG_LOCKDEP */
94
95 static inline int
96 RW_LOCK_HELD(krwlock_t *rwp)
97 {
98         return (rwsem_is_locked(SEM(rwp)));
99 }
100
101 static inline int
102 RW_WRITE_HELD(krwlock_t *rwp)
103 {
104         return (rw_owner(rwp) == current);
105 }
106
107 static inline int
108 RW_READ_HELD(krwlock_t *rwp)
109 {
110         return (RW_LOCK_HELD(rwp) && rw_owner(rwp) == NULL);
111 }
112
113 /*
114  * The following functions must be a #define and not static inline.
115  * This ensures that the native linux semaphore functions (down/up)
116  * will be correctly located in the users code which is important
117  * for the built in kernel lock analysis tools
118  */
119 /* BEGIN CSTYLED */
120 #define rw_init(rwp, name, type, arg)                                   \
121 ({                                                                      \
122         static struct lock_class_key __key;                             \
123         ASSERT(type == RW_DEFAULT || type == RW_NOLOCKDEP);             \
124                                                                         \
125         __init_rwsem(SEM(rwp), #rwp, &__key);                           \
126         spl_rw_clear_owner(rwp);                                        \
127         spl_rw_set_type(rwp, type);                                     \
128 })
129
130 /*
131  * The Linux rwsem implementation does not require a matching destroy.
132  */
133 #define rw_destroy(rwp)         ((void) 0)
134
135 /*
136  * Upgrading a rwsem from a reader to a writer is not supported by the
137  * Linux kernel.  The lock must be dropped and reacquired as a writer.
138  */
139 #define rw_tryupgrade(rwp)      RW_WRITE_HELD(rwp)
140
141 #define rw_tryenter(rwp, rw)                                            \
142 ({                                                                      \
143         int _rc_ = 0;                                                   \
144                                                                         \
145         spl_rw_lockdep_off_maybe(rwp);                                  \
146         switch (rw) {                                                   \
147         case RW_READER:                                                 \
148                 _rc_ = down_read_trylock(SEM(rwp));                     \
149                 break;                                                  \
150         case RW_WRITER:                                                 \
151                 if ((_rc_ = down_write_trylock(SEM(rwp))))              \
152                         spl_rw_set_owner(rwp);                          \
153                 break;                                                  \
154         default:                                                        \
155                 VERIFY(0);                                              \
156         }                                                               \
157         spl_rw_lockdep_on_maybe(rwp);                                   \
158         _rc_;                                                           \
159 })
160
161 #define rw_enter(rwp, rw)                                               \
162 ({                                                                      \
163         spl_rw_lockdep_off_maybe(rwp);                                  \
164         switch (rw) {                                                   \
165         case RW_READER:                                                 \
166                 down_read(SEM(rwp));                                    \
167                 break;                                                  \
168         case RW_WRITER:                                                 \
169                 down_write(SEM(rwp));                                   \
170                 spl_rw_set_owner(rwp);                                  \
171                 break;                                                  \
172         default:                                                        \
173                 VERIFY(0);                                              \
174         }                                                               \
175         spl_rw_lockdep_on_maybe(rwp);                                   \
176 })
177
178 #define rw_exit(rwp)                                                    \
179 ({                                                                      \
180         spl_rw_lockdep_off_maybe(rwp);                                  \
181         if (RW_WRITE_HELD(rwp)) {                                       \
182                 spl_rw_clear_owner(rwp);                                \
183                 up_write(SEM(rwp));                                     \
184         } else {                                                        \
185                 ASSERT(RW_READ_HELD(rwp));                              \
186                 up_read(SEM(rwp));                                      \
187         }                                                               \
188         spl_rw_lockdep_on_maybe(rwp);                                   \
189 })
190
191 #define rw_downgrade(rwp)                                               \
192 ({                                                                      \
193         spl_rw_lockdep_off_maybe(rwp);                                  \
194         spl_rw_clear_owner(rwp);                                        \
195         downgrade_write(SEM(rwp));                                      \
196         spl_rw_lockdep_on_maybe(rwp);                                   \
197 })
198 /* END CSTYLED */
199
200 #endif /* _SPL_RWLOCK_H */