]> git.proxmox.com Git - mirror_spl.git/blob - include/sys/rwlock.h
Update rwlocks to track owner to ensure correct semantics
[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 init_rwsem(SEM(rwp)); \
158 spl_rw_clear_owner(rwp); \
159 })
160
161 #define rw_destroy(rwp) \
162 ({ \
163 VERIFY(!RW_LOCK_HELD(rwp)); \
164 })
165
166 #define rw_tryenter(rwp, rw) \
167 ({ \
168 int _rc_ = 0; \
169 \
170 switch (rw) { \
171 case RW_READER: \
172 _rc_ = down_read_trylock(SEM(rwp)); \
173 break; \
174 case RW_WRITER: \
175 if ((_rc_ = down_write_trylock(SEM(rwp)))) \
176 spl_rw_set_owner(rwp); \
177 break; \
178 default: \
179 SBUG(); \
180 } \
181 _rc_; \
182 })
183
184 #define rw_enter(rwp, rw) \
185 ({ \
186 switch (rw) { \
187 case RW_READER: \
188 down_read(SEM(rwp)); \
189 break; \
190 case RW_WRITER: \
191 down_write(SEM(rwp)); \
192 spl_rw_set_owner(rwp); \
193 break; \
194 default: \
195 SBUG(); \
196 } \
197 })
198
199 #define rw_exit(rwp) \
200 ({ \
201 if (RW_WRITE_HELD(rwp)) { \
202 spl_rw_clear_owner(rwp); \
203 up_write(SEM(rwp)); \
204 } else { \
205 ASSERT(RW_READ_HELD(rwp)); \
206 up_read(SEM(rwp)); \
207 } \
208 })
209
210 #define rw_downgrade(rwp) \
211 ({ \
212 spl_rw_clear_owner(rwp); \
213 downgrade_write(SEM(rwp)); \
214 })
215
216 #define rw_tryupgrade(rwp) \
217 ({ \
218 unsigned long _flags_; \
219 int _rc_ = 0; \
220 \
221 spin_lock_irqsave(&SEM(rwp)->wait_lock, _flags_); \
222 if (list_empty(&SEM(rwp)->wait_list) && (RW_COUNT(rwp) == 1)) { \
223 rw_exit_locked(SEM(rwp)); \
224 VERIFY(_rc_ = rw_tryenter_locked(SEM(rwp))); \
225 (rwp)->rw_owner = current; \
226 } \
227 spin_unlock_irqrestore(&SEM(rwp)->wait_lock, _flags_); \
228 _rc_; \
229 })
230
231 int spl_rw_init(void);
232 void spl_rw_fini(void);
233
234 #endif /* _SPL_RWLOCK_H */