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