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 #define rw_init(rwp, name, type, arg) /* CSTYLED */ \
120 ({ \
121 static struct lock_class_key __key; \
122 ASSERT(type == RW_DEFAULT || type == RW_NOLOCKDEP); \
123 \
124 __init_rwsem(SEM(rwp), #rwp, &__key); \
125 spl_rw_clear_owner(rwp); \
126 spl_rw_set_type(rwp, type); \
127 })
128
129 /*
130 * The Linux rwsem implementation does not require a matching destroy.
131 */
132 #define rw_destroy(rwp) ((void) 0)
133
134 /*
135 * Upgrading a rwsem from a reader to a writer is not supported by the
136 * Linux kernel. The lock must be dropped and reacquired as a writer.
137 */
138 #define rw_tryupgrade(rwp) RW_WRITE_HELD(rwp)
139
140 #define rw_tryenter(rwp, rw) /* CSTYLED */ \
141 ({ \
142 int _rc_ = 0; \
143 \
144 spl_rw_lockdep_off_maybe(rwp); \
145 switch (rw) { \
146 case RW_READER: \
147 _rc_ = down_read_trylock(SEM(rwp)); \
148 break; \
149 case RW_WRITER: \
150 if ((_rc_ = down_write_trylock(SEM(rwp)))) \
151 spl_rw_set_owner(rwp); \
152 break; \
153 default: \
154 VERIFY(0); \
155 } \
156 spl_rw_lockdep_on_maybe(rwp); \
157 _rc_; \
158 })
159
160 #define rw_enter(rwp, rw) /* CSTYLED */ \
161 ({ \
162 spl_rw_lockdep_off_maybe(rwp); \
163 switch (rw) { \
164 case RW_READER: \
165 down_read(SEM(rwp)); \
166 break; \
167 case RW_WRITER: \
168 down_write(SEM(rwp)); \
169 spl_rw_set_owner(rwp); \
170 break; \
171 default: \
172 VERIFY(0); \
173 } \
174 spl_rw_lockdep_on_maybe(rwp); \
175 })
176
177 #define rw_exit(rwp) /* CSTYLED */ \
178 ({ \
179 spl_rw_lockdep_off_maybe(rwp); \
180 if (RW_WRITE_HELD(rwp)) { \
181 spl_rw_clear_owner(rwp); \
182 up_write(SEM(rwp)); \
183 } else { \
184 ASSERT(RW_READ_HELD(rwp)); \
185 up_read(SEM(rwp)); \
186 } \
187 spl_rw_lockdep_on_maybe(rwp); \
188 })
189
190 #define rw_downgrade(rwp) /* CSTYLED */ \
191 ({ \
192 spl_rw_lockdep_off_maybe(rwp); \
193 spl_rw_clear_owner(rwp); \
194 downgrade_write(SEM(rwp)); \
195 spl_rw_lockdep_on_maybe(rwp); \
196 })
197
198 #endif /* _SPL_RWLOCK_H */
Cache object: 3d7b0161ac1ab82dfbff7ddc96546db1
|