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 = opr_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
132 * or attaching for only reading (V_READONLY).
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)) {
151 * Before VShouldCheckInUse() was called, the caller checked out the
152 * volume from the fileserver. The volume may not be in use by the
153 * fileserver, or another program, at this point. The caller should
154 * verify by checking inUse is not set, otherwise the volume state
157 * However, an exception is made for the V_READONLY attach mode. The
158 * volume may still be in use by the fileserver when a caller has
159 * checked out the volume from the fileserver with the V_READONLY
160 * attach mode, and so it is not an error for the inUse field to be set
161 * at this point. The caller should not check the inUse and may
162 * not change any volume state.
164 if (mode == V_READONLY) {
165 return 0; /* allowed to be inUse; do not check */
167 return 1; /* may not be inUse; check */
172 #if defined(AFS_DEMAND_ATTACH_FS) || defined(AFS_DEMAND_ATTACH_UTIL)
174 * acquire a non-blocking disk lock for a particular volume id.
176 * @param[in] volid the volume ID to lock
177 * @param[in] dp the partition on which 'volid' resides
178 * @param[in] locktype READ_LOCK or WRITE_LOCK
180 * @return operation status
181 * @retval 0 success, lock was obtained
182 * @retval EBUSY another process holds a conflicting lock
183 * @retval EIO error acquiring lock
185 * @note Use VLockVolumeNB instead, if possible; only use this directly if
186 * you are not dealing with 'Volume*'s and attached volumes and such
188 * @pre There must not be any other threads acquiring locks on the same volid
189 * and partition; the locks will not work correctly if two threads try to
190 * acquire locks for the same volume
193 VLockVolumeByIdNB(VolumeId volid, struct DiskPartition64 *dp, int locktype)
195 return VLockFileLock(&dp->volLockFile, volid, locktype, 1 /* nonblock */);
199 * release a lock acquired by VLockVolumeByIdNB.
201 * @param[in] volid the volume id to unlock
202 * @param[in] dp the partition on which 'volid' resides
204 * @pre volid was previously locked by VLockVolumeByIdNB
207 VUnlockVolumeById(VolumeId volid, struct DiskPartition64 *dp)
209 VLockFileUnlock(&dp->volLockFile, volid);
212 /***************************************************/
213 /* demand attach fs state machine routines */
214 /***************************************************/
217 * tells caller whether we need to keep volumes locked for the entire time we
218 * are using them, or if we can unlock volumes as soon as they are attached.
220 * @return whether we can unlock attached volumes or not
221 * @retval 1 yes, we can unlock attached volumes
222 * @retval 0 no, do not unlock volumes until we unattach them
225 VCanUnlockAttached(void)
227 switch(programType) {
236 * tells caller whether we need to lock a vol header with a write lock, a
237 * read lock, or if we do not need to lock it at all, when attaching.
239 * @param[in] mode volume attachment mode
240 * @param[in] writable 1 if the volume is writable, 0 if not
242 * @return how we need to lock the vol header
243 * @retval 0 do not lock the vol header at all
244 * @retval READ_LOCK lock the vol header with a read lock
245 * @retval WRITE_LOCK lock the vol header with a write lock
247 * @note DAFS only (non-DAFS uses partition locks)
250 VVolLockType(int mode, int writable)
252 switch (programType) {
265 /* volserver, vol utilies, etc */
286 opr_Assert(0 /* unknown checkout mode */);
291 #endif /* AFS_DEMAND_ATTACH_FS || AFS_DEMAND_ATTACH_UTIL */
293 #ifdef AFS_DEMAND_ATTACH_FS
296 * tells caller whether or not the volume is effectively salvaging.
298 * @param vp volume pointer
300 * @return whether volume is salvaging or not
301 * @retval 0 no, volume is not salvaging
302 * @retval 1 yes, volume is salvaging
304 * @note The volume may not actually be getting salvaged at the moment if
305 * this returns 1, but may have just been requested or scheduled to be
306 * salvaged. Callers should treat these cases as pretty much the same
307 * anyway, since we should not touch a volume that is busy salvaging or
308 * waiting to be salvaged.
311 VIsSalvaging(struct Volume *vp)
313 /* these tests are a bit redundant, but to be safe... */
314 switch(V_attachState(vp)) {
315 case VOL_STATE_SALVAGING:
316 case VOL_STATE_SALVAGE_REQ:
319 if (vp->salvage.requested || vp->salvage.scheduled) {
327 * tells caller whether or not the current state requires
328 * exclusive access without holding glock.
330 * @param state volume state enumeration
332 * @return whether volume state is a mutually exclusive state
333 * @retval 0 no, state is re-entrant
334 * @retval 1 yes, state is mutually exclusive
336 * @note DEMAND_ATTACH_FS only
339 VIsExclusiveState(VolState state)
342 case VOL_STATE_UPDATING:
343 case VOL_STATE_ATTACHING:
344 case VOL_STATE_GET_BITMAP:
345 case VOL_STATE_HDR_LOADING:
346 case VOL_STATE_HDR_ATTACHING:
347 case VOL_STATE_OFFLINING:
348 case VOL_STATE_DETACHING:
349 case VOL_STATE_SALVSYNC_REQ:
350 case VOL_STATE_VNODE_ALLOC:
351 case VOL_STATE_VNODE_GET:
352 case VOL_STATE_VNODE_CLOSE:
353 case VOL_STATE_VNODE_RELEASE:
354 case VOL_STATE_VLRU_ADD:
355 case VOL_STATE_SCANNING_RXCALLS:
363 * tell caller whether V_attachState is an error condition.
365 * @param state volume state enumeration
367 * @return whether volume state is in error state
368 * @retval 0 state is not an error state
369 * @retval 1 state is an error state
371 * @note DEMAND_ATTACH_FS only
374 VIsErrorState(VolState state)
377 case VOL_STATE_ERROR:
378 case VOL_STATE_SALVAGING:
379 case VOL_STATE_SALVAGE_REQ:
387 * tell caller whether V_attachState is an offline condition.
389 * @param state volume state enumeration
391 * @return whether volume state is in offline state
392 * @retval 0 state is not an offline state
393 * @retval 1 state is an offline state
395 * @note DEMAND_ATTACH_FS only
398 VIsOfflineState(VolState state)
401 case VOL_STATE_UNATTACHED:
402 case VOL_STATE_ERROR:
403 case VOL_STATE_SALVAGING:
404 case VOL_STATE_DELETED:
412 * tell caller whether V_attachState is valid.
414 * @param state volume state enumeration
416 * @return whether volume state is a mutually exclusive state
417 * @retval 0 no, state is not valid
418 * @retval 1 yes, state is a valid enumeration member
420 * @note DEMAND_ATTACH_FS only
422 * @note do we really want to treat VOL_STATE_FREED as valid?
425 VIsValidState(VolState state)
427 if (((int) state >= 0) &&
428 (state < VOL_STATE_COUNT)) {
435 * increment volume-package internal refcount.
437 * @param vp volume object pointer
439 * @internal volume package internal use only
441 * @pre VOL_LOCK must be held
443 * @post volume waiters refcount is incremented
445 * @see VCancelReservation_r
447 * @note DEMAND_ATTACH_FS only
450 VCreateReservation_r(Volume * vp)
456 * wait for the volume to change states.
458 * @param vp volume object pointer
460 * @pre VOL_LOCK held; ref held on volume
462 * @post VOL_LOCK held; volume state has changed from previous value
464 * @note DEMAND_ATTACH_FS only
467 VWaitStateChange_r(Volume * vp)
469 VolState state_save = V_attachState(vp);
471 opr_Assert(vp->nWaiters || vp->nUsers);
473 VOL_CV_WAIT(&V_attachCV(vp));
474 } while (V_attachState(vp) == state_save);
475 opr_Assert(V_attachState(vp) != VOL_STATE_FREED);
479 * wait for the volume to change states within a certain amount of time
481 * @param[in] vp volume object pointer
482 * @param[in] ts deadline (absolute time) or NULL to wait forever
484 * @pre VOL_LOCK held; ref held on volume
485 * @post VOL_LOCK held; volume state has changed and/or it is after the time
488 * @note DEMAND_ATTACH_FS only
489 * @note if ts is NULL, this is identical to VWaitStateChange_r
492 VTimedWaitStateChange_r(Volume * vp, const struct timespec *ts, int *atimedout)
502 VWaitStateChange_r(vp);
506 state_save = V_attachState(vp);
508 opr_Assert(vp->nWaiters || vp->nUsers);
510 VOL_CV_TIMEDWAIT(&V_attachCV(vp), ts, &timeout);
511 } while (V_attachState(vp) == state_save && !timeout);
512 opr_Assert(V_attachState(vp) != VOL_STATE_FREED);
514 if (atimedout && timeout) {
520 * wait for blocking ops to end.
522 * @pre VOL_LOCK held; ref held on volume
524 * @post VOL_LOCK held; volume not in exclusive state
526 * @param vp volume object pointer
528 * @note DEMAND_ATTACH_FS only
531 VWaitExclusiveState_r(Volume * vp)
533 opr_Assert(vp->nWaiters || vp->nUsers);
534 while (VIsExclusiveState(V_attachState(vp))) {
535 VOL_CV_WAIT(&V_attachCV(vp));
537 opr_Assert(V_attachState(vp) != VOL_STATE_FREED);
541 * change state, and notify other threads,
542 * return previous state to caller.
544 * @param vp pointer to volume object
545 * @param new_state new volume state value
548 * @post volume state changed; stats updated
550 * @return previous volume state
552 * @note DEMAND_ATTACH_FS only
554 static_inline VolState
555 VChangeState_r(Volume * vp, VolState new_state)
557 VolState old_state = V_attachState(vp);
559 /* XXX profiling need to make sure these counters
560 * don't kill performance... */
561 VStats.state_levels[old_state]--;
562 VStats.state_levels[new_state]++;
564 V_attachState(vp) = new_state;
565 opr_cv_broadcast(&V_attachCV(vp));
569 #endif /* AFS_DEMAND_ATTACH_FS */
571 #define VENUMCASE(en) \
575 * translate a ProgramType code to a string.
577 * @param[in] type ProgramType numeric code
579 * @return a human-readable string for that program type
580 * @retval "**UNKNOWN**" an unknown ProgramType was given
583 VPTypeToString(ProgramType type)
586 VENUMCASE(fileServer);
587 VENUMCASE(volumeUtility);
589 VENUMCASE(salvageServer);
590 VENUMCASE(debugUtility);
591 VENUMCASE(volumeServer);
592 VENUMCASE(volumeSalvager);
594 return "**UNKNOWN**";
600 #endif /* _AFS_VOL_VOLUME_INLINE_H */