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