Add code for locking individual volumes on disk
[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  * tell caller whether the given program type represents a salvaging
16  * program.
17  *
18  * @param type  program type enumeration
19  *
20  * @return whether program state is a salvager
21  *   @retval 0  type is a non-salvaging program
22  *   @retval 1  type is a salvaging program
23  */
24 static_inline int
25 VIsSalvager(ProgramType type)
26 {
27     switch(type) {
28     case salvager:
29     case salvageServer:
30     case volumeSalvager:
31         return 1;
32     default:
33         return 0;
34     }
35 }
36
37 /**
38  * tells caller whether or not we need to lock the entire partition when
39  * attaching a volume.
40  *
41  * @return whether or not we need to lock the partition
42  *  @retval 0  no, we do not
43  *  @retval 1  yes, we do
44  */
45 static_inline int
46 VRequiresPartLock(void)
47 {
48     switch (programType) {
49     case volumeServer:
50     case volumeUtility:
51         return 1;
52     default:
53         return 0;
54     }
55 }
56
57 /**
58  * tells caller whether we should check the inUse field in the volume
59  * header when attaching a volume.
60  *
61  * If we check inUse, that generally means we will salvage the volume
62  * (or put it in an error state) if we detect that another program
63  * claims to be using the volume when we try to attach. We don't always
64  * want to do that, since sometimes we know that the volume may be in
65  * use by another program, e.g. when we are attaching with V_PEEK, and
66  * we don't care.
67  *
68  * @param mode  the mode of attachment for the volume
69  *
70  * @return whether or not we should check inUse
71  *  @retval 0  no, we should not check inUse
72  *  @retval 1  yes, we should check inUse
73  */
74 static_inline int
75 VShouldCheckInUse(int mode)
76 {
77     if (programType == fileServer) {
78        return 1;
79     }
80     if (VCanUseFSSYNC() && mode != V_SECRETLY && mode != V_PEEK) {
81        /* If we can FSSYNC, we assume we checked out the volume from
82         * the fileserver, so inUse should not be set. If we checked out
83         * with V_SECRETLY or V_PEEK, though, we didn't ask the
84         * fileserver, so don't check inUse. */
85        return 1;
86     }
87     return 0;
88 }
89
90 #ifdef AFS_DEMAND_ATTACH_FS
91 /**
92  * acquire a non-blocking disk lock for a particular volume id.
93  *
94  * @param[in] volid the volume ID to lock
95  * @param[in] dp    the partition on which 'volid' resides
96  * @param[in] locktype READ_LOCK or WRITE_LOCK
97  *
98  * @return operation status
99  *  @retval 0 success, lock was obtained
100  *  @retval EBUSY another process holds a conflicting lock
101  *  @retval EIO   error acquiring lock
102  *
103  * @note Use VLockVolumeNB instead, if possible; only use this directly if
104  * you are not dealing with 'Volume*'s and attached volumes and such
105  *
106  * @pre There must not be any other threads acquiring locks on the same volid
107  * and partition; the locks will not work correctly if two threads try to
108  * acquire locks for the same volume
109  */
110 static_inline int
111 VLockVolumeByIdNB(VolumeId volid, struct DiskPartition64 *dp, int locktype)
112 {
113     return VLockFileLock(&dp->volLockFile, volid, locktype, 1 /* nonblock */);
114 }
115
116 /**
117  * release a lock acquired by VLockVolumeByIdNB.
118  *
119  * @param[in] volid the volume id to unlock
120  * @param[in] dp    the partition on which 'volid' resides
121  *
122  * @pre volid was previously locked by VLockVolumeByIdNB
123  */
124 static_inline void
125 VUnlockVolumeById(VolumeId volid, struct DiskPartition64 *dp)
126 {
127     VLockFileUnlock(&dp->volLockFile, volid);
128 }
129
130 /***************************************************/
131 /* demand attach fs state machine routines         */
132 /***************************************************/
133
134 /**
135  * tells caller whether we need to keep volumes locked for the entire time we
136  * are using them, or if we can unlock volumes as soon as they are attached.
137  *
138  * @return whether we can unlock attached volumes or not
139  *  @retval 1 yes, we can unlock attached volumes
140  *  @retval 0 no, do not unlock volumes until we unattach them
141  */
142 static_inline int
143 VCanUnlockAttached(void)
144 {
145     switch(programType) {
146     case fileServer:
147         return 1;
148     default:
149         return 0;
150     }
151 }
152
153 /**
154  * tells caller whether we need to lock a vol header with a write lock, a
155  * read lock, or if we do not need to lock it at all, when attaching.
156  *
157  * @param[in]  mode  volume attachment mode
158  * @param[in]  writeable  1 if the volume is writable, 0 if not
159  *
160  * @return how we need to lock the vol header
161  *  @retval 0 do not lock the vol header at all
162  *  @retval READ_LOCK lock the vol header with a read lock
163  *  @retval WRITE_LOCK lock the vol header with a write lock
164  *
165  * @note DAFS only (non-DAFS uses partition locks)
166  */
167 static_inline int
168 VVolLockType(int mode, int writeable)
169 {
170     switch (programType) {
171     case fileServer:
172         if (writeable) {
173             return WRITE_LOCK;
174         }
175         return READ_LOCK;
176
177     case volumeSalvager:
178     case salvageServer:
179     case salvager:
180         return WRITE_LOCK;
181
182     default:
183         /* volserver, vol utilies, etc */
184
185         switch (mode) {
186         case V_READONLY:
187             return READ_LOCK;
188
189         case V_VOLUPD:
190         case V_SECRETLY:
191             return WRITE_LOCK;
192
193         case V_CLONE:
194         case V_DUMP:
195             if (writeable) {
196                 return WRITE_LOCK;
197             }
198             return READ_LOCK;
199
200         case V_PEEK:
201             return 0;
202
203         default:
204             assert(0 /* unknown checkout mode */);
205             return 0;
206         }
207     }
208 }
209
210 /**
211  * tells caller whether or not the current state requires
212  * exclusive access without holding glock.
213  *
214  * @param state  volume state enumeration
215  *
216  * @return whether volume state is a mutually exclusive state
217  *   @retval 0  no, state is re-entrant
218  *   @retval 1  yes, state is mutually exclusive
219  *
220  * @note DEMAND_ATTACH_FS only
221  */
222 static_inline int
223 VIsExclusiveState(VolState state)
224 {
225     switch (state) {
226     case VOL_STATE_UPDATING:
227     case VOL_STATE_ATTACHING:
228     case VOL_STATE_GET_BITMAP:
229     case VOL_STATE_HDR_LOADING:
230     case VOL_STATE_HDR_ATTACHING:
231     case VOL_STATE_OFFLINING:
232     case VOL_STATE_DETACHING:
233     case VOL_STATE_SALVSYNC_REQ:
234     case VOL_STATE_VNODE_ALLOC:
235     case VOL_STATE_VNODE_GET:
236     case VOL_STATE_VNODE_CLOSE:
237     case VOL_STATE_VNODE_RELEASE:
238     case VOL_STATE_VLRU_ADD:
239         return 1;
240     default:
241         return 0;
242     }
243 }
244
245 /**
246  * tell caller whether V_attachState is an error condition.
247  *
248  * @param state  volume state enumeration
249  *
250  * @return whether volume state is in error state
251  *   @retval 0  state is not an error state
252  *   @retval 1  state is an error state
253  *
254  * @note DEMAND_ATTACH_FS only
255  */
256 static_inline int
257 VIsErrorState(VolState state)
258 {
259     switch (state) {
260     case VOL_STATE_ERROR:
261     case VOL_STATE_SALVAGING:
262         return 1;
263     default:
264         return 0;
265     }
266 }
267
268 /**
269  * tell caller whether V_attachState is an offline condition.
270  *
271  * @param state  volume state enumeration
272  *
273  * @return whether volume state is in offline state
274  *   @retval 0  state is not an offline state
275  *   @retval 1  state is an offline state
276  *
277  * @note DEMAND_ATTACH_FS only
278  */
279 static_inline int
280 VIsOfflineState(VolState state)
281 {
282     switch (state) {
283     case VOL_STATE_UNATTACHED:
284     case VOL_STATE_ERROR:
285     case VOL_STATE_SALVAGING:
286         return 1;
287     default:
288         return 0;
289     }
290 }
291
292 /**
293  * tell caller whether V_attachState is valid.
294  *
295  * @param state  volume state enumeration
296  *
297  * @return whether volume state is a mutually exclusive state
298  *   @retval 0  no, state is not valid
299  *   @retval 1  yes, state is a valid enumeration member
300  *
301  * @note DEMAND_ATTACH_FS only
302  *
303  * @note do we really want to treat VOL_STATE_FREED as valid?
304  */
305 static_inline int
306 VIsValidState(VolState state)
307 {
308     if ((state >= 0) && 
309         (state < VOL_STATE_COUNT)) {
310         return 1;
311     }
312     return 0;
313 }
314
315 /**
316  * increment volume-package internal refcount.
317  *
318  * @param vp  volume object pointer
319  *
320  * @internal volume package internal use only
321  *
322  * @pre VOL_LOCK must be held
323  *
324  * @post volume waiters refcount is incremented
325  *
326  * @see VCancelReservation_r
327  *
328  * @note DEMAND_ATTACH_FS only
329  */
330 static_inline void
331 VCreateReservation_r(Volume * vp)
332 {
333     vp->nWaiters++;
334 }
335
336 /**
337  * wait for the volume to change states.
338  *
339  * @param vp  volume object pointer
340  *
341  * @pre VOL_LOCK held; ref held on volume
342  *
343  * @post VOL_LOCK held; volume state has changed from previous value
344  *
345  * @note DEMAND_ATTACH_FS only
346  */
347 static_inline void
348 VWaitStateChange_r(Volume * vp)
349 {
350     VolState state_save = V_attachState(vp);
351
352     assert(vp->nWaiters || vp->nUsers);
353     do {
354         VOL_CV_WAIT(&V_attachCV(vp));
355     } while (V_attachState(vp) == state_save);
356     assert(V_attachState(vp) != VOL_STATE_FREED);
357 }
358
359 /**
360  * wait for blocking ops to end.
361  *
362  * @pre VOL_LOCK held; ref held on volume
363  *
364  * @post VOL_LOCK held; volume not in exclusive state
365  *
366  * @param vp  volume object pointer
367  *
368  * @note DEMAND_ATTACH_FS only
369  */
370 static_inline void
371 VWaitExclusiveState_r(Volume * vp)
372 {
373     assert(vp->nWaiters || vp->nUsers);
374     while (VIsExclusiveState(V_attachState(vp))) {
375         VOL_CV_WAIT(&V_attachCV(vp));
376     }
377     assert(V_attachState(vp) != VOL_STATE_FREED);
378 }
379
380 /**
381  * change state, and notify other threads,
382  * return previous state to caller.
383  *
384  * @param vp         pointer to volume object
385  * @param new_state  new volume state value
386  * @pre VOL_LOCK held
387  *
388  * @post volume state changed; stats updated
389  *
390  * @return previous volume state
391  *
392  * @note DEMAND_ATTACH_FS only
393  */
394 static_inline VolState
395 VChangeState_r(Volume * vp, VolState new_state)
396 {
397     VolState old_state = V_attachState(vp);
398
399     /* XXX profiling need to make sure these counters
400      * don't kill performance... */
401     VStats.state_levels[old_state]--;
402     VStats.state_levels[new_state]++;
403
404     V_attachState(vp) = new_state;
405     assert(pthread_cond_broadcast(&V_attachCV(vp)) == 0);
406     return old_state;
407 }
408
409 #endif /* AFS_DEMAND_ATTACH_FS */
410
411 #define VENUMCASE(en) \
412     case en: \
413         return #en; \
414         break
415
416 /**
417  * translate a ProgramType code to a string.
418  *
419  * @param[in] type ProgramType numeric code
420  *
421  * @return a human-readable string for that program type
422  *  @retval "**UNKNOWN**" an unknown ProgramType was given
423  */
424 static_inline char *
425 VPTypeToString(ProgramType type)
426 {
427     switch (type) {
428         VENUMCASE(fileServer);
429         VENUMCASE(volumeUtility);
430         VENUMCASE(salvager);
431         VENUMCASE(salvageServer);
432         VENUMCASE(debugUtility);
433         VENUMCASE(volumeServer);
434         VENUMCASE(volumeSalvager);
435     default:
436         return "**UNKNOWN**";
437     }
438 }
439
440 #undef VENUMCASE
441
442 #endif /* _AFS_VOL_VOLUME_INLINE_H */