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