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 #include <afs/opr_assert.h>
25 * @param[in] cv cond var
26 * @param[in] ts deadline, or NULL to wait forever
27 * @param[out] timedout set to 1 if we returned due to the deadline, 0 if we
28 * returned due to the cond var getting signalled. If
29 * NULL, it is ignored.
32 VOL_CV_TIMEDWAIT(pthread_cond_t *cv, const struct timespec *ts, int *timedout)
42 VOL_LOCK_DBG_CV_WAIT_BEGIN;
43 code = CV_TIMEDWAIT(cv, &vol_glock_mutex, ts);
44 VOL_LOCK_DBG_CV_WAIT_END;
45 if (code == ETIMEDOUT) {
51 opr_Assert(code == 0);
53 #endif /* AFS_PTHREAD_ENV */
56 * tell caller whether the given program type represents a salvaging
59 * @param type program type enumeration
61 * @return whether program state is a salvager
62 * @retval 0 type is a non-salvaging program
63 * @retval 1 type is a salvaging program
66 VIsSalvager(ProgramType type)
79 * tells caller whether or not we need to lock the entire partition when
82 * @return whether or not we need to lock the partition
83 * @retval 0 no, we do not
84 * @retval 1 yes, we do
86 * @note for DAFS, always returns 0, since we use per-header locks instead
89 VRequiresPartLock(void)
91 #if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
94 switch (programType) {
101 #endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
105 * tells caller whether or not we need to check out a volume from the
106 * fileserver before we can use it.
108 * @param[in] mode the mode of attachment for the volume
110 * @return whether or not we need to check out the volume from the fileserver
111 * @retval 0 no, we can just use the volume
112 * @retval 1 yes, we must check out the volume before use
115 VMustCheckoutVolume(int mode)
117 if (VCanUseFSSYNC() && mode != V_SECRETLY && mode != V_PEEK) {
124 * tells caller whether we should check the inUse field in the volume
125 * header when attaching a volume.
127 * If we check inUse, that generally means we will salvage the volume
128 * (or put it in an error state) if we detect that another program
129 * claims to be using the volume when we try to attach. We don't always
130 * want to do that, since sometimes we know that the volume may be in
131 * use by another program, e.g. when we are attaching with V_PEEK, and
134 * @param mode the mode of attachment for the volume
136 * @return whether or not we should check inUse
137 * @retval 0 no, we should not check inUse
138 * @retval 1 yes, we should check inUse
141 VShouldCheckInUse(int mode)
143 if (VCanUnsafeAttach()) {
146 if (programType == fileServer) {
149 if (VMustCheckoutVolume(mode)) {
150 /* assume we checked out the volume from the fileserver, so inUse
151 * should not be set */
157 #if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
159 * acquire a non-blocking disk lock for a particular volume id.
161 * @param[in] volid the volume ID to lock
162 * @param[in] dp the partition on which 'volid' resides
163 * @param[in] locktype READ_LOCK or WRITE_LOCK
165 * @return operation status
166 * @retval 0 success, lock was obtained
167 * @retval EBUSY another process holds a conflicting lock
168 * @retval EIO error acquiring lock
170 * @note Use VLockVolumeNB instead, if possible; only use this directly if
171 * you are not dealing with 'Volume*'s and attached volumes and such
173 * @pre There must not be any other threads acquiring locks on the same volid
174 * and partition; the locks will not work correctly if two threads try to
175 * acquire locks for the same volume
178 VLockVolumeByIdNB(VolumeId volid, struct DiskPartition64 *dp, int locktype)
180 return VLockFileLock(&dp->volLockFile, volid, locktype, 1 /* nonblock */);
184 * release a lock acquired by VLockVolumeByIdNB.
186 * @param[in] volid the volume id to unlock
187 * @param[in] dp the partition on which 'volid' resides
189 * @pre volid was previously locked by VLockVolumeByIdNB
192 VUnlockVolumeById(VolumeId volid, struct DiskPartition64 *dp)
194 VLockFileUnlock(&dp->volLockFile, volid);
197 /***************************************************/
198 /* demand attach fs state machine routines */
199 /***************************************************/
202 * tells caller whether we need to keep volumes locked for the entire time we
203 * are using them, or if we can unlock volumes as soon as they are attached.
205 * @return whether we can unlock attached volumes or not
206 * @retval 1 yes, we can unlock attached volumes
207 * @retval 0 no, do not unlock volumes until we unattach them
210 VCanUnlockAttached(void)
212 switch(programType) {
221 * tells caller whether we need to lock a vol header with a write lock, a
222 * read lock, or if we do not need to lock it at all, when attaching.
224 * @param[in] mode volume attachment mode
225 * @param[in] writable 1 if the volume is writable, 0 if not
227 * @return how we need to lock the vol header
228 * @retval 0 do not lock the vol header at all
229 * @retval READ_LOCK lock the vol header with a read lock
230 * @retval WRITE_LOCK lock the vol header with a write lock
232 * @note DAFS only (non-DAFS uses partition locks)
235 VVolLockType(int mode, int writable)
237 switch (programType) {
250 /* volserver, vol utilies, etc */
271 opr_Assert(0 /* unknown checkout mode */);
276 #endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
278 #ifdef AFS_DEMAND_ATTACH_FS
281 * tells caller whether or not the volume is effectively salvaging.
283 * @param vp volume pointer
285 * @return whether volume is salvaging or not
286 * @retval 0 no, volume is not salvaging
287 * @retval 1 yes, volume is salvaging
289 * @note The volume may not actually be getting salvaged at the moment if
290 * this returns 1, but may have just been requested or scheduled to be
291 * salvaged. Callers should treat these cases as pretty much the same
292 * anyway, since we should not touch a volume that is busy salvaging or
293 * waiting to be salvaged.
296 VIsSalvaging(struct Volume *vp)
298 /* these tests are a bit redundant, but to be safe... */
299 switch(V_attachState(vp)) {
300 case VOL_STATE_SALVAGING:
301 case VOL_STATE_SALVAGE_REQ:
304 if (vp->salvage.requested || vp->salvage.scheduled) {
312 * tells caller whether or not the current state requires
313 * exclusive access without holding glock.
315 * @param state volume state enumeration
317 * @return whether volume state is a mutually exclusive state
318 * @retval 0 no, state is re-entrant
319 * @retval 1 yes, state is mutually exclusive
321 * @note DEMAND_ATTACH_FS only
324 VIsExclusiveState(VolState state)
327 case VOL_STATE_UPDATING:
328 case VOL_STATE_ATTACHING:
329 case VOL_STATE_GET_BITMAP:
330 case VOL_STATE_HDR_LOADING:
331 case VOL_STATE_HDR_ATTACHING:
332 case VOL_STATE_OFFLINING:
333 case VOL_STATE_DETACHING:
334 case VOL_STATE_SALVSYNC_REQ:
335 case VOL_STATE_VNODE_ALLOC:
336 case VOL_STATE_VNODE_GET:
337 case VOL_STATE_VNODE_CLOSE:
338 case VOL_STATE_VNODE_RELEASE:
339 case VOL_STATE_VLRU_ADD:
340 case VOL_STATE_SCANNING_RXCALLS:
348 * tell caller whether V_attachState is an error condition.
350 * @param state volume state enumeration
352 * @return whether volume state is in error state
353 * @retval 0 state is not an error state
354 * @retval 1 state is an error state
356 * @note DEMAND_ATTACH_FS only
359 VIsErrorState(VolState state)
362 case VOL_STATE_ERROR:
363 case VOL_STATE_SALVAGING:
364 case VOL_STATE_SALVAGE_REQ:
372 * tell caller whether V_attachState is an offline condition.
374 * @param state volume state enumeration
376 * @return whether volume state is in offline state
377 * @retval 0 state is not an offline state
378 * @retval 1 state is an offline state
380 * @note DEMAND_ATTACH_FS only
383 VIsOfflineState(VolState state)
386 case VOL_STATE_UNATTACHED:
387 case VOL_STATE_ERROR:
388 case VOL_STATE_SALVAGING:
389 case VOL_STATE_DELETED:
397 * tell caller whether V_attachState is valid.
399 * @param state volume state enumeration
401 * @return whether volume state is a mutually exclusive state
402 * @retval 0 no, state is not valid
403 * @retval 1 yes, state is a valid enumeration member
405 * @note DEMAND_ATTACH_FS only
407 * @note do we really want to treat VOL_STATE_FREED as valid?
410 VIsValidState(VolState state)
413 (state < VOL_STATE_COUNT)) {
420 * increment volume-package internal refcount.
422 * @param vp volume object pointer
424 * @internal volume package internal use only
426 * @pre VOL_LOCK must be held
428 * @post volume waiters refcount is incremented
430 * @see VCancelReservation_r
432 * @note DEMAND_ATTACH_FS only
435 VCreateReservation_r(Volume * vp)
441 * wait for the volume to change states.
443 * @param vp volume object pointer
445 * @pre VOL_LOCK held; ref held on volume
447 * @post VOL_LOCK held; volume state has changed from previous value
449 * @note DEMAND_ATTACH_FS only
452 VWaitStateChange_r(Volume * vp)
454 VolState state_save = V_attachState(vp);
456 opr_Assert(vp->nWaiters || vp->nUsers);
458 VOL_CV_WAIT(&V_attachCV(vp));
459 } while (V_attachState(vp) == state_save);
460 opr_Assert(V_attachState(vp) != VOL_STATE_FREED);
464 * wait for the volume to change states within a certain amount of time
466 * @param[in] vp volume object pointer
467 * @param[in] ts deadline (absolute time) or NULL to wait forever
469 * @pre VOL_LOCK held; ref held on volume
470 * @post VOL_LOCK held; volume state has changed and/or it is after the time
473 * @note DEMAND_ATTACH_FS only
474 * @note if ts is NULL, this is identical to VWaitStateChange_r
477 VTimedWaitStateChange_r(Volume * vp, const struct timespec *ts, int *atimedout)
487 VWaitStateChange_r(vp);
491 state_save = V_attachState(vp);
493 assert(vp->nWaiters || vp->nUsers);
495 VOL_CV_TIMEDWAIT(&V_attachCV(vp), ts, &timeout);
496 } while (V_attachState(vp) == state_save && !timeout);
497 assert(V_attachState(vp) != VOL_STATE_FREED);
499 if (atimedout && timeout) {
505 * wait for blocking ops to end.
507 * @pre VOL_LOCK held; ref held on volume
509 * @post VOL_LOCK held; volume not in exclusive state
511 * @param vp volume object pointer
513 * @note DEMAND_ATTACH_FS only
516 VWaitExclusiveState_r(Volume * vp)
518 opr_Assert(vp->nWaiters || vp->nUsers);
519 while (VIsExclusiveState(V_attachState(vp))) {
520 VOL_CV_WAIT(&V_attachCV(vp));
522 opr_Assert(V_attachState(vp) != VOL_STATE_FREED);
526 * change state, and notify other threads,
527 * return previous state to caller.
529 * @param vp pointer to volume object
530 * @param new_state new volume state value
533 * @post volume state changed; stats updated
535 * @return previous volume state
537 * @note DEMAND_ATTACH_FS only
539 static_inline VolState
540 VChangeState_r(Volume * vp, VolState new_state)
542 VolState old_state = V_attachState(vp);
544 /* XXX profiling need to make sure these counters
545 * don't kill performance... */
546 VStats.state_levels[old_state]--;
547 VStats.state_levels[new_state]++;
549 V_attachState(vp) = new_state;
550 CV_BROADCAST(&V_attachCV(vp));
554 #endif /* AFS_DEMAND_ATTACH_FS */
556 #define VENUMCASE(en) \
560 * translate a ProgramType code to a string.
562 * @param[in] type ProgramType numeric code
564 * @return a human-readable string for that program type
565 * @retval "**UNKNOWN**" an unknown ProgramType was given
568 VPTypeToString(ProgramType type)
571 VENUMCASE(fileServer);
572 VENUMCASE(volumeUtility);
574 VENUMCASE(salvageServer);
575 VENUMCASE(debugUtility);
576 VENUMCASE(volumeServer);
577 VENUMCASE(volumeSalvager);
579 return "**UNKNOWN**";
585 #endif /* _AFS_VOL_VOLUME_INLINE_H */