2 * Copyright 2005-2008, Sine Nomine Associates and others.
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
10 #ifndef _AFS_VOL_VOLUME_INLINE_H
11 #define _AFS_VOL_VOLUME_INLINE_H 1
14 #include "partition.h"
16 #if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
20 #ifdef AFS_PTHREAD_ENV
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.
29 VOL_CV_TIMEDWAIT(pthread_cond_t *cv, const struct timespec *ts, int *timedout)
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) {
48 osi_Assert(code == 0);
50 #endif /* AFS_PTHREAD_ENV */
53 * tell caller whether the given program type represents a salvaging
56 * @param type program type enumeration
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
63 VIsSalvager(ProgramType type)
76 * tells caller whether or not we need to lock the entire partition when
79 * @return whether or not we need to lock the partition
80 * @retval 0 no, we do not
81 * @retval 1 yes, we do
83 * @note for DAFS, always returns 0, since we use per-header locks instead
86 VRequiresPartLock(void)
88 #if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
91 switch (programType) {
98 #endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
102 * tells caller whether or not we need to check out a volume from the
103 * fileserver before we can use it.
105 * @param[in] mode the mode of attachment for the volume
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
112 VMustCheckoutVolume(int mode)
114 if (VCanUseFSSYNC() && mode != V_SECRETLY && mode != V_PEEK) {
121 * tells caller whether we should check the inUse field in the volume
122 * header when attaching a volume.
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
131 * @param mode the mode of attachment for the volume
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
138 VShouldCheckInUse(int mode)
140 if (VCanUnsafeAttach()) {
143 if (programType == fileServer) {
146 if (VMustCheckoutVolume(mode)) {
147 /* assume we checked out the volume from the fileserver, so inUse
148 * should not be set */
154 #if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
156 * acquire a non-blocking disk lock for a particular volume id.
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
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
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
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
175 VLockVolumeByIdNB(VolumeId volid, struct DiskPartition64 *dp, int locktype)
177 return VLockFileLock(&dp->volLockFile, volid, locktype, 1 /* nonblock */);
181 * release a lock acquired by VLockVolumeByIdNB.
183 * @param[in] volid the volume id to unlock
184 * @param[in] dp the partition on which 'volid' resides
186 * @pre volid was previously locked by VLockVolumeByIdNB
189 VUnlockVolumeById(VolumeId volid, struct DiskPartition64 *dp)
191 VLockFileUnlock(&dp->volLockFile, volid);
194 /***************************************************/
195 /* demand attach fs state machine routines */
196 /***************************************************/
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.
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
207 VCanUnlockAttached(void)
209 switch(programType) {
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.
221 * @param[in] mode volume attachment mode
222 * @param[in] writeable 1 if the volume is writable, 0 if not
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
229 * @note DAFS only (non-DAFS uses partition locks)
232 VVolLockType(int mode, int writeable)
234 switch (programType) {
247 /* volserver, vol utilies, etc */
268 osi_Assert(0 /* unknown checkout mode */);
273 #endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
275 #ifdef AFS_DEMAND_ATTACH_FS
278 * tells caller whether or not the volume is effectively salvaging.
280 * @param vp volume pointer
282 * @return whether volume is salvaging or not
283 * @retval 0 no, volume is not salvaging
284 * @retval 1 yes, volume is salvaging
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.
293 VIsSalvaging(struct Volume *vp)
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:
301 if (vp->salvage.requested || vp->salvage.scheduled) {
309 * tells caller whether or not the current state requires
310 * exclusive access without holding glock.
312 * @param state volume state enumeration
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
318 * @note DEMAND_ATTACH_FS only
321 VIsExclusiveState(VolState 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:
345 * tell caller whether V_attachState is an error condition.
347 * @param state volume state enumeration
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
353 * @note DEMAND_ATTACH_FS only
356 VIsErrorState(VolState state)
359 case VOL_STATE_ERROR:
360 case VOL_STATE_SALVAGING:
361 case VOL_STATE_SALVAGE_REQ:
369 * tell caller whether V_attachState is an offline condition.
371 * @param state volume state enumeration
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
377 * @note DEMAND_ATTACH_FS only
380 VIsOfflineState(VolState state)
383 case VOL_STATE_UNATTACHED:
384 case VOL_STATE_ERROR:
385 case VOL_STATE_SALVAGING:
386 case VOL_STATE_DELETED:
394 * tell caller whether V_attachState is valid.
396 * @param state volume state enumeration
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
402 * @note DEMAND_ATTACH_FS only
404 * @note do we really want to treat VOL_STATE_FREED as valid?
407 VIsValidState(VolState state)
410 (state < VOL_STATE_COUNT)) {
417 * increment volume-package internal refcount.
419 * @param vp volume object pointer
421 * @internal volume package internal use only
423 * @pre VOL_LOCK must be held
425 * @post volume waiters refcount is incremented
427 * @see VCancelReservation_r
429 * @note DEMAND_ATTACH_FS only
432 VCreateReservation_r(Volume * vp)
438 * wait for the volume to change states.
440 * @param vp volume object pointer
442 * @pre VOL_LOCK held; ref held on volume
444 * @post VOL_LOCK held; volume state has changed from previous value
446 * @note DEMAND_ATTACH_FS only
449 VWaitStateChange_r(Volume * vp)
451 VolState state_save = V_attachState(vp);
453 osi_Assert(vp->nWaiters || vp->nUsers);
455 VOL_CV_WAIT(&V_attachCV(vp));
456 } while (V_attachState(vp) == state_save);
457 osi_Assert(V_attachState(vp) != VOL_STATE_FREED);
461 * wait for the volume to change states within a certain amount of time
463 * @param[in] vp volume object pointer
464 * @param[in] ts deadline (absolute time) or NULL to wait forever
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
470 * @note DEMAND_ATTACH_FS only
471 * @note if ts is NULL, this is identical to VWaitStateChange_r
474 VTimedWaitStateChange_r(Volume * vp, const struct timespec *ts, int *atimedout)
484 VWaitStateChange_r(vp);
488 state_save = V_attachState(vp);
490 assert(vp->nWaiters || vp->nUsers);
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);
496 if (atimedout && timeout) {
502 * wait for blocking ops to end.
504 * @pre VOL_LOCK held; ref held on volume
506 * @post VOL_LOCK held; volume not in exclusive state
508 * @param vp volume object pointer
510 * @note DEMAND_ATTACH_FS only
513 VWaitExclusiveState_r(Volume * vp)
515 osi_Assert(vp->nWaiters || vp->nUsers);
516 while (VIsExclusiveState(V_attachState(vp))) {
517 VOL_CV_WAIT(&V_attachCV(vp));
519 osi_Assert(V_attachState(vp) != VOL_STATE_FREED);
523 * change state, and notify other threads,
524 * return previous state to caller.
526 * @param vp pointer to volume object
527 * @param new_state new volume state value
530 * @post volume state changed; stats updated
532 * @return previous volume state
534 * @note DEMAND_ATTACH_FS only
536 static_inline VolState
537 VChangeState_r(Volume * vp, VolState new_state)
539 VolState old_state = V_attachState(vp);
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]++;
546 V_attachState(vp) = new_state;
547 CV_BROADCAST(&V_attachCV(vp));
551 #endif /* AFS_DEMAND_ATTACH_FS */
553 #define VENUMCASE(en) \
557 * translate a ProgramType code to a string.
559 * @param[in] type ProgramType numeric code
561 * @return a human-readable string for that program type
562 * @retval "**UNKNOWN**" an unknown ProgramType was given
565 VPTypeToString(ProgramType type)
568 VENUMCASE(fileServer);
569 VENUMCASE(volumeUtility);
571 VENUMCASE(salvageServer);
572 VENUMCASE(debugUtility);
573 VENUMCASE(volumeServer);
574 VENUMCASE(volumeSalvager);
576 return "**UNKNOWN**";
582 #endif /* _AFS_VOL_VOLUME_INLINE_H */