dafs-vol-offline-race-20090127
[openafs.git] / src / vol / volume_inline.h
1 /*
2  * Copyright 2005-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_VOLUME_INLINE_H
11 #define _AFS_VOL_VOLUME_INLINE_H 1
12
13 #include "volume.h"
14
15 /***************************************************/
16 /* demand attach fs state machine routines         */
17 /***************************************************/
18
19 #ifdef AFS_DEMAND_ATTACH_FS
20 /**
21  * tells caller whether or not the current state requires
22  * exclusive access without holding glock.
23  *
24  * @param state  volume state enumeration
25  *
26  * @return whether volume state is a mutually exclusive state
27  *   @retval 0  no, state is re-entrant
28  *   @retval 1  yes, state is mutually exclusive
29  *
30  * @note DEMAND_ATTACH_FS only
31  */
32 static_inline int
33 VIsExclusiveState(VolState state)
34 {
35     switch (state) {
36     case VOL_STATE_UPDATING:
37     case VOL_STATE_ATTACHING:
38     case VOL_STATE_GET_BITMAP:
39     case VOL_STATE_HDR_LOADING:
40     case VOL_STATE_HDR_ATTACHING:
41     case VOL_STATE_OFFLINING:
42     case VOL_STATE_DETACHING:
43     case VOL_STATE_SALVSYNC_REQ:
44     case VOL_STATE_VNODE_ALLOC:
45     case VOL_STATE_VNODE_GET:
46     case VOL_STATE_VNODE_CLOSE:
47     case VOL_STATE_VNODE_RELEASE:
48         return 1;
49     }
50     return 0;
51 }
52
53 /**
54  * tell caller whether V_attachState is an error condition.
55  *
56  * @param state  volume state enumeration
57  *
58  * @return whether volume state is in error state
59  *   @retval 0  state is not an error state
60  *   @retval 1  state is an error state
61  *
62  * @note DEMAND_ATTACH_FS only
63  */
64 static_inline int
65 VIsErrorState(VolState state)
66 {
67     switch (state) {
68     case VOL_STATE_ERROR:
69     case VOL_STATE_SALVAGING:
70         return 1;
71     }
72     return 0;
73 }
74
75 /**
76  * tell caller whether V_attachState is an offline condition.
77  *
78  * @param state  volume state enumeration
79  *
80  * @return whether volume state is in offline state
81  *   @retval 0  state is not an offline state
82  *   @retval 1  state is an offline state
83  *
84  * @note DEMAND_ATTACH_FS only
85  */
86 static_inline int
87 VIsOfflineState(VolState state)
88 {
89     switch (state) {
90     case VOL_STATE_UNATTACHED:
91     case VOL_STATE_ERROR:
92     case VOL_STATE_SALVAGING:
93         return 1;
94     }
95     return 0;
96 }
97
98 /**
99  * tell caller whether V_attachState is valid.
100  *
101  * @param state  volume state enumeration
102  *
103  * @return whether volume state is a mutually exclusive state
104  *   @retval 0  no, state is not valid
105  *   @retval 1  yes, state is a valid enumeration member
106  *
107  * @note DEMAND_ATTACH_FS only
108  *
109  * @note do we really want to treat VOL_STATE_FREED as valid?
110  */
111 static_inline int
112 VIsValidState(VolState state)
113 {
114     if ((state >= 0) && 
115         (state < VOL_STATE_COUNT)) {
116         return 1;
117     }
118     return 0;
119 }
120
121 /**
122  * increment volume-package internal refcount.
123  *
124  * @param vp  volume object pointer
125  *
126  * @internal volume package internal use only
127  *
128  * @pre VOL_LOCK must be held
129  *
130  * @post volume waiters refcount is incremented
131  *
132  * @see VCancelReservation_r
133  *
134  * @note DEMAND_ATTACH_FS only
135  */
136 static_inline void
137 VCreateReservation_r(Volume * vp)
138 {
139     vp->nWaiters++;
140 }
141
142 /**
143  * wait for the volume to change states.
144  *
145  * @param vp  volume object pointer
146  *
147  * @pre VOL_LOCK held; ref held on volume
148  *
149  * @post VOL_LOCK held; volume state has changed from previous value
150  *
151  * @note DEMAND_ATTACH_FS only
152  */
153 static_inline void
154 VWaitStateChange_r(Volume * vp)
155 {
156     VolState state_save = V_attachState(vp);
157
158     assert(vp->nWaiters || vp->nUsers);
159     do {
160         VOL_CV_WAIT(&V_attachCV(vp));
161     } while (V_attachState(vp) == state_save);
162     assert(V_attachState(vp) != VOL_STATE_FREED);
163 }
164
165 /**
166  * wait for blocking ops to end.
167  *
168  * @pre VOL_LOCK held; ref held on volume
169  *
170  * @post VOL_LOCK held; volume not in exclusive state
171  *
172  * @param vp  volume object pointer
173  *
174  * @note DEMAND_ATTACH_FS only
175  */
176 static_inline void
177 VWaitExclusiveState_r(Volume * vp)
178 {
179     assert(vp->nWaiters || vp->nUsers);
180     while (VIsExclusiveState(V_attachState(vp))) {
181         VOL_CV_WAIT(&V_attachCV(vp));
182     }
183     assert(V_attachState(vp) != VOL_STATE_FREED);
184 }
185
186 /**
187  * change state, and notify other threads,
188  * return previous state to caller.
189  *
190  * @param vp         pointer to volume object
191  * @param new_state  new volume state value
192  * @pre VOL_LOCK held
193  *
194  * @post volume state changed; stats updated
195  *
196  * @return previous volume state
197  *
198  * @note DEMAND_ATTACH_FS only
199  */
200 static_inline VolState
201 VChangeState_r(Volume * vp, VolState new_state)
202 {
203     VolState old_state = V_attachState(vp);
204
205     /* XXX profiling need to make sure these counters
206      * don't kill performance... */
207     VStats.state_levels[old_state]--;
208     VStats.state_levels[new_state]++;
209
210     V_attachState(vp) = new_state;
211     assert(pthread_cond_broadcast(&V_attachCV(vp)) == 0);
212     return old_state;
213 }
214
215 #endif /* AFS_DEMAND_ATTACH_FS */
216
217 #endif /* _AFS_VOL_VOLUME_INLINE_H */