Merge branch 'stable-3.2' into pandora-3.2
[pandora-kernel.git] / fs / aufs / rwsem.h
1 /*
2  * Copyright (C) 2005-2012 Junjiro R. Okajima
3  *
4  * This program, aufs is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 /*
20  * simple read-write semaphore wrappers
21  */
22
23 #ifndef __AUFS_RWSEM_H__
24 #define __AUFS_RWSEM_H__
25
26 #ifdef __KERNEL__
27
28 #include "debug.h"
29
30 struct au_rwsem {
31         struct rw_semaphore     rwsem;
32 #ifdef CONFIG_AUFS_DEBUG
33         /* just for debugging, not almighty counter */
34         atomic_t                rcnt, wcnt;
35 #endif
36 };
37
38 #ifdef CONFIG_AUFS_DEBUG
39 #define AuDbgCntInit(rw) do { \
40         atomic_set(&(rw)->rcnt, 0); \
41         atomic_set(&(rw)->wcnt, 0); \
42         smp_mb(); /* atomic set */ \
43 } while (0)
44
45 #define AuDbgRcntInc(rw)        atomic_inc(&(rw)->rcnt)
46 #define AuDbgRcntDec(rw)        WARN_ON(atomic_dec_return(&(rw)->rcnt) < 0)
47 #define AuDbgWcntInc(rw)        atomic_inc(&(rw)->wcnt)
48 #define AuDbgWcntDec(rw)        WARN_ON(atomic_dec_return(&(rw)->wcnt) < 0)
49 #else
50 #define AuDbgCntInit(rw)        do {} while (0)
51 #define AuDbgRcntInc(rw)        do {} while (0)
52 #define AuDbgRcntDec(rw)        do {} while (0)
53 #define AuDbgWcntInc(rw)        do {} while (0)
54 #define AuDbgWcntDec(rw)        do {} while (0)
55 #endif /* CONFIG_AUFS_DEBUG */
56
57 /* to debug easier, do not make them inlined functions */
58 #define AuRwMustNoWaiters(rw)   AuDebugOn(!list_empty(&(rw)->rwsem.wait_list))
59 /* rwsem_is_locked() is unusable */
60 #define AuRwMustReadLock(rw)    AuDebugOn(atomic_read(&(rw)->rcnt) <= 0)
61 #define AuRwMustWriteLock(rw)   AuDebugOn(atomic_read(&(rw)->wcnt) <= 0)
62 #define AuRwMustAnyLock(rw)     AuDebugOn(atomic_read(&(rw)->rcnt) <= 0 \
63                                         && atomic_read(&(rw)->wcnt) <= 0)
64 #define AuRwDestroy(rw)         AuDebugOn(atomic_read(&(rw)->rcnt) \
65                                         || atomic_read(&(rw)->wcnt))
66
67 #define au_rw_class(rw, key)    lockdep_set_class(&(rw)->rwsem, key)
68
69 static inline void au_rw_init(struct au_rwsem *rw)
70 {
71         AuDbgCntInit(rw);
72         init_rwsem(&rw->rwsem);
73 }
74
75 static inline void au_rw_init_wlock(struct au_rwsem *rw)
76 {
77         au_rw_init(rw);
78         down_write(&rw->rwsem);
79         AuDbgWcntInc(rw);
80 }
81
82 static inline void au_rw_init_wlock_nested(struct au_rwsem *rw,
83                                            unsigned int lsc)
84 {
85         au_rw_init(rw);
86         down_write_nested(&rw->rwsem, lsc);
87         AuDbgWcntInc(rw);
88 }
89
90 static inline void au_rw_read_lock(struct au_rwsem *rw)
91 {
92         down_read(&rw->rwsem);
93         AuDbgRcntInc(rw);
94 }
95
96 static inline void au_rw_read_lock_nested(struct au_rwsem *rw, unsigned int lsc)
97 {
98         down_read_nested(&rw->rwsem, lsc);
99         AuDbgRcntInc(rw);
100 }
101
102 static inline void au_rw_read_unlock(struct au_rwsem *rw)
103 {
104         AuRwMustReadLock(rw);
105         AuDbgRcntDec(rw);
106         up_read(&rw->rwsem);
107 }
108
109 static inline void au_rw_dgrade_lock(struct au_rwsem *rw)
110 {
111         AuRwMustWriteLock(rw);
112         AuDbgRcntInc(rw);
113         AuDbgWcntDec(rw);
114         downgrade_write(&rw->rwsem);
115 }
116
117 static inline void au_rw_write_lock(struct au_rwsem *rw)
118 {
119         down_write(&rw->rwsem);
120         AuDbgWcntInc(rw);
121 }
122
123 static inline void au_rw_write_lock_nested(struct au_rwsem *rw,
124                                            unsigned int lsc)
125 {
126         down_write_nested(&rw->rwsem, lsc);
127         AuDbgWcntInc(rw);
128 }
129
130 static inline void au_rw_write_unlock(struct au_rwsem *rw)
131 {
132         AuRwMustWriteLock(rw);
133         AuDbgWcntDec(rw);
134         up_write(&rw->rwsem);
135 }
136
137 /* why is not _nested version defined */
138 static inline int au_rw_read_trylock(struct au_rwsem *rw)
139 {
140         int ret = down_read_trylock(&rw->rwsem);
141         if (ret)
142                 AuDbgRcntInc(rw);
143         return ret;
144 }
145
146 static inline int au_rw_write_trylock(struct au_rwsem *rw)
147 {
148         int ret = down_write_trylock(&rw->rwsem);
149         if (ret)
150                 AuDbgWcntInc(rw);
151         return ret;
152 }
153
154 #undef AuDbgCntInit
155 #undef AuDbgRcntInc
156 #undef AuDbgRcntDec
157 #undef AuDbgWcntInc
158 #undef AuDbgWcntDec
159
160 #define AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
161 static inline void prefix##_read_lock(param) \
162 { au_rw_read_lock(rwsem); } \
163 static inline void prefix##_write_lock(param) \
164 { au_rw_write_lock(rwsem); } \
165 static inline int prefix##_read_trylock(param) \
166 { return au_rw_read_trylock(rwsem); } \
167 static inline int prefix##_write_trylock(param) \
168 { return au_rw_write_trylock(rwsem); }
169 /* why is not _nested version defined */
170 /* static inline void prefix##_read_trylock_nested(param, lsc)
171 { au_rw_read_trylock_nested(rwsem, lsc)); }
172 static inline void prefix##_write_trylock_nestd(param, lsc)
173 { au_rw_write_trylock_nested(rwsem, lsc); } */
174
175 #define AuSimpleUnlockRwsemFuncs(prefix, param, rwsem) \
176 static inline void prefix##_read_unlock(param) \
177 { au_rw_read_unlock(rwsem); } \
178 static inline void prefix##_write_unlock(param) \
179 { au_rw_write_unlock(rwsem); } \
180 static inline void prefix##_downgrade_lock(param) \
181 { au_rw_dgrade_lock(rwsem); }
182
183 #define AuSimpleRwsemFuncs(prefix, param, rwsem) \
184         AuSimpleLockRwsemFuncs(prefix, param, rwsem) \
185         AuSimpleUnlockRwsemFuncs(prefix, param, rwsem)
186
187 #endif /* __KERNEL__ */
188 #endif /* __AUFS_RWSEM_H__ */