1cfdf980f0803c0b601c6537465457bb72379257
[openafs.git] / src / vol / vnode_inline.h
1 /*
2  * Copyright 2007-2008, Sine Nomine Associates and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #ifndef _AFS_VOL_VNODE_INLINE_H
11 #define _AFS_VOL_VNODE_INLINE_H 1
12
13 #include "vnode.h"
14
15 #ifdef AFS_HPUX_ENV
16 #define static_inline static __inline
17 #elif defined(AFS_AIX_ENV) || defined(AFS_SGI_ENV)
18 #define static_inline static
19 #else
20 #define static_inline static inline
21 #endif
22
23 /***************************************************/
24 /* demand attach vnode state machine routines      */
25 /***************************************************/
26
27 /**
28  * get a reference to a vnode object.
29  *
30  * @param[in] vnp  vnode object pointer
31  *
32  * @internal vnode package internal use only
33  *
34  * @pre VOL_LOCK must be held
35  *
36  * @post vnode refcount incremented
37  *
38  * @see VnCancelReservation_r
39  */
40 static_inline void
41 VnCreateReservation_r(Vnode * vnp)
42 {
43     Vn_refcount(vnp)++;
44     if (Vn_refcount(vnp) == 1) {
45         DeleteFromVnLRU(Vn_class(vnp), vnp);
46     }
47 }
48
49 extern int TrustVnodeCacheEntry;
50
51 /**
52  * release a reference to a vnode object.
53  *
54  * @param[in] vnp  vnode object pointer
55  *
56  * @pre VOL_LOCK held
57  *
58  * @post refcount decremented; possibly re-added to vn lru
59  *
60  * @internal vnode package internal use only
61  *
62  * @see VnCreateReservation_r
63  */
64 static_inline void
65 VnCancelReservation_r(Vnode * vnp)
66 {
67     if (--Vn_refcount(vnp) == 0) {
68         AddToVnLRU(Vn_class(vnp), vnp);
69
70         /* If caching is turned off, 
71          * disassociate vnode cache entry from volume object */
72         if (!TrustVnodeCacheEntry) {
73             DeleteFromVVnList(vnp);
74         }
75     }
76 }
77
78 #ifdef AFS_PTHREAD_ENV
79 #define VN_SET_WRITER_THREAD_ID(v)  (((v)->writer) = pthread_self())
80 #else
81 #define VN_SET_WRITER_THREAD_ID(v)  (LWP_CurrentProcess(&((v)->writer)))
82 #endif
83
84 #define VOL_LOCK_NOT_HELD 0
85 #define VOL_LOCK_HELD 1
86 #define MIGHT_DEADLOCK 0
87 #define WILL_NOT_DEADLOCK 1
88
89 /**
90  * acquire a lock on a vnode object.
91  *
92  * @param[in] vnp   vnode object pointer
93  * @param[in] type  lock type
94  * @param[in] held  whether or not vol glock is held
95  * @param[in] safe  whether it it is safe to acquire without dropping vol glock
96  *
97  * @note caller must guarantee deadlock will not occur
98  *
99  * @post lock acquired.
100  *       for write case, thread owner field set.
101  *
102  * @note for DAFS, this is a no-op
103  *
104  * @internal vnode package internal use only
105  */
106 static_inline void
107 VnLock(Vnode * vnp, int type, int held, int safe)
108 {
109 #ifdef AFS_DEMAND_ATTACH_FS
110     if (type == WRITE_LOCK) {
111         VN_SET_WRITER_THREAD_ID(vnp);
112     }
113 #else /* !AFS_DEMAND_ATTACH_FS */
114     if (held && !safe) {
115         VOL_UNLOCK;
116     }
117     if (type == READ_LOCK) {
118         ObtainReadLock(&vnp->lock);
119     } else {
120         ObtainWriteLock(&vnp->lock);
121         VN_SET_WRITER_THREAD_ID(vnp);
122     }
123     if (held && !safe) {
124         VOL_LOCK;
125     }
126 #endif /* !AFS_DEMAND_ATTACH_FS */
127 }
128
129 /**
130  * release a lock on a vnode object.
131  *
132  * @param[in] vnp   vnode object pointer
133  * @param[in] type  lock type
134  *
135  * @note for DAFS, this is a no-op
136  *
137  * @internal vnode package internal use only
138  */
139 static_inline void
140 VnUnlock(Vnode * vnp, int type)
141 {
142     if (type == READ_LOCK) {
143 #ifndef AFS_DEMAND_ATTACH_FS
144         ReleaseReadLock(&vnp->lock);
145 #endif
146     } else {
147         vnp->writer = 0;
148 #ifndef AFS_DEMAND_ATTACH_FS
149         ReleaseWriteLock(&vnp->lock);
150 #endif
151     }
152 }
153
154
155 #ifdef AFS_DEMAND_ATTACH_FS
156 /**
157  * change state, and notify other threads,
158  * return previous state to caller.
159  *
160  * @param[in] vnp        pointer to vnode object
161  * @param[in] new_state  new vnode state value
162  *
163  * @pre VOL_LOCK held
164  *
165  * @post vnode state changed
166  *
167  * @return previous vnode state
168  *
169  * @note DEMAND_ATTACH_FS only
170  *
171  * @internal vnode package internal use only
172  */
173 static_inline VnState
174 VnChangeState_r(Vnode * vnp, VnState new_state)
175 {
176     VnState old_state = Vn_state(vnp);
177
178     Vn_state(vnp) = new_state;
179     assert(pthread_cond_broadcast(&Vn_stateCV(vnp)) == 0);
180     return old_state;
181 }
182
183 /**
184  * tells caller whether or not the current state requires
185  * exclusive access without holding glock.
186  *
187  * @param[in] state  vnode state enumeration
188  *
189  * @return whether vnode state is a mutually exclusive state
190  *   @retval 0  no, state is re-entrant
191  *   @retval 1  yes, state is mutually exclusive
192  *
193  * @note DEMAND_ATTACH_FS only
194  */
195 static_inline int
196 VnIsExclusiveState(VnState state)
197 {
198     switch (state) {
199     case VN_STATE_RELEASING:
200     case VN_STATE_CLOSING:
201     case VN_STATE_ALLOC:
202     case VN_STATE_LOAD:
203     case VN_STATE_EXCLUSIVE:
204     case VN_STATE_STORE:
205         return 1;
206     }
207     return 0;
208 }
209
210 /**
211  * tell caller whether vnode state is an error condition.
212  *
213  * @param[in] state  vnode state enumeration
214  *
215  * @return whether vnode state is in error state
216  *   @retval 0  state is not an error state
217  *   @retval 1  state is an error state
218  *
219  * @note DEMAND_ATTACH_FS only
220  */
221 static_inline int
222 VnIsErrorState(VnState state)
223 {
224     switch (state) {
225     case VN_STATE_ERROR:
226         return 1;
227     }
228     return 0;
229 }
230
231 /**
232  * tell caller whether vnode state is valid.
233  *
234  * @param[in] state  vnode state enumeration
235  *
236  * @return whether vnode state is a mutually exclusive state
237  *   @retval 0  no, state is not valid
238  *   @retval 1  yes, state is a valid enumeration member
239  *
240  * @note DEMAND_ATTACH_FS only
241  */
242 static_inline int
243 VnIsValidState(VnState state)
244 {
245     if ((state >= 0) && 
246         (state < VN_STATE_COUNT)) {
247         return 1;
248     }
249     return 0;
250 }
251
252 /**
253  * wait for the vnode to change states.
254  *
255  * @param[in] vnp  vnode object pointer
256  *
257  * @pre VOL_LOCK held; ref held on vnode
258  *
259  * @post VOL_LOCK held; vnode state has changed from previous value
260  *
261  * @note DEMAND_ATTACH_FS only
262  */
263 static_inline void
264 VnWaitStateChange_r(Vnode * vnp)
265 {
266     VnState state_save = Vn_state(vnp);
267
268     assert(Vn_refcount(vnp));
269     do {
270         VOL_CV_WAIT(&Vn_stateCV(vnp));
271     } while (Vn_state(vnp) == state_save);
272     assert(!(Vn_stateFlags(vnp) & VN_ON_LRU));
273 }
274
275 /**
276  * wait for blocking ops to end.
277  *
278  * @pre VOL_LOCK held; ref held on vnode
279  *
280  * @post VOL_LOCK held; vnode not in exclusive state
281  *
282  * @param[in] vnp  vnode object pointer
283  *
284  * @note DEMAND_ATTACH_FS only
285  */
286 static_inline void
287 VnWaitExclusiveState_r(Vnode * vnp)
288 {
289     assert(Vn_refcount(vnp));
290     while (VnIsExclusiveState(Vn_state(vnp))) {
291         VOL_CV_WAIT(&Vn_stateCV(vnp));
292     }
293     assert(!(Vn_stateFlags(vnp) & VN_ON_LRU));
294 }
295
296 /**
297  * wait until vnode is in non-exclusive state, and there are no active readers.
298  *
299  * @param[in] vnp  vnode object pointer
300  *
301  * @pre VOL_LOCK held; ref held on vnode
302  *
303  * @post VOL_LOCK held; vnode is in non-exclusive state and has no active readers
304  *
305  * @note DEMAND_ATTACH_FS only
306  */
307 static_inline void
308 VnWaitQuiescent_r(Vnode * vnp)
309 {
310     assert(Vn_refcount(vnp));
311     while (VnIsExclusiveState(Vn_state(vnp)) ||
312            Vn_readers(vnp)) {
313         VOL_CV_WAIT(&Vn_stateCV(vnp));
314     }
315     assert(!(Vn_stateFlags(vnp) & VN_ON_LRU));
316 }
317
318 /**
319  * register a new reader on a vnode.
320  *
321  * @param[in] vnp  vnode object pointer
322  *
323  * @pre VOL_LOCK held.
324  *      ref held on vnode.
325  *      vnode in VN_STATE_READ or VN_STATE_ONLINE
326  *
327  * @post refcount incremented.
328  *       state set to VN_STATE_READ.
329  *
330  * @note DEMAND_ATTACH_FS only
331  *
332  * @internal vnode package internal use only
333  */
334 static_inline void
335 VnBeginRead_r(Vnode * vnp)
336 {
337     if (!Vn_readers(vnp)) {
338         assert(Vn_state(vnp) == VN_STATE_ONLINE);
339         VnChangeState_r(vnp, VN_STATE_READ);
340     }
341     Vn_readers(vnp)++;
342     assert(Vn_state(vnp) == VN_STATE_READ);
343 }
344
345 /**
346  * deregister a reader on a vnode.
347  *
348  * @param[in] vnp  vnode object pointer
349  *
350  * @pre VOL_LOCK held.
351  *      ref held on vnode.
352  *      read ref held on vnode.
353  *      vnode in VN_STATE_READ.
354  *
355  * @post refcount decremented.
356  *       when count reaches zero, state set to VN_STATE_ONLINE.
357  *
358  * @note DEMAND_ATTACH_FS only
359  *
360  * @internal vnode package internal use only
361  */
362 static_inline void
363 VnEndRead_r(Vnode * vnp)
364 {
365     assert(Vn_readers(vnp) > 0);
366     Vn_readers(vnp)--;
367     if (!Vn_readers(vnp)) {
368         assert(pthread_cond_broadcast(&Vn_stateCV(vnp)) == 0);
369         VnChangeState_r(vnp, VN_STATE_ONLINE);
370     }
371 }
372
373 #endif /* AFS_DEMAND_ATTACH_FS */
374
375 #endif /* _AFS_VOL_VNODE_INLINE_H */