Import Upstream version 1.8.5
[hcoop/debian/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 */