]> git.proxmox.com Git - mirror_spl.git/blob - include/sys/rwlock.h
75356b95d8fb77bd91ee1d092c524b6c6069bae0
[mirror_spl.git] / include / sys / rwlock.h
1 /*
2 * This file is part of the SPL: Solaris Porting Layer.
3 *
4 * Copyright (c) 2009 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 #ifndef _SPL_RWLOCK_H
28 #define _SPL_RWLOCK_H
29
30 #include <sys/types.h>
31 #include <linux/rwsem.h>
32
33 typedef enum {
34 RW_DRIVER = 2,
35 RW_DEFAULT = 4
36 } krw_type_t;
37
38 typedef enum {
39 RW_NONE = 0,
40 RW_WRITER = 1,
41 RW_READER = 2
42 } krw_t;
43
44 typedef struct {
45 struct rw_semaphore rw_rwlock;
46 kthread_t *rw_owner;
47 } krwlock_t;
48
49 /*
50 * For the generic and x86 implementations of rw-semaphores the following
51 * is true. If your semaphore implementation internally represents the
52 * semaphore state differently special case handling will be required.
53 * - if activity/count is 0 then there are no active readers or writers
54 * - if activity/count is +ve then that is the number of active readers
55 * - if activity/count is -1 then there is one active writer
56 */
57 #define SEM(rwp) ((struct rw_semaphore *)(rwp))
58
59 #if defined(CONFIG_RWSEM_GENERIC_SPINLOCK)
60 # define RW_COUNT(rwp) (SEM(rwp)->activity)
61 # define rw_exit_locked(rwp) __up_read_locked(rwp)
62 # define rw_tryenter_locked(rwp) __down_write_trylock_locked(rwp)
63 extern void __up_read_locked(struct rw_semaphore *);
64 extern int __down_write_trylock_locked(struct rw_semaphore *);
65 #else
66 # define RW_COUNT(rwp) (SEM(rwp)->count & RWSEM_ACTIVE_MASK)
67 # define rw_exit_locked(rwp) up_read(rwp)
68 # define rw_tryenter_locked(rwp) down_write_trylock(rwp)
69 #endif
70
71 static inline kthread_t *
72 spl_rw_get_owner(krwlock_t *rwp)
73 {
74 return rwp->rw_owner;
75 }
76
77 static inline void
78 spl_rw_set_owner(krwlock_t *rwp)
79 {
80 unsigned long flags;
81
82 spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
83 rwp->rw_owner = current;
84 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
85 }
86
87 static inline void
88 spl_rw_clear_owner(krwlock_t *rwp)
89 {
90 unsigned long flags;
91
92 spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
93 rwp->rw_owner = NULL;
94 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
95 }
96
97 static inline kthread_t *
98 rw_owner(krwlock_t *rwp)
99 {
100 unsigned long flags;
101 kthread_t *owner;
102
103 spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
104 owner = spl_rw_get_owner(rwp);
105 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
106
107 return owner;
108 }
109
110 static inline int
111 RW_READ_HELD(krwlock_t *rwp)
112 {
113 unsigned long flags;
114 int rc;
115
116 spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
117 rc = ((RW_COUNT(rwp) > 0) && (spl_rw_get_owner(rwp) == NULL));
118 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
119
120 return rc;
121 }
122
123 static inline int
124 RW_WRITE_HELD(krwlock_t *rwp)
125 {
126 unsigned long flags;
127 int rc;
128
129 spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
130 rc = ((RW_COUNT(rwp) < 0) && (spl_rw_get_owner(rwp) == current));
131 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
132
133 return rc;
134 }
135
136 static inline int
137 RW_LOCK_HELD(krwlock_t *rwp)
138 {
139 unsigned long flags;
140 int rc;
141
142 spin_lock_irqsave(&SEM(rwp)->wait_lock, flags);
143 rc = (RW_COUNT(rwp) != 0);
144 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, flags);
145
146 return rc;
147 }
148
149 /*
150 * The following functions must be a #define and not static inline.
151 * This ensures that the native linux semaphore functions (down/up)
152 * will be correctly located in the users code which is important
153 * for the built in kernel lock analysis tools
154 */
155 #define rw_init(rwp, name, type, arg) \
156 ({ \
157 static struct lock_class_key __key; \
158 \
159 __init_rwsem(SEM(rwp), #rwp, &__key); \
160 spl_rw_clear_owner(rwp); \
161 })
162
163 #define rw_destroy(rwp) \
164 ({ \
165 VERIFY(!RW_LOCK_HELD(rwp)); \
166 })
167
168 #define rw_tryenter(rwp, rw) \
169 ({ \
170 int _rc_ = 0; \
171 \
172 switch (rw) { \
173 case RW_READER: \
174 _rc_ = down_read_trylock(SEM(rwp)); \
175 break; \
176 case RW_WRITER: \
177 if ((_rc_ = down_write_trylock(SEM(rwp)))) \
178 spl_rw_set_owner(rwp); \
179 break; \
180 default: \
181 SBUG(); \
182 } \
183 _rc_; \
184 })
185
186 #define rw_enter(rwp, rw) \
187 ({ \
188 switch (rw) { \
189 case RW_READER: \
190 down_read(SEM(rwp)); \
191 break; \
192 case RW_WRITER: \
193 down_write(SEM(rwp)); \
194 spl_rw_set_owner(rwp); \
195 break; \
196 default: \
197 SBUG(); \
198 } \
199 })
200
201 #define rw_exit(rwp) \
202 ({ \
203 if (RW_WRITE_HELD(rwp)) { \
204 spl_rw_clear_owner(rwp); \
205 up_write(SEM(rwp)); \
206 } else { \
207 ASSERT(RW_READ_HELD(rwp)); \
208 up_read(SEM(rwp)); \
209 } \
210 })
211
212 #define rw_downgrade(rwp) \
213 ({ \
214 spl_rw_clear_owner(rwp); \
215 downgrade_write(SEM(rwp)); \
216 })
217
218 #define rw_tryupgrade(rwp) \
219 ({ \
220 unsigned long _flags_; \
221 int _rc_ = 0; \
222 \
223 spin_lock_irqsave(&SEM(rwp)->wait_lock, _flags_); \
224 if (list_empty(&SEM(rwp)->wait_list) && (RW_COUNT(rwp) == 1)) { \
225 rw_exit_locked(SEM(rwp)); \
226 VERIFY(_rc_ = rw_tryenter_locked(SEM(rwp))); \
227 (rwp)->rw_owner = current; \
228 } \
229 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, _flags_); \
230 _rc_; \
231 })
232
233 int spl_rw_init(void);
234 void spl_rw_fini(void);
235
236 #endif /* _SPL_RWLOCK_H */