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