0ef7f8182e0f064fea9ef47f0c804b58e166c6be
[openafs.git] / src / vol / volume.c
1 /*
2  * Copyright 2000, International Business Machines Corporation 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  * Portions Copyright (c) 2005-2008 Sine Nomine Associates
10  */
11
12 /* 1/1/89: NB:  this stuff is all going to be replaced.  Don't take it too seriously */
13 /*
14
15         System:         VICE-TWO
16         Module:         volume.c
17         Institution:    The Information Technology Center, Carnegie-Mellon University
18
19  */
20
21 #include <afsconfig.h>
22 #include <afs/param.h>
23
24 #include <roken.h>
25 #include <afs/opr.h>
26
27 #include <ctype.h>
28 #include <stddef.h>
29
30 #ifdef HAVE_SYS_FILE_H
31 #include <sys/file.h>
32 #endif
33
34 #include <rx/xdr.h>
35 #include <afs/afsint.h>
36
37 #ifndef AFS_NT40_ENV
38 #if !defined(AFS_SGI_ENV)
39 #ifdef  AFS_OSF_ENV
40 #include <ufs/fs.h>
41 #else /* AFS_OSF_ENV */
42 #ifdef AFS_VFSINCL_ENV
43 #define VFS
44 #ifdef  AFS_SUN5_ENV
45 #include <sys/fs/ufs_fs.h>
46 #else
47 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
48 #include <ufs/ufs/dinode.h>
49 #include <ufs/ffs/fs.h>
50 #else
51 #include <ufs/fs.h>
52 #endif
53 #endif
54 #else /* AFS_VFSINCL_ENV */
55 #if !defined(AFS_AIX_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV) && !defined(AFS_DARWIN_ENV)
56 #include <sys/fs.h>
57 #endif
58 #endif /* AFS_VFSINCL_ENV */
59 #endif /* AFS_OSF_ENV */
60 #endif /* AFS_SGI_ENV */
61 #endif /* !AFS_NT40_ENV */
62
63 #ifdef  AFS_AIX_ENV
64 #include <sys/vfs.h>
65 #else
66 #ifdef  AFS_HPUX_ENV
67 #include <mntent.h>
68 #else
69 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
70 #ifdef  AFS_SUN5_ENV
71 #include <sys/mnttab.h>
72 #include <sys/mntent.h>
73 #else
74 #include <mntent.h>
75 #endif
76 #else
77 #ifndef AFS_NT40_ENV
78 #if defined(AFS_SGI_ENV)
79 #include <mntent.h>
80 #else
81 #ifndef AFS_LINUX20_ENV
82 #include <fstab.h>              /* Need to find in libc 5, present in libc 6 */
83 #endif
84 #endif
85 #endif /* AFS_SGI_ENV */
86 #endif
87 #endif /* AFS_HPUX_ENV */
88 #endif
89
90 #include "nfs.h"
91 #include <afs/errors.h>
92 #include "lock.h"
93 #include "lwp.h"
94 #include <afs/afssyscalls.h>
95 #include "ihandle.h"
96 #include <afs/afsutil.h>
97 #include "daemon_com.h"
98 #include "fssync.h"
99 #include "salvsync.h"
100 #include "vnode.h"
101 #include "volume.h"
102 #include "partition.h"
103 #include "volume_inline.h"
104 #include "common.h"
105 #include "vutils.h"
106 #include <afs/dir.h>
107
108 #ifdef AFS_PTHREAD_ENV
109 pthread_mutex_t vol_glock_mutex;
110 pthread_mutex_t vol_trans_mutex;
111 pthread_cond_t vol_put_volume_cond;
112 pthread_cond_t vol_sleep_cond;
113 pthread_cond_t vol_init_attach_cond;
114 pthread_cond_t vol_vinit_cond;
115 int vol_attach_threads = 1;
116 #endif /* AFS_PTHREAD_ENV */
117
118 /* start-time configurable I/O parameters */
119 ih_init_params vol_io_params;
120
121 #ifdef AFS_DEMAND_ATTACH_FS
122 pthread_mutex_t vol_salvsync_mutex;
123
124 /*
125  * Set this to 1 to disallow SALVSYNC communication in all threads; used
126  * during shutdown, since the salvageserver may have gone away.
127  */
128 static volatile sig_atomic_t vol_disallow_salvsync = 0;
129 #endif /* AFS_DEMAND_ATTACH_FS */
130
131 /**
132  * has VShutdown_r been called / is VShutdown_r running?
133  */
134 static int vol_shutting_down = 0;
135
136 #ifdef  AFS_OSF_ENV
137 extern void *calloc(), *realloc();
138 #endif
139
140 /* Forward declarations */
141 static Volume *attach2(Error * ec, VolId volumeId, char *path,
142                        struct DiskPartition64 *partp, Volume * vp,
143                        int isbusy, int mode, int *acheckedOut);
144 static void ReallyFreeVolume(Volume * vp);
145 #ifdef AFS_DEMAND_ATTACH_FS
146 static void FreeVolume(Volume * vp);
147 #else /* !AFS_DEMAND_ATTACH_FS */
148 #define FreeVolume(vp) ReallyFreeVolume(vp)
149 static void VScanUpdateList(void);
150 #endif /* !AFS_DEMAND_ATTACH_FS */
151 static void VInitVolumeHeaderCache(afs_uint32 howMany);
152 static int GetVolumeHeader(Volume * vp);
153 static void ReleaseVolumeHeader(struct volHeader *hd);
154 static void FreeVolumeHeader(Volume * vp);
155 static void AddVolumeToHashTable(Volume * vp, int hashid);
156 static void DeleteVolumeFromHashTable(Volume * vp);
157 #if 0
158 static int VHold(Volume * vp);
159 #endif
160 static int VHold_r(Volume * vp);
161 static void VGetBitmap_r(Error * ec, Volume * vp, VnodeClass class);
162 static void VReleaseVolumeHandles_r(Volume * vp);
163 static void VCloseVolumeHandles_r(Volume * vp);
164 static void LoadVolumeHeader(Error * ec, Volume * vp);
165 static int VCheckOffline(Volume * vp);
166 static int VCheckDetach(Volume * vp);
167 static Volume * GetVolume(Error * ec, Error * client_ec, VolId volumeId,
168                           Volume * hint, const struct timespec *ts);
169
170 int LogLevel;                   /* Vice loglevel--not defined as extern so that it will be
171                                  * defined when not linked with vice, XXXX */
172 ProgramType programType;        /* The type of program using the package */
173 static VolumePackageOptions vol_opts;
174
175 /* extended volume package statistics */
176 VolPkgStats VStats;
177
178 #ifdef VOL_LOCK_DEBUG
179 pthread_t vol_glock_holder = 0;
180 #endif
181
182
183 /* this parameter needs to be tunable at runtime.
184  * 128 was really inadequate for largish servers -- at 16384 volumes this
185  * puts average chain length at 128, thus an average 65 deref's to find a volptr.
186  * talk about bad spatial locality...
187  *
188  * an AVL or splay tree might work a lot better, but we'll just increase
189  * the default hash table size for now
190  */
191 #define DEFAULT_VOLUME_HASH_SIZE 256   /* Must be a power of 2!! */
192 #define DEFAULT_VOLUME_HASH_MASK (DEFAULT_VOLUME_HASH_SIZE-1)
193 #define VOLUME_HASH(volumeId) (volumeId&(VolumeHashTable.Mask))
194
195 /*
196  * turn volume hash chains into partially ordered lists.
197  * when the threshold is exceeded between two adjacent elements,
198  * perform a chain rebalancing operation.
199  *
200  * keep the threshold high in order to keep cache line invalidates
201  * low "enough" on SMPs
202  */
203 #define VOLUME_HASH_REORDER_THRESHOLD 200
204
205 /*
206  * when possible, don't just reorder single elements, but reorder
207  * entire chains of elements at once.  a chain of elements that
208  * exceed the element previous to the pivot by at least CHAIN_THRESH
209  * accesses are moved in front of the chain whose elements have at
210  * least CHAIN_THRESH less accesses than the pivot element
211  */
212 #define VOLUME_HASH_REORDER_CHAIN_THRESH (VOLUME_HASH_REORDER_THRESHOLD / 2)
213
214 #include "rx/rx_queue.h"
215
216
217 VolumeHashTable_t VolumeHashTable = {
218     DEFAULT_VOLUME_HASH_SIZE,
219     DEFAULT_VOLUME_HASH_MASK,
220     NULL
221 };
222
223
224 static void VInitVolumeHash(void);
225
226
227 #ifndef AFS_HAVE_FFS
228 /* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
229 ffs(x)
230 {
231     afs_int32 ffs_i;
232     afs_int32 ffs_tmp = x;
233     if (ffs_tmp == 0)
234         return (-1);
235     else
236         for (ffs_i = 1;; ffs_i++) {
237             if (ffs_tmp & 1)
238                 return (ffs_i);
239             else
240                 ffs_tmp >>= 1;
241         }
242 }
243 #endif /* !AFS_HAVE_FFS */
244
245 #ifdef AFS_PTHREAD_ENV
246 /**
247  * disk partition queue element
248  */
249 typedef struct diskpartition_queue_t {
250     struct rx_queue queue;             /**< queue header */
251     struct DiskPartition64 *diskP;     /**< disk partition table entry */
252 } diskpartition_queue_t;
253
254 #ifndef AFS_DEMAND_ATTACH_FS
255
256 typedef struct vinitvolumepackage_thread_t {
257     struct rx_queue queue;
258     pthread_cond_t thread_done_cv;
259     int n_threads_complete;
260 } vinitvolumepackage_thread_t;
261 static void * VInitVolumePackageThread(void * args);
262
263 #else  /* !AFS_DEMAND_ATTTACH_FS */
264 #define VINIT_BATCH_MAX_SIZE 512
265
266 /**
267  * disk partition work queue
268  */
269 struct partition_queue {
270     struct rx_queue head;              /**< diskpartition_queue_t queue */
271     pthread_mutex_t mutex;
272     pthread_cond_t cv;
273 };
274
275 /**
276  * volumes parameters for preattach
277  */
278 struct volume_init_batch {
279     struct rx_queue queue;               /**< queue header */
280     int thread;                          /**< posting worker thread */
281     int last;                            /**< indicates thread is done */
282     int size;                            /**< number of volume ids in batch */
283     Volume *batch[VINIT_BATCH_MAX_SIZE]; /**< volumes ids to preattach */
284 };
285
286 /**
287  * volume parameters work queue
288  */
289 struct volume_init_queue {
290     struct rx_queue head;                /**< volume_init_batch queue */
291     pthread_mutex_t mutex;
292     pthread_cond_t cv;
293 };
294
295 /**
296  * volume init worker thread parameters
297  */
298 struct vinitvolumepackage_thread_param {
299     int nthreads;                        /**< total number of worker threads */
300     int thread;                          /**< thread number for this worker thread */
301     struct partition_queue *pq;          /**< queue partitions to scan */
302     struct volume_init_queue *vq;        /**< queue of volume to preattach */
303 };
304
305 static void *VInitVolumePackageThread(void *args);
306 static struct DiskPartition64 *VInitNextPartition(struct partition_queue *pq);
307 static VolId VInitNextVolumeId(DIR *dirp);
308 static int VInitPreAttachVolumes(int nthreads, struct volume_init_queue *vq);
309
310 #endif /* !AFS_DEMAND_ATTACH_FS */
311 #endif /* AFS_PTHREAD_ENV */
312
313 #ifndef AFS_DEMAND_ATTACH_FS
314 static int VAttachVolumesByPartition(struct DiskPartition64 *diskP,
315                                      int * nAttached, int * nUnattached);
316 #endif /* AFS_DEMAND_ATTACH_FS */
317
318
319 #ifdef AFS_DEMAND_ATTACH_FS
320 /* demand attach fileserver extensions */
321
322 /* XXX
323  * in the future we will support serialization of VLRU state into the fs_state
324  * disk dumps
325  *
326  * these structures are the beginning of that effort
327  */
328 struct VLRU_DiskHeader {
329     struct versionStamp stamp;            /* magic and structure version number */
330     afs_uint32 mtime;                     /* time of dump to disk */
331     afs_uint32 num_records;               /* number of VLRU_DiskEntry records */
332 };
333
334 struct VLRU_DiskEntry {
335     afs_uint32 vid;                       /* volume ID */
336     afs_uint32 idx;                       /* generation */
337     afs_uint32 last_get;                  /* timestamp of last get */
338 };
339
340 struct VLRU_StartupQueue {
341     struct VLRU_DiskEntry * entry;
342     int num_entries;
343     int next_idx;
344 };
345
346 typedef struct vshutdown_thread_t {
347     struct rx_queue q;
348     pthread_mutex_t lock;
349     pthread_cond_t cv;
350     pthread_cond_t master_cv;
351     int n_threads;
352     int n_threads_complete;
353     int vol_remaining;
354     int schedule_version;
355     int pass;
356     byte n_parts;
357     byte n_parts_done_pass;
358     byte part_thread_target[VOLMAXPARTS+1];
359     byte part_done_pass[VOLMAXPARTS+1];
360     struct rx_queue * part_pass_head[VOLMAXPARTS+1];
361     int stats[4][VOLMAXPARTS+1];
362 } vshutdown_thread_t;
363 static void * VShutdownThread(void * args);
364
365
366 static Volume * VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode);
367 static int VCheckFree(Volume * vp);
368
369 /* VByP List */
370 static void AddVolumeToVByPList_r(Volume * vp);
371 static void DeleteVolumeFromVByPList_r(Volume * vp);
372 static void VVByPListBeginExclusive_r(struct DiskPartition64 * dp);
373 static void VVByPListEndExclusive_r(struct DiskPartition64 * dp);
374 static void VVByPListWait_r(struct DiskPartition64 * dp);
375
376 /* online salvager */
377 typedef enum {
378     VCHECK_SALVAGE_OK = 0,         /**< no pending salvage */
379     VCHECK_SALVAGE_SCHEDULED = 1,  /**< salvage has been scheduled */
380     VCHECK_SALVAGE_ASYNC = 2,      /**< salvage being scheduled */
381     VCHECK_SALVAGE_DENIED = 3,     /**< salvage not scheduled; denied */
382     VCHECK_SALVAGE_FAIL = 4        /**< salvage not scheduled; failed */
383 } vsalvage_check;
384 static int VCheckSalvage(Volume * vp);
385 #if defined(SALVSYNC_BUILD_CLIENT) || defined(FSSYNC_BUILD_CLIENT)
386 static int VScheduleSalvage_r(Volume * vp);
387 #endif
388
389 /* Volume hash table */
390 static void VReorderHash_r(VolumeHashChainHead * head, Volume * pp, Volume * vp);
391 static void VHashBeginExclusive_r(VolumeHashChainHead * head);
392 static void VHashEndExclusive_r(VolumeHashChainHead * head);
393 static void VHashWait_r(VolumeHashChainHead * head);
394
395 /* shutdown */
396 static int ShutdownVByPForPass_r(struct DiskPartition64 * dp, int pass);
397 static int ShutdownVolumeWalk_r(struct DiskPartition64 * dp, int pass,
398                                 struct rx_queue ** idx);
399 static void ShutdownController(vshutdown_thread_t * params);
400 static void ShutdownCreateSchedule(vshutdown_thread_t * params);
401
402 /* VLRU */
403 static void VLRU_ComputeConstants(void);
404 static void VInitVLRU(void);
405 static void VLRU_Init_Node_r(Volume * vp);
406 static void VLRU_Add_r(Volume * vp);
407 static void VLRU_Delete_r(Volume * vp);
408 static void VLRU_UpdateAccess_r(Volume * vp);
409 static void * VLRU_ScannerThread(void * args);
410 static void VLRU_Scan_r(int idx);
411 static void VLRU_Promote_r(int idx);
412 static void VLRU_Demote_r(int idx);
413 static void VLRU_SwitchQueues(Volume * vp, int new_idx, int append);
414
415 /* soft detach */
416 static int VCheckSoftDetach(Volume * vp, afs_uint32 thresh);
417 static int VCheckSoftDetachCandidate(Volume * vp, afs_uint32 thresh);
418 static int VSoftDetachVolume_r(Volume * vp, afs_uint32 thresh);
419
420
421 pthread_key_t VThread_key;
422 VThreadOptions_t VThread_defaults = {
423     0                           /**< allow salvsync */
424 };
425 #endif /* AFS_DEMAND_ATTACH_FS */
426
427
428 struct Lock vol_listLock;       /* Lock obtained when listing volumes:
429                                  * prevents a volume from being missed
430                                  * if the volume is attached during a
431                                  * list volumes */
432
433
434 /* Common message used when the volume goes off line */
435 char *VSalvageMessage =
436     "Files in this volume are currently unavailable; call operations";
437
438 int VInit;                      /* 0 - uninitialized,
439                                  * 1 - initialized but not all volumes have been attached,
440                                  * 2 - initialized and all volumes have been attached,
441                                  * 3 - initialized, all volumes have been attached, and
442                                  * VConnectFS() has completed. */
443
444 static int vinit_attach_abort = 0;
445
446 bit32 VolumeCacheCheck;         /* Incremented everytime a volume goes on line--
447                                  * used to stamp volume headers and in-core
448                                  * vnodes.  When the volume goes on-line the
449                                  * vnode will be invalidated
450                                  * access only with VOL_LOCK held */
451
452
453
454
455 /***************************************************/
456 /* Startup routines                                */
457 /***************************************************/
458
459 #if defined(FAST_RESTART) && defined(AFS_DEMAND_ATTACH_FS)
460 # error FAST_RESTART and DAFS are incompatible. For the DAFS equivalent \
461         of FAST_RESTART, use the -unsafe-nosalvage fileserver argument
462 #endif
463
464 /**
465  * assign default values to a VolumePackageOptions struct.
466  *
467  * Always call this on a VolumePackageOptions struct first, then set any
468  * specific options you want, then call VInitVolumePackage2.
469  *
470  * @param[in]  pt   caller's program type
471  * @param[out] opts volume package options
472  */
473 void
474 VOptDefaults(ProgramType pt, VolumePackageOptions *opts)
475 {
476     opts->nLargeVnodes = opts->nSmallVnodes = 5;
477     opts->volcache = 0;
478
479     opts->canScheduleSalvage = 0;
480     opts->canUseFSSYNC = 0;
481     opts->canUseSALVSYNC = 0;
482
483     opts->interrupt_rxcall = NULL;
484     opts->offline_timeout = -1;
485     opts->offline_shutdown_timeout = -1;
486     opts->usage_threshold = 128;
487     opts->usage_rate_limit = 5;
488
489 #ifdef FAST_RESTART
490     opts->unsafe_attach = 1;
491 #else /* !FAST_RESTART */
492     opts->unsafe_attach = 0;
493 #endif /* !FAST_RESTART */
494
495     switch (pt) {
496     case fileServer:
497         opts->canScheduleSalvage = 1;
498         opts->canUseSALVSYNC = 1;
499         break;
500
501     case salvageServer:
502         opts->canUseFSSYNC = 1;
503         break;
504
505     case volumeServer:
506         opts->nLargeVnodes = 0;
507         opts->nSmallVnodes = 0;
508
509         opts->canScheduleSalvage = 1;
510         opts->canUseFSSYNC = 1;
511         break;
512
513     default:
514         /* noop */
515         break;
516     }
517 }
518
519 /**
520  * Set VInit to a certain value, and signal waiters.
521  *
522  * @param[in] value  the value to set VInit to
523  *
524  * @pre VOL_LOCK held
525  */
526 static void
527 VSetVInit_r(int value)
528 {
529     VInit = value;
530     CV_BROADCAST(&vol_vinit_cond);
531 }
532
533 static_inline void
534 VLogOfflineTimeout(const char *type, afs_int32 timeout)
535 {
536     if (timeout < 0) {
537         return;
538     }
539     if (timeout == 0) {
540         Log("VInitVolumePackage: Interrupting clients accessing %s "
541             "immediately\n", type);
542     } else {
543         Log("VInitVolumePackage: Interrupting clients accessing %s "
544             "after %ld second%s\n", type, (long)timeout, timeout==1?"":"s");
545     }
546 }
547
548 int
549 VInitVolumePackage2(ProgramType pt, VolumePackageOptions * opts)
550 {
551     int errors = 0;             /* Number of errors while finding vice partitions. */
552
553     programType = pt;
554     vol_opts = *opts;
555
556 #ifndef AFS_PTHREAD_ENV
557     if (opts->offline_timeout != -1 || opts->offline_shutdown_timeout != -1) {
558         Log("VInitVolumePackage: offline_timeout and/or "
559             "offline_shutdown_timeout was specified, but the volume package "
560             "does not support these for LWP builds\n");
561         return -1;
562     }
563 #endif
564     VLogOfflineTimeout("volumes going offline", opts->offline_timeout);
565     VLogOfflineTimeout("volumes going offline during shutdown",
566                        opts->offline_shutdown_timeout);
567
568     memset(&VStats, 0, sizeof(VStats));
569     VStats.hdr_cache_size = 200;
570
571     VInitPartitionPackage();
572     VInitVolumeHash();
573 #ifdef AFS_DEMAND_ATTACH_FS
574     if (programType == fileServer) {
575         VInitVLRU();
576     } else {
577         VLRU_SetOptions(VLRU_SET_ENABLED, 0);
578     }
579     osi_Assert(pthread_key_create(&VThread_key, NULL) == 0);
580 #endif
581
582     MUTEX_INIT(&vol_glock_mutex, "vol glock", MUTEX_DEFAULT, 0);
583     MUTEX_INIT(&vol_trans_mutex, "vol trans", MUTEX_DEFAULT, 0);
584     CV_INIT(&vol_put_volume_cond, "vol put", CV_DEFAULT, 0);
585     CV_INIT(&vol_sleep_cond, "vol sleep", CV_DEFAULT, 0);
586     CV_INIT(&vol_init_attach_cond, "vol init attach", CV_DEFAULT, 0);
587     CV_INIT(&vol_vinit_cond, "vol init", CV_DEFAULT, 0);
588 #ifndef AFS_PTHREAD_ENV
589     IOMGR_Initialize();
590 #endif /* AFS_PTHREAD_ENV */
591     Lock_Init(&vol_listLock);
592
593     srandom(time(0));           /* For VGetVolumeInfo */
594
595 #ifdef AFS_DEMAND_ATTACH_FS
596     MUTEX_INIT(&vol_salvsync_mutex, "salvsync", MUTEX_DEFAULT, 0);
597 #endif /* AFS_DEMAND_ATTACH_FS */
598
599     /* Ok, we have done enough initialization that fileserver can
600      * start accepting calls, even though the volumes may not be
601      * available just yet.
602      */
603     VInit = 1;
604
605 #if defined(AFS_DEMAND_ATTACH_FS) && defined(SALVSYNC_BUILD_SERVER)
606     if (programType == salvageServer) {
607         SALVSYNC_salvInit();
608     }
609 #endif /* AFS_DEMAND_ATTACH_FS */
610 #ifdef FSSYNC_BUILD_SERVER
611     if (programType == fileServer) {
612         FSYNC_fsInit();
613     }
614 #endif
615 #if defined(AFS_DEMAND_ATTACH_FS) && defined(SALVSYNC_BUILD_CLIENT)
616     if (VCanUseSALVSYNC()) {
617         /* establish a connection to the salvager at this point */
618         osi_Assert(VConnectSALV() != 0);
619     }
620 #endif /* AFS_DEMAND_ATTACH_FS */
621
622     if (opts->volcache > VStats.hdr_cache_size)
623         VStats.hdr_cache_size = opts->volcache;
624     VInitVolumeHeaderCache(VStats.hdr_cache_size);
625
626     VInitVnodes(vLarge, opts->nLargeVnodes);
627     VInitVnodes(vSmall, opts->nSmallVnodes);
628
629
630     errors = VAttachPartitions();
631     if (errors)
632         return -1;
633
634     if (programType != fileServer) {
635         errors = VInitAttachVolumes(programType);
636         if (errors) {
637             return -1;
638         }
639     }
640
641 #ifdef FSSYNC_BUILD_CLIENT
642     if (VCanUseFSSYNC()) {
643         if (!VConnectFS()) {
644 #ifdef AFS_DEMAND_ATTACH_FS
645             if (programType == salvageServer) {
646                 Log("Unable to connect to file server; aborted\n");
647                 exit(1);
648             }
649 #endif /* AFS_DEMAND_ATTACH_FS */
650             Log("Unable to connect to file server; will retry at need\n");
651         }
652     }
653 #endif /* FSSYNC_BUILD_CLIENT */
654     return 0;
655 }
656
657
658 #if !defined(AFS_PTHREAD_ENV)
659 /**
660  * Attach volumes in vice partitions
661  *
662  * @param[in]  pt         calling program type
663  *
664  * @return 0
665  * @note This is the original, non-threaded version of attach parititions.
666  *
667  * @post VInit state is 2
668  */
669 int
670 VInitAttachVolumes(ProgramType pt)
671 {
672     osi_Assert(VInit==1);
673     if (pt == fileServer) {
674         struct DiskPartition64 *diskP;
675         /* Attach all the volumes in this partition */
676         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
677             int nAttached = 0, nUnattached = 0;
678             osi_Assert(VAttachVolumesByPartition(diskP, &nAttached, &nUnattached) == 0);
679         }
680     }
681     VOL_LOCK;
682     VSetVInit_r(2);                     /* Initialized, and all volumes have been attached */
683     LWP_NoYieldSignal(VInitAttachVolumes);
684     VOL_UNLOCK;
685     return 0;
686 }
687 #endif /* !AFS_PTHREAD_ENV */
688
689 #if defined(AFS_PTHREAD_ENV) && !defined(AFS_DEMAND_ATTACH_FS)
690 /**
691  * Attach volumes in vice partitions
692  *
693  * @param[in]  pt         calling program type
694  *
695  * @return 0
696  * @note Threaded version of attach parititions.
697  *
698  * @post VInit state is 2
699  */
700 int
701 VInitAttachVolumes(ProgramType pt)
702 {
703     osi_Assert(VInit==1);
704     if (pt == fileServer) {
705         struct DiskPartition64 *diskP;
706         struct vinitvolumepackage_thread_t params;
707         struct diskpartition_queue_t * dpq;
708         int i, threads, parts;
709         pthread_t tid;
710         pthread_attr_t attrs;
711
712         CV_INIT(&params.thread_done_cv, "thread done", CV_DEFAULT, 0);
713         queue_Init(&params);
714         params.n_threads_complete = 0;
715
716         /* create partition work queue */
717         for (parts=0, diskP = DiskPartitionList; diskP; diskP = diskP->next, parts++) {
718             dpq = malloc(sizeof(struct diskpartition_queue_t));
719             osi_Assert(dpq != NULL);
720             dpq->diskP = diskP;
721             queue_Append(&params,dpq);
722         }
723
724         threads = min(parts, vol_attach_threads);
725
726         if (threads > 1) {
727             /* spawn off a bunch of initialization threads */
728             osi_Assert(pthread_attr_init(&attrs) == 0);
729             osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
730
731             Log("VInitVolumePackage: beginning parallel fileserver startup\n");
732             Log("VInitVolumePackage: using %d threads to attach volumes on %d partitions\n",
733                 threads, parts);
734
735             VOL_LOCK;
736             for (i=0; i < threads; i++) {
737                 AFS_SIGSET_DECL;
738                 AFS_SIGSET_CLEAR();
739                 osi_Assert(pthread_create
740                        (&tid, &attrs, &VInitVolumePackageThread,
741                         &params) == 0);
742                 AFS_SIGSET_RESTORE();
743             }
744
745             while(params.n_threads_complete < threads) {
746                 VOL_CV_WAIT(&params.thread_done_cv);
747             }
748             VOL_UNLOCK;
749
750             osi_Assert(pthread_attr_destroy(&attrs) == 0);
751         } else {
752             /* if we're only going to run one init thread, don't bother creating
753              * another LWP */
754             Log("VInitVolumePackage: beginning single-threaded fileserver startup\n");
755             Log("VInitVolumePackage: using 1 thread to attach volumes on %d partition(s)\n",
756                 parts);
757
758             VInitVolumePackageThread(&params);
759         }
760
761         CV_DESTROY(&params.thread_done_cv);
762     }
763     VOL_LOCK;
764     VSetVInit_r(2);                     /* Initialized, and all volumes have been attached */
765     CV_BROADCAST(&vol_init_attach_cond);
766     VOL_UNLOCK;
767     return 0;
768 }
769
770 static void *
771 VInitVolumePackageThread(void * args) {
772
773     struct DiskPartition64 *diskP;
774     struct vinitvolumepackage_thread_t * params;
775     struct diskpartition_queue_t * dpq;
776
777     params = (vinitvolumepackage_thread_t *) args;
778
779
780     VOL_LOCK;
781     /* Attach all the volumes in this partition */
782     while (queue_IsNotEmpty(params)) {
783         int nAttached = 0, nUnattached = 0;
784
785         if (vinit_attach_abort) {
786             Log("Aborting initialization\n");
787             goto done;
788         }
789
790         dpq = queue_First(params,diskpartition_queue_t);
791         queue_Remove(dpq);
792         VOL_UNLOCK;
793         diskP = dpq->diskP;
794         free(dpq);
795
796         osi_Assert(VAttachVolumesByPartition(diskP, &nAttached, &nUnattached) == 0);
797
798         VOL_LOCK;
799     }
800
801 done:
802     params->n_threads_complete++;
803     CV_SIGNAL(&params->thread_done_cv);
804     VOL_UNLOCK;
805     return NULL;
806 }
807 #endif /* AFS_PTHREAD_ENV && !AFS_DEMAND_ATTACH_FS */
808
809 #if defined(AFS_DEMAND_ATTACH_FS)
810 /**
811  * Attach volumes in vice partitions
812  *
813  * @param[in]  pt         calling program type
814  *
815  * @return 0
816  * @note Threaded version of attach partitions.
817  *
818  * @post VInit state is 2
819  */
820 int
821 VInitAttachVolumes(ProgramType pt)
822 {
823     osi_Assert(VInit==1);
824     if (pt == fileServer) {
825
826         struct DiskPartition64 *diskP;
827         struct partition_queue pq;
828         struct volume_init_queue vq;
829
830         int i, threads, parts;
831         pthread_t tid;
832         pthread_attr_t attrs;
833
834         /* create partition work queue */
835         queue_Init(&pq);
836         CV_INIT(&(pq.cv), "partq", CV_DEFAULT, 0);
837         MUTEX_INIT(&(pq.mutex), "partq", MUTEX_DEFAULT, 0);
838         for (parts = 0, diskP = DiskPartitionList; diskP; diskP = diskP->next, parts++) {
839             struct diskpartition_queue_t *dp;
840             dp = malloc(sizeof(struct diskpartition_queue_t));
841             osi_Assert(dp != NULL);
842             dp->diskP = diskP;
843             queue_Append(&pq, dp);
844         }
845
846         /* number of worker threads; at least one, not to exceed the number of partitions */
847         threads = min(parts, vol_attach_threads);
848
849         /* create volume work queue */
850         queue_Init(&vq);
851         CV_INIT(&(vq.cv), "volq", CV_DEFAULT, 0);
852         MUTEX_INIT(&(vq.mutex), "volq", MUTEX_DEFAULT, 0);
853
854         osi_Assert(pthread_attr_init(&attrs) == 0);
855         osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
856
857         Log("VInitVolumePackage: beginning parallel fileserver startup\n");
858         Log("VInitVolumePackage: using %d threads to pre-attach volumes on %d partitions\n",
859                 threads, parts);
860
861         /* create threads to scan disk partitions. */
862         for (i=0; i < threads; i++) {
863             struct vinitvolumepackage_thread_param *params;
864             AFS_SIGSET_DECL;
865
866             params = malloc(sizeof(struct vinitvolumepackage_thread_param));
867             osi_Assert(params);
868             params->pq = &pq;
869             params->vq = &vq;
870             params->nthreads = threads;
871             params->thread = i+1;
872
873             AFS_SIGSET_CLEAR();
874             osi_Assert(pthread_create (&tid, &attrs, &VInitVolumePackageThread, (void*)params) == 0);
875             AFS_SIGSET_RESTORE();
876         }
877
878         VInitPreAttachVolumes(threads, &vq);
879
880         osi_Assert(pthread_attr_destroy(&attrs) == 0);
881         CV_DESTROY(&pq.cv);
882         MUTEX_DESTROY(&pq.mutex);
883         CV_DESTROY(&vq.cv);
884         MUTEX_DESTROY(&vq.mutex);
885     }
886
887     VOL_LOCK;
888     VSetVInit_r(2);                     /* Initialized, and all volumes have been attached */
889     CV_BROADCAST(&vol_init_attach_cond);
890     VOL_UNLOCK;
891
892     return 0;
893 }
894
895 /**
896  * Volume package initialization worker thread. Scan partitions for volume
897  * header files. Gather batches of volume ids and dispatch them to
898  * the main thread to be preattached.  The volume preattachement is done
899  * in the main thread to avoid global volume lock contention.
900  */
901 static void *
902 VInitVolumePackageThread(void *args)
903 {
904     struct vinitvolumepackage_thread_param *params;
905     struct DiskPartition64 *partition;
906     struct partition_queue *pq;
907     struct volume_init_queue *vq;
908     struct volume_init_batch *vb;
909
910     osi_Assert(args);
911     params = (struct vinitvolumepackage_thread_param *)args;
912     pq = params->pq;
913     vq = params->vq;
914     osi_Assert(pq);
915     osi_Assert(vq);
916
917     vb = malloc(sizeof(struct volume_init_batch));
918     osi_Assert(vb);
919     vb->thread = params->thread;
920     vb->last = 0;
921     vb->size = 0;
922
923     Log("Scanning partitions on thread %d of %d\n", params->thread, params->nthreads);
924     while((partition = VInitNextPartition(pq))) {
925         DIR *dirp;
926         VolId vid;
927
928         Log("Partition %s: pre-attaching volumes\n", partition->name);
929         dirp = opendir(VPartitionPath(partition));
930         if (!dirp) {
931             Log("opendir on Partition %s failed, errno=%d!\n", partition->name, errno);
932             continue;
933         }
934         while ((vid = VInitNextVolumeId(dirp))) {
935             Volume *vp = calloc(1, sizeof(Volume));
936             osi_Assert(vp);
937             vp->device = partition->device;
938             vp->partition = partition;
939             vp->hashid = vid;
940             queue_Init(&vp->vnode_list);
941             queue_Init(&vp->rx_call_list);
942             CV_INIT(&V_attachCV(vp), "partattach", CV_DEFAULT, 0);
943
944             vb->batch[vb->size++] = vp;
945             if (vb->size == VINIT_BATCH_MAX_SIZE) {
946                 MUTEX_ENTER(&vq->mutex);
947                 queue_Append(vq, vb);
948                 CV_BROADCAST(&vq->cv);
949                 MUTEX_EXIT(&vq->mutex);
950
951                 vb = malloc(sizeof(struct volume_init_batch));
952                 osi_Assert(vb);
953                 vb->thread = params->thread;
954                 vb->size = 0;
955                 vb->last = 0;
956             }
957         }
958         closedir(dirp);
959     }
960
961     vb->last = 1;
962     MUTEX_ENTER(&vq->mutex);
963     queue_Append(vq, vb);
964     CV_BROADCAST(&vq->cv);
965     MUTEX_EXIT(&vq->mutex);
966
967     Log("Partition scan thread %d of %d ended\n", params->thread, params->nthreads);
968     free(params);
969     return NULL;
970 }
971
972 /**
973  * Read next element from the pre-populated partition list.
974  */
975 static struct DiskPartition64*
976 VInitNextPartition(struct partition_queue *pq)
977 {
978     struct DiskPartition64 *partition;
979     struct diskpartition_queue_t *dp; /* queue element */
980
981     if (vinit_attach_abort) {
982         Log("Aborting volume preattach thread.\n");
983         return NULL;
984     }
985
986     /* get next partition to scan */
987     MUTEX_ENTER(&pq->mutex);
988     if (queue_IsEmpty(pq)) {
989         MUTEX_EXIT(&pq->mutex);
990         return NULL;
991     }
992     dp = queue_First(pq, diskpartition_queue_t);
993     queue_Remove(dp);
994     MUTEX_EXIT(&pq->mutex);
995
996     osi_Assert(dp);
997     osi_Assert(dp->diskP);
998
999     partition = dp->diskP;
1000     free(dp);
1001     return partition;
1002 }
1003
1004 /**
1005  * Find next volume id on the partition.
1006  */
1007 static VolId
1008 VInitNextVolumeId(DIR *dirp)
1009 {
1010     struct dirent *d;
1011     VolId vid = 0;
1012     char *ext;
1013
1014     while((d = readdir(dirp))) {
1015         if (vinit_attach_abort) {
1016             Log("Aborting volume preattach thread.\n");
1017             break;
1018         }
1019         ext = strrchr(d->d_name, '.');
1020         if (d->d_name[0] == 'V' && ext && strcmp(ext, VHDREXT) == 0) {
1021             vid = VolumeNumber(d->d_name);
1022             if (vid) {
1023                break;
1024             }
1025             Log("Warning: bogus volume header file: %s\n", d->d_name);
1026         }
1027     }
1028     return vid;
1029 }
1030
1031 /**
1032  * Preattach volumes in batches to avoid lock contention.
1033  */
1034 static int
1035 VInitPreAttachVolumes(int nthreads, struct volume_init_queue *vq)
1036 {
1037     struct volume_init_batch *vb;
1038     int i;
1039
1040     while (nthreads) {
1041         /* dequeue next volume */
1042         MUTEX_ENTER(&vq->mutex);
1043         if (queue_IsEmpty(vq)) {
1044             CV_WAIT(&vq->cv, &vq->mutex);
1045         }
1046         vb = queue_First(vq, volume_init_batch);
1047         queue_Remove(vb);
1048         MUTEX_EXIT(&vq->mutex);
1049
1050         if (vb->size) {
1051             VOL_LOCK;
1052             for (i = 0; i<vb->size; i++) {
1053                 Volume *vp;
1054                 Volume *dup;
1055                 Error ec = 0;
1056
1057                 vp = vb->batch[i];
1058                 dup = VLookupVolume_r(&ec, vp->hashid, NULL);
1059                 if (ec) {
1060                     Log("Error looking up volume, code=%d\n", ec);
1061                 }
1062                 else if (dup) {
1063                     Log("Warning: Duplicate volume id %d detected.\n", vp->hashid);
1064                 }
1065                 else {
1066                     /* put pre-attached volume onto the hash table
1067                      * and bring it up to the pre-attached state */
1068                     AddVolumeToHashTable(vp, vp->hashid);
1069                     AddVolumeToVByPList_r(vp);
1070                     VLRU_Init_Node_r(vp);
1071                     VChangeState_r(vp, VOL_STATE_PREATTACHED);
1072                 }
1073             }
1074             VOL_UNLOCK;
1075         }
1076
1077         if (vb->last) {
1078             nthreads--;
1079         }
1080         free(vb);
1081     }
1082     return 0;
1083 }
1084 #endif /* AFS_DEMAND_ATTACH_FS */
1085
1086 #if !defined(AFS_DEMAND_ATTACH_FS)
1087 /*
1088  * attach all volumes on a given disk partition
1089  */
1090 static int
1091 VAttachVolumesByPartition(struct DiskPartition64 *diskP, int * nAttached, int * nUnattached)
1092 {
1093   DIR * dirp;
1094   struct dirent * dp;
1095   int ret = 0;
1096
1097   Log("Partition %s: attaching volumes\n", diskP->name);
1098   dirp = opendir(VPartitionPath(diskP));
1099   if (!dirp) {
1100     Log("opendir on Partition %s failed!\n", diskP->name);
1101     return 1;
1102   }
1103
1104   while ((dp = readdir(dirp))) {
1105     char *p;
1106     p = strrchr(dp->d_name, '.');
1107
1108     if (vinit_attach_abort) {
1109       Log("Partition %s: abort attach volumes\n", diskP->name);
1110       goto done;
1111     }
1112
1113     if (p != NULL && strcmp(p, VHDREXT) == 0) {
1114       Error error;
1115       Volume *vp;
1116       vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
1117                                V_VOLUPD);
1118       (*(vp ? nAttached : nUnattached))++;
1119       if (error == VOFFLINE)
1120         Log("Volume %d stays offline (/vice/offline/%s exists)\n", VolumeNumber(dp->d_name), dp->d_name);
1121       else if (LogLevel >= 5) {
1122         Log("Partition %s: attached volume %d (%s)\n",
1123             diskP->name, VolumeNumber(dp->d_name),
1124             dp->d_name);
1125       }
1126       if (vp) {
1127         VPutVolume(vp);
1128       }
1129     }
1130   }
1131
1132   Log("Partition %s: attached %d volumes; %d volumes not attached\n", diskP->name, *nAttached, *nUnattached);
1133 done:
1134   closedir(dirp);
1135   return ret;
1136 }
1137 #endif /* !AFS_DEMAND_ATTACH_FS */
1138
1139 /***************************************************/
1140 /* Shutdown routines                               */
1141 /***************************************************/
1142
1143 /*
1144  * demand attach fs
1145  * highly multithreaded volume package shutdown
1146  *
1147  * with the demand attach fileserver extensions,
1148  * VShutdown has been modified to be multithreaded.
1149  * In order to achieve optimal use of many threads,
1150  * the shutdown code involves one control thread and
1151  * n shutdown worker threads.  The control thread
1152  * periodically examines the number of volumes available
1153  * for shutdown on each partition, and produces a worker
1154  * thread allocation schedule.  The idea is to eliminate
1155  * redundant scheduling computation on the workers by
1156  * having a single master scheduler.
1157  *
1158  * The scheduler's objectives are:
1159  * (1) fairness
1160  *   each partition with volumes remaining gets allocated
1161  *   at least 1 thread (assuming sufficient threads)
1162  * (2) performance
1163  *   threads are allocated proportional to the number of
1164  *   volumes remaining to be offlined.  This ensures that
1165  *   the OS I/O scheduler has many requests to elevator
1166  *   seek on partitions that will (presumably) take the
1167  *   longest amount of time (from now) to finish shutdown
1168  * (3) keep threads busy
1169  *   when there are extra threads, they are assigned to
1170  *   partitions using a simple round-robin algorithm
1171  *
1172  * In the future, we may wish to add the ability to adapt
1173  * to the relative performance patterns of each disk
1174  * partition.
1175  *
1176  *
1177  * demand attach fs
1178  * multi-step shutdown process
1179  *
1180  * demand attach shutdown is a four-step process. Each
1181  * shutdown "pass" shuts down increasingly more difficult
1182  * volumes.  The main purpose is to achieve better cache
1183  * utilization during shutdown.
1184  *
1185  * pass 0
1186  *   shutdown volumes in the unattached, pre-attached
1187  *   and error states
1188  * pass 1
1189  *   shutdown attached volumes with cached volume headers
1190  * pass 2
1191  *   shutdown all volumes in non-exclusive states
1192  * pass 3
1193  *   shutdown all remaining volumes
1194  */
1195
1196 #ifdef AFS_DEMAND_ATTACH_FS
1197
1198 void
1199 VShutdown_r(void)
1200 {
1201     int i;
1202     struct DiskPartition64 * diskP;
1203     struct diskpartition_queue_t * dpq;
1204     vshutdown_thread_t params;
1205     pthread_t tid;
1206     pthread_attr_t attrs;
1207
1208     memset(&params, 0, sizeof(vshutdown_thread_t));
1209
1210     if (VInit < 2) {
1211         Log("VShutdown:  aborting attach volumes\n");
1212         vinit_attach_abort = 1;
1213         VOL_CV_WAIT(&vol_init_attach_cond);
1214     }
1215
1216     for (params.n_parts=0, diskP = DiskPartitionList;
1217          diskP; diskP = diskP->next, params.n_parts++);
1218
1219     Log("VShutdown:  shutting down on-line volumes on %d partition%s...\n",
1220         params.n_parts, params.n_parts > 1 ? "s" : "");
1221
1222     vol_shutting_down = 1;
1223
1224     if (vol_attach_threads > 1) {
1225         /* prepare for parallel shutdown */
1226         params.n_threads = vol_attach_threads;
1227         MUTEX_INIT(&params.lock, "params", MUTEX_DEFAULT, 0);
1228         CV_INIT(&params.cv, "params", CV_DEFAULT, 0);
1229         CV_INIT(&params.master_cv, "params master", CV_DEFAULT, 0);
1230         osi_Assert(pthread_attr_init(&attrs) == 0);
1231         osi_Assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
1232         queue_Init(&params);
1233
1234         /* setup the basic partition information structures for
1235          * parallel shutdown */
1236         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1237             /* XXX debug */
1238             struct rx_queue * qp, * nqp;
1239             Volume * vp;
1240             int count = 0;
1241
1242             VVByPListWait_r(diskP);
1243             VVByPListBeginExclusive_r(diskP);
1244
1245             /* XXX debug */
1246             for (queue_Scan(&diskP->vol_list, qp, nqp, rx_queue)) {
1247                 vp = (Volume *)((char *)qp - offsetof(Volume, vol_list));
1248                 if (vp->header)
1249                     count++;
1250             }
1251             Log("VShutdown: partition %s has %d volumes with attached headers\n",
1252                 VPartitionPath(diskP), count);
1253
1254
1255             /* build up the pass 0 shutdown work queue */
1256             dpq = malloc(sizeof(struct diskpartition_queue_t));
1257             osi_Assert(dpq != NULL);
1258             dpq->diskP = diskP;
1259             queue_Prepend(&params, dpq);
1260
1261             params.part_pass_head[diskP->index] = queue_First(&diskP->vol_list, rx_queue);
1262         }
1263
1264         Log("VShutdown:  beginning parallel fileserver shutdown\n");
1265         Log("VShutdown:  using %d threads to offline volumes on %d partition%s\n",
1266             vol_attach_threads, params.n_parts, params.n_parts > 1 ? "s" : "" );
1267
1268         /* do pass 0 shutdown */
1269         MUTEX_ENTER(&params.lock);
1270         for (i=0; i < params.n_threads; i++) {
1271             osi_Assert(pthread_create
1272                    (&tid, &attrs, &VShutdownThread,
1273                     &params) == 0);
1274         }
1275
1276         /* wait for all the pass 0 shutdowns to complete */
1277         while (params.n_threads_complete < params.n_threads) {
1278             CV_WAIT(&params.master_cv, &params.lock);
1279         }
1280         params.n_threads_complete = 0;
1281         params.pass = 1;
1282         CV_BROADCAST(&params.cv);
1283         MUTEX_EXIT(&params.lock);
1284
1285         Log("VShutdown:  pass 0 completed using the 1 thread per partition algorithm\n");
1286         Log("VShutdown:  starting passes 1 through 3 using finely-granular mp-fast algorithm\n");
1287
1288         /* run the parallel shutdown scheduler. it will drop the glock internally */
1289         ShutdownController(&params);
1290
1291         /* wait for all the workers to finish pass 3 and terminate */
1292         while (params.pass < 4) {
1293             VOL_CV_WAIT(&params.cv);
1294         }
1295
1296         osi_Assert(pthread_attr_destroy(&attrs) == 0);
1297         CV_DESTROY(&params.cv);
1298         CV_DESTROY(&params.master_cv);
1299         MUTEX_DESTROY(&params.lock);
1300
1301         /* drop the VByPList exclusive reservations */
1302         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1303             VVByPListEndExclusive_r(diskP);
1304             Log("VShutdown:  %s stats : (pass[0]=%d, pass[1]=%d, pass[2]=%d, pass[3]=%d)\n",
1305                 VPartitionPath(diskP),
1306                 params.stats[0][diskP->index],
1307                 params.stats[1][diskP->index],
1308                 params.stats[2][diskP->index],
1309                 params.stats[3][diskP->index]);
1310         }
1311
1312         Log("VShutdown:  shutdown finished using %d threads\n", params.n_threads);
1313     } else {
1314         /* if we're only going to run one shutdown thread, don't bother creating
1315          * another LWP */
1316         Log("VShutdown:  beginning single-threaded fileserver shutdown\n");
1317
1318         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1319             VShutdownByPartition_r(diskP);
1320         }
1321     }
1322
1323     Log("VShutdown:  complete.\n");
1324 }
1325
1326 #else /* AFS_DEMAND_ATTACH_FS */
1327
1328 void
1329 VShutdown_r(void)
1330 {
1331     int i;
1332     Volume *vp, *np;
1333     afs_int32 code;
1334
1335     if (VInit < 2) {
1336         Log("VShutdown:  aborting attach volumes\n");
1337         vinit_attach_abort = 1;
1338 #ifdef AFS_PTHREAD_ENV
1339         VOL_CV_WAIT(&vol_init_attach_cond);
1340 #else
1341         LWP_WaitProcess(VInitAttachVolumes);
1342 #endif /* AFS_PTHREAD_ENV */
1343     }
1344
1345     Log("VShutdown:  shutting down on-line volumes...\n");
1346     vol_shutting_down = 1;
1347     for (i = 0; i < VolumeHashTable.Size; i++) {
1348         /* try to hold first volume in the hash table */
1349         for (queue_Scan(&VolumeHashTable.Table[i],vp,np,Volume)) {
1350             code = VHold_r(vp);
1351             if (code == 0) {
1352                 if (LogLevel >= 5)
1353                     Log("VShutdown:  Attempting to take volume %u offline.\n",
1354                         vp->hashid);
1355
1356                 /* next, take the volume offline (drops reference count) */
1357                 VOffline_r(vp, "File server was shut down");
1358             }
1359         }
1360     }
1361     Log("VShutdown:  complete.\n");
1362 }
1363 #endif /* AFS_DEMAND_ATTACH_FS */
1364
1365
1366 void
1367 VShutdown(void)
1368 {
1369     osi_Assert(VInit>0);
1370     VOL_LOCK;
1371     VShutdown_r();
1372     VOL_UNLOCK;
1373 }
1374
1375 /**
1376  * stop new activity (e.g. SALVSYNC) from occurring
1377  *
1378  * Use this to make the volume package less busy; for example, during
1379  * shutdown. This doesn't actually shutdown/detach anything in the
1380  * volume package, but prevents certain processes from ocurring. For
1381  * example, preventing new SALVSYNC communication in DAFS. In theory, we
1382  * could also use this to prevent new volume attachment, or prevent
1383  * other programs from checking out volumes, etc.
1384  */
1385 void
1386 VSetTranquil(void)
1387 {
1388 #ifdef AFS_DEMAND_ATTACH_FS
1389     /* make sure we don't try to contact the salvageserver, since it may
1390      * not be around anymore */
1391     vol_disallow_salvsync = 1;
1392 #endif
1393 }
1394
1395 #ifdef AFS_DEMAND_ATTACH_FS
1396 /*
1397  * demand attach fs
1398  * shutdown control thread
1399  */
1400 static void
1401 ShutdownController(vshutdown_thread_t * params)
1402 {
1403     /* XXX debug */
1404     struct DiskPartition64 * diskP;
1405     Device id;
1406     vshutdown_thread_t shadow;
1407
1408     ShutdownCreateSchedule(params);
1409
1410     while ((params->pass < 4) &&
1411            (params->n_threads_complete < params->n_threads)) {
1412         /* recompute schedule once per second */
1413
1414         memcpy(&shadow, params, sizeof(vshutdown_thread_t));
1415
1416         VOL_UNLOCK;
1417         /* XXX debug */
1418         Log("ShutdownController:  schedule version=%d, vol_remaining=%d, pass=%d\n",
1419             shadow.schedule_version, shadow.vol_remaining, shadow.pass);
1420         Log("ShutdownController:  n_threads_complete=%d, n_parts_done_pass=%d\n",
1421             shadow.n_threads_complete, shadow.n_parts_done_pass);
1422         for (diskP = DiskPartitionList; diskP; diskP=diskP->next) {
1423             id = diskP->index;
1424             Log("ShutdownController:  part[%d] : (len=%d, thread_target=%d, done_pass=%d, pass_head=%p)\n",
1425                 id,
1426                 diskP->vol_list.len,
1427                 shadow.part_thread_target[id],
1428                 shadow.part_done_pass[id],
1429                 shadow.part_pass_head[id]);
1430         }
1431
1432         sleep(1);
1433         VOL_LOCK;
1434
1435         ShutdownCreateSchedule(params);
1436     }
1437 }
1438
1439 /* create the shutdown thread work schedule.
1440  * this scheduler tries to implement fairness
1441  * by allocating at least 1 thread to each
1442  * partition with volumes to be shutdown,
1443  * and then it attempts to allocate remaining
1444  * threads based upon the amount of work left
1445  */
1446 static void
1447 ShutdownCreateSchedule(vshutdown_thread_t * params)
1448 {
1449     struct DiskPartition64 * diskP;
1450     int sum, thr_workload, thr_left;
1451     int part_residue[VOLMAXPARTS+1];
1452     Device id;
1453
1454     /* compute the total number of outstanding volumes */
1455     sum = 0;
1456     for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1457         sum += diskP->vol_list.len;
1458     }
1459
1460     params->schedule_version++;
1461     params->vol_remaining = sum;
1462
1463     if (!sum)
1464         return;
1465
1466     /* compute average per-thread workload */
1467     thr_workload = sum / params->n_threads;
1468     if (sum % params->n_threads)
1469         thr_workload++;
1470
1471     thr_left = params->n_threads;
1472     memset(&part_residue, 0, sizeof(part_residue));
1473
1474     /* for fairness, give every partition with volumes remaining
1475      * at least one thread */
1476     for (diskP = DiskPartitionList; diskP && thr_left; diskP = diskP->next) {
1477         id = diskP->index;
1478         if (diskP->vol_list.len) {
1479             params->part_thread_target[id] = 1;
1480             thr_left--;
1481         } else {
1482             params->part_thread_target[id] = 0;
1483         }
1484     }
1485
1486     if (thr_left && thr_workload) {
1487         /* compute length-weighted workloads */
1488         int delta;
1489
1490         for (diskP = DiskPartitionList; diskP && thr_left; diskP = diskP->next) {
1491             id = diskP->index;
1492             delta = (diskP->vol_list.len / thr_workload) -
1493                 params->part_thread_target[id];
1494             if (delta < 0) {
1495                 continue;
1496             }
1497             if (delta < thr_left) {
1498                 params->part_thread_target[id] += delta;
1499                 thr_left -= delta;
1500             } else {
1501                 params->part_thread_target[id] += thr_left;
1502                 thr_left = 0;
1503                 break;
1504             }
1505         }
1506     }
1507
1508     if (thr_left) {
1509         /* try to assign any leftover threads to partitions that
1510          * had volume lengths closer to needing thread_target+1 */
1511         int max_residue, max_id = 0;
1512
1513         /* compute the residues */
1514         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1515             id = diskP->index;
1516             part_residue[id] = diskP->vol_list.len -
1517                 (params->part_thread_target[id] * thr_workload);
1518         }
1519
1520         /* now try to allocate remaining threads to partitions with the
1521          * highest residues */
1522         while (thr_left) {
1523             max_residue = 0;
1524             for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1525                 id = diskP->index;
1526                 if (part_residue[id] > max_residue) {
1527                     max_residue = part_residue[id];
1528                     max_id = id;
1529                 }
1530             }
1531
1532             if (!max_residue) {
1533                 break;
1534             }
1535
1536             params->part_thread_target[max_id]++;
1537             thr_left--;
1538             part_residue[max_id] = 0;
1539         }
1540     }
1541
1542     if (thr_left) {
1543         /* punt and give any remaining threads equally to each partition */
1544         int alloc;
1545         if (thr_left >= params->n_parts) {
1546             alloc = thr_left / params->n_parts;
1547             for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1548                 id = diskP->index;
1549                 params->part_thread_target[id] += alloc;
1550                 thr_left -= alloc;
1551             }
1552         }
1553
1554         /* finish off the last of the threads */
1555         for (diskP = DiskPartitionList; thr_left && diskP; diskP = diskP->next) {
1556             id = diskP->index;
1557             params->part_thread_target[id]++;
1558             thr_left--;
1559         }
1560     }
1561 }
1562
1563 /* worker thread for parallel shutdown */
1564 static void *
1565 VShutdownThread(void * args)
1566 {
1567     vshutdown_thread_t * params;
1568     int found, pass, schedule_version_save, count;
1569     struct DiskPartition64 *diskP;
1570     struct diskpartition_queue_t * dpq;
1571     Device id;
1572
1573     params = (vshutdown_thread_t *) args;
1574
1575     /* acquire the shutdown pass 0 lock */
1576     MUTEX_ENTER(&params->lock);
1577
1578     /* if there's still pass 0 work to be done,
1579      * get a work entry, and do a pass 0 shutdown */
1580     if (queue_IsNotEmpty(params)) {
1581         dpq = queue_First(params, diskpartition_queue_t);
1582         queue_Remove(dpq);
1583         MUTEX_EXIT(&params->lock);
1584         diskP = dpq->diskP;
1585         free(dpq);
1586         id = diskP->index;
1587
1588         count = 0;
1589         while (ShutdownVolumeWalk_r(diskP, 0, &params->part_pass_head[id]))
1590             count++;
1591         params->stats[0][diskP->index] = count;
1592         MUTEX_ENTER(&params->lock);
1593     }
1594
1595     params->n_threads_complete++;
1596     if (params->n_threads_complete == params->n_threads) {
1597         /* notify control thread that all workers have completed pass 0 */
1598         CV_SIGNAL(&params->master_cv);
1599     }
1600     while (params->pass == 0) {
1601         CV_WAIT(&params->cv, &params->lock);
1602     }
1603
1604     /* switch locks */
1605     MUTEX_EXIT(&params->lock);
1606     VOL_LOCK;
1607
1608     pass = params->pass;
1609     osi_Assert(pass > 0);
1610
1611     /* now escalate through the more complicated shutdowns */
1612     while (pass <= 3) {
1613         schedule_version_save = params->schedule_version;
1614         found = 0;
1615         /* find a disk partition to work on */
1616         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1617             id = diskP->index;
1618             if (params->part_thread_target[id] && !params->part_done_pass[id]) {
1619                 params->part_thread_target[id]--;
1620                 found = 1;
1621                 break;
1622             }
1623         }
1624
1625         if (!found) {
1626             /* hmm. for some reason the controller thread couldn't find anything for
1627              * us to do. let's see if there's anything we can do */
1628             for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1629                 id = diskP->index;
1630                 if (diskP->vol_list.len && !params->part_done_pass[id]) {
1631                     found = 1;
1632                     break;
1633                 } else if (!params->part_done_pass[id]) {
1634                     params->part_done_pass[id] = 1;
1635                     params->n_parts_done_pass++;
1636                     if (pass == 3) {
1637                         Log("VShutdown:  done shutting down volumes on partition %s.\n",
1638                             VPartitionPath(diskP));
1639                     }
1640                 }
1641             }
1642         }
1643
1644         /* do work on this partition until either the controller
1645          * creates a new schedule, or we run out of things to do
1646          * on this partition */
1647         if (found) {
1648             count = 0;
1649             while (!params->part_done_pass[id] &&
1650                    (schedule_version_save == params->schedule_version)) {
1651                 /* ShutdownVolumeWalk_r will drop the glock internally */
1652                 if (!ShutdownVolumeWalk_r(diskP, pass, &params->part_pass_head[id])) {
1653                     if (!params->part_done_pass[id]) {
1654                         params->part_done_pass[id] = 1;
1655                         params->n_parts_done_pass++;
1656                         if (pass == 3) {
1657                             Log("VShutdown:  done shutting down volumes on partition %s.\n",
1658                                 VPartitionPath(diskP));
1659                         }
1660                     }
1661                     break;
1662                 }
1663                 count++;
1664             }
1665
1666             params->stats[pass][id] += count;
1667         } else {
1668             /* ok, everyone is done this pass, proceed */
1669
1670             /* barrier lock */
1671             params->n_threads_complete++;
1672             while (params->pass == pass) {
1673                 if (params->n_threads_complete == params->n_threads) {
1674                     /* we are the last thread to complete, so we will
1675                      * reinitialize worker pool state for the next pass */
1676                     params->n_threads_complete = 0;
1677                     params->n_parts_done_pass = 0;
1678                     params->pass++;
1679                     for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
1680                         id = diskP->index;
1681                         params->part_done_pass[id] = 0;
1682                         params->part_pass_head[id] = queue_First(&diskP->vol_list, rx_queue);
1683                     }
1684
1685                     /* compute a new thread schedule before releasing all the workers */
1686                     ShutdownCreateSchedule(params);
1687
1688                     /* wake up all the workers */
1689                     CV_BROADCAST(&params->cv);
1690
1691                     VOL_UNLOCK;
1692                     Log("VShutdown:  pass %d completed using %d threads on %d partitions\n",
1693                         pass, params->n_threads, params->n_parts);
1694                     VOL_LOCK;
1695                 } else {
1696                     VOL_CV_WAIT(&params->cv);
1697                 }
1698             }
1699             pass = params->pass;
1700         }
1701
1702         /* for fairness */
1703         VOL_UNLOCK;
1704         pthread_yield();
1705         VOL_LOCK;
1706     }
1707
1708     VOL_UNLOCK;
1709
1710     return NULL;
1711 }
1712
1713 /* shut down all volumes on a given disk partition
1714  *
1715  * note that this function will not allow mp-fast
1716  * shutdown of a partition */
1717 int
1718 VShutdownByPartition_r(struct DiskPartition64 * dp)
1719 {
1720     int pass;
1721     int pass_stats[4];
1722     int total;
1723
1724     /* wait for other exclusive ops to finish */
1725     VVByPListWait_r(dp);
1726
1727     /* begin exclusive access */
1728     VVByPListBeginExclusive_r(dp);
1729
1730     /* pick the low-hanging fruit first,
1731      * then do the complicated ones last
1732      * (has the advantage of keeping
1733      *  in-use volumes up until the bitter end) */
1734     for (pass = 0, total=0; pass < 4; pass++) {
1735         pass_stats[pass] = ShutdownVByPForPass_r(dp, pass);
1736         total += pass_stats[pass];
1737     }
1738
1739     /* end exclusive access */
1740     VVByPListEndExclusive_r(dp);
1741
1742     Log("VShutdownByPartition:  shut down %d volumes on %s (pass[0]=%d, pass[1]=%d, pass[2]=%d, pass[3]=%d)\n",
1743         total, VPartitionPath(dp), pass_stats[0], pass_stats[1], pass_stats[2], pass_stats[3]);
1744
1745     return 0;
1746 }
1747
1748 /* internal shutdown functionality
1749  *
1750  * for multi-pass shutdown:
1751  * 0 to only "shutdown" {pre,un}attached and error state volumes
1752  * 1 to also shutdown attached volumes w/ volume header loaded
1753  * 2 to also shutdown attached volumes w/o volume header loaded
1754  * 3 to also shutdown exclusive state volumes
1755  *
1756  * caller MUST hold exclusive access on the hash chain
1757  * because we drop vol_glock_mutex internally
1758  *
1759  * this function is reentrant for passes 1--3
1760  * (e.g. multiple threads can cooperate to
1761  *  shutdown a partition mp-fast)
1762  *
1763  * pass 0 is not scaleable because the volume state data is
1764  * synchronized by vol_glock mutex, and the locking overhead
1765  * is too high to drop the lock long enough to do linked list
1766  * traversal
1767  */
1768 static int
1769 ShutdownVByPForPass_r(struct DiskPartition64 * dp, int pass)
1770 {
1771     struct rx_queue * q = queue_First(&dp->vol_list, rx_queue);
1772     int i = 0;
1773
1774     while (ShutdownVolumeWalk_r(dp, pass, &q))
1775         i++;
1776
1777     return i;
1778 }
1779
1780 /* conditionally shutdown one volume on partition dp
1781  * returns 1 if a volume was shutdown in this pass,
1782  * 0 otherwise */
1783 static int
1784 ShutdownVolumeWalk_r(struct DiskPartition64 * dp, int pass,
1785                      struct rx_queue ** idx)
1786 {
1787     struct rx_queue *qp, *nqp;
1788     Volume * vp;
1789
1790     qp = *idx;
1791
1792     for (queue_ScanFrom(&dp->vol_list, qp, qp, nqp, rx_queue)) {
1793         vp = (Volume *) (((char *)qp) - offsetof(Volume, vol_list));
1794
1795         switch (pass) {
1796         case 0:
1797             if ((V_attachState(vp) != VOL_STATE_UNATTACHED) &&
1798                 (V_attachState(vp) != VOL_STATE_ERROR) &&
1799                 (V_attachState(vp) != VOL_STATE_DELETED) &&
1800                 (V_attachState(vp) != VOL_STATE_PREATTACHED)) {
1801                 break;
1802             }
1803         case 1:
1804             if ((V_attachState(vp) == VOL_STATE_ATTACHED) &&
1805                 (vp->header == NULL)) {
1806                 break;
1807             }
1808         case 2:
1809             if (VIsExclusiveState(V_attachState(vp))) {
1810                 break;
1811             }
1812         case 3:
1813             *idx = nqp;
1814             DeleteVolumeFromVByPList_r(vp);
1815             VShutdownVolume_r(vp);
1816             vp = NULL;
1817             return 1;
1818         }
1819     }
1820
1821     return 0;
1822 }
1823
1824 /*
1825  * shutdown a specific volume
1826  */
1827 /* caller MUST NOT hold a heavyweight ref on vp */
1828 int
1829 VShutdownVolume_r(Volume * vp)
1830 {
1831     int code;
1832
1833     VCreateReservation_r(vp);
1834
1835     if (LogLevel >= 5) {
1836         Log("VShutdownVolume_r:  vid=%u, device=%d, state=%hu\n",
1837             vp->hashid, vp->partition->device, V_attachState(vp));
1838     }
1839
1840     /* wait for other blocking ops to finish */
1841     VWaitExclusiveState_r(vp);
1842
1843     osi_Assert(VIsValidState(V_attachState(vp)));
1844
1845     switch(V_attachState(vp)) {
1846     case VOL_STATE_SALVAGING:
1847         /* Leave salvaging volumes alone. Any in-progress salvages will
1848          * continue working after viced shuts down. This is intentional.
1849          */
1850
1851     case VOL_STATE_PREATTACHED:
1852     case VOL_STATE_ERROR:
1853         VChangeState_r(vp, VOL_STATE_UNATTACHED);
1854     case VOL_STATE_UNATTACHED:
1855     case VOL_STATE_DELETED:
1856         break;
1857     case VOL_STATE_GOING_OFFLINE:
1858     case VOL_STATE_SHUTTING_DOWN:
1859     case VOL_STATE_ATTACHED:
1860         code = VHold_r(vp);
1861         if (!code) {
1862             if (LogLevel >= 5)
1863                 Log("VShutdown:  Attempting to take volume %u offline.\n",
1864                     vp->hashid);
1865
1866             /* take the volume offline (drops reference count) */
1867             VOffline_r(vp, "File server was shut down");
1868         }
1869         break;
1870     default:
1871         break;
1872     }
1873
1874     VCancelReservation_r(vp);
1875     vp = NULL;
1876     return 0;
1877 }
1878 #endif /* AFS_DEMAND_ATTACH_FS */
1879
1880
1881 /***************************************************/
1882 /* Header I/O routines                             */
1883 /***************************************************/
1884
1885 static const char *
1886 HeaderName(bit32 magic)
1887 {
1888     switch (magic) {
1889     case VOLUMEINFOMAGIC:
1890         return "volume info";
1891     case SMALLINDEXMAGIC:
1892         return "small index";
1893     case LARGEINDEXMAGIC:
1894         return "large index";
1895     case LINKTABLEMAGIC:
1896         return "link table";
1897     }
1898     return "unknown";
1899 }
1900
1901 /* open a descriptor for the inode (h),
1902  * read in an on-disk structure into buffer (to) of size (size),
1903  * verify versionstamp in structure has magic (magic) and
1904  * optionally verify version (version) if (version) is nonzero
1905  */
1906 static void
1907 ReadHeader(Error * ec, IHandle_t * h, char *to, int size, bit32 magic,
1908            bit32 version)
1909 {
1910     struct versionStamp *vsn;
1911     FdHandle_t *fdP;
1912     afs_sfsize_t nbytes;
1913     afs_ino_str_t stmp;
1914
1915     *ec = 0;
1916     if (h == NULL) {
1917         Log("ReadHeader: Null inode handle argument for %s header file.\n",
1918             HeaderName(magic));
1919         *ec = VSALVAGE;
1920         return;
1921     }
1922
1923     fdP = IH_OPEN(h);
1924     if (fdP == NULL) {
1925         Log("ReadHeader: Failed to open %s header file "
1926             "(volume=%u, inode=%s); errno=%d\n", HeaderName(magic), h->ih_vid,
1927             PrintInode(stmp, h->ih_ino), errno);
1928         *ec = VSALVAGE;
1929         return;
1930     }
1931
1932     vsn = (struct versionStamp *)to;
1933     nbytes = FDH_PREAD(fdP, to, size, 0);
1934     if (nbytes < 0) {
1935         Log("ReadHeader: Failed to read %s header file "
1936             "(volume=%u, inode=%s); errno=%d\n", HeaderName(magic), h->ih_vid,
1937             PrintInode(stmp, h->ih_ino), errno);
1938         *ec = VSALVAGE;
1939         FDH_REALLYCLOSE(fdP);
1940         return;
1941     }
1942     if (nbytes != size) {
1943         Log("ReadHeader: Incorrect number of bytes read from %s header file "
1944             "(volume=%u, inode=%s); expected=%d, read=%d\n",
1945             HeaderName(magic), h->ih_vid, PrintInode(stmp, h->ih_ino), size,
1946             (int)nbytes);
1947         *ec = VSALVAGE;
1948         FDH_REALLYCLOSE(fdP);
1949         return;
1950     }
1951     if (vsn->magic != magic) {
1952         Log("ReadHeader: Incorrect magic for %s header file "
1953             "(volume=%u, inode=%s); expected=0x%x, read=0x%x\n",
1954             HeaderName(magic), h->ih_vid, PrintInode(stmp, h->ih_ino), magic,
1955             vsn->magic);
1956         *ec = VSALVAGE;
1957         FDH_REALLYCLOSE(fdP);
1958         return;
1959     }
1960
1961     FDH_CLOSE(fdP);
1962
1963     /* Check is conditional, in case caller wants to inspect version himself */
1964     if (version && vsn->version != version) {
1965         Log("ReadHeader: Incorrect version for %s header file "
1966             "(volume=%u, inode=%s); expected=%x, read=%x\n",
1967             HeaderName(magic), h->ih_vid, PrintInode(stmp, h->ih_ino),
1968             version, vsn->version);
1969         *ec = VSALVAGE;
1970     }
1971 }
1972
1973 void
1974 WriteVolumeHeader_r(Error * ec, Volume * vp)
1975 {
1976     IHandle_t *h = V_diskDataHandle(vp);
1977     FdHandle_t *fdP;
1978
1979     *ec = 0;
1980
1981     fdP = IH_OPEN(h);
1982     if (fdP == NULL) {
1983         *ec = VSALVAGE;
1984         return;
1985     }
1986     if (FDH_PWRITE(fdP, (char *)&V_disk(vp), sizeof(V_disk(vp)), 0)
1987         != sizeof(V_disk(vp))) {
1988         *ec = VSALVAGE;
1989         FDH_REALLYCLOSE(fdP);
1990         return;
1991     }
1992     FDH_CLOSE(fdP);
1993 }
1994
1995 /* VolumeHeaderToDisk
1996  * Allows for storing 64 bit inode numbers in on-disk volume header
1997  * file.
1998  */
1999 /* convert in-memory representation of a volume header to the
2000  * on-disk representation of a volume header */
2001 void
2002 VolumeHeaderToDisk(VolumeDiskHeader_t * dh, VolumeHeader_t * h)
2003 {
2004
2005     memset(dh, 0, sizeof(VolumeDiskHeader_t));
2006     dh->stamp = h->stamp;
2007     dh->id = h->id;
2008     dh->parent = h->parent;
2009
2010 #ifdef AFS_64BIT_IOPS_ENV
2011     dh->volumeInfo_lo = (afs_int32) h->volumeInfo & 0xffffffff;
2012     dh->volumeInfo_hi = (afs_int32) (h->volumeInfo >> 32) & 0xffffffff;
2013     dh->smallVnodeIndex_lo = (afs_int32) h->smallVnodeIndex & 0xffffffff;
2014     dh->smallVnodeIndex_hi =
2015         (afs_int32) (h->smallVnodeIndex >> 32) & 0xffffffff;
2016     dh->largeVnodeIndex_lo = (afs_int32) h->largeVnodeIndex & 0xffffffff;
2017     dh->largeVnodeIndex_hi =
2018         (afs_int32) (h->largeVnodeIndex >> 32) & 0xffffffff;
2019     dh->linkTable_lo = (afs_int32) h->linkTable & 0xffffffff;
2020     dh->linkTable_hi = (afs_int32) (h->linkTable >> 32) & 0xffffffff;
2021 #else
2022     dh->volumeInfo_lo = h->volumeInfo;
2023     dh->smallVnodeIndex_lo = h->smallVnodeIndex;
2024     dh->largeVnodeIndex_lo = h->largeVnodeIndex;
2025     dh->linkTable_lo = h->linkTable;
2026 #endif
2027 }
2028
2029 /* DiskToVolumeHeader
2030  * Converts an on-disk representation of a volume header to
2031  * the in-memory representation of a volume header.
2032  *
2033  * Makes the assumption that AFS has *always*
2034  * zero'd the volume header file so that high parts of inode
2035  * numbers are 0 in older (SGI EFS) volume header files.
2036  */
2037 void
2038 DiskToVolumeHeader(VolumeHeader_t * h, VolumeDiskHeader_t * dh)
2039 {
2040     memset(h, 0, sizeof(VolumeHeader_t));
2041     h->stamp = dh->stamp;
2042     h->id = dh->id;
2043     h->parent = dh->parent;
2044
2045 #ifdef AFS_64BIT_IOPS_ENV
2046     h->volumeInfo =
2047         (Inode) dh->volumeInfo_lo | ((Inode) dh->volumeInfo_hi << 32);
2048
2049     h->smallVnodeIndex =
2050         (Inode) dh->smallVnodeIndex_lo | ((Inode) dh->
2051                                           smallVnodeIndex_hi << 32);
2052
2053     h->largeVnodeIndex =
2054         (Inode) dh->largeVnodeIndex_lo | ((Inode) dh->
2055                                           largeVnodeIndex_hi << 32);
2056     h->linkTable =
2057         (Inode) dh->linkTable_lo | ((Inode) dh->linkTable_hi << 32);
2058 #else
2059     h->volumeInfo = dh->volumeInfo_lo;
2060     h->smallVnodeIndex = dh->smallVnodeIndex_lo;
2061     h->largeVnodeIndex = dh->largeVnodeIndex_lo;
2062     h->linkTable = dh->linkTable_lo;
2063 #endif
2064 }
2065
2066
2067 /***************************************************/
2068 /* Volume Attachment routines                      */
2069 /***************************************************/
2070
2071 #ifdef AFS_DEMAND_ATTACH_FS
2072 /**
2073  * pre-attach a volume given its path.
2074  *
2075  * @param[out] ec         outbound error code
2076  * @param[in]  partition  partition path string
2077  * @param[in]  name       volume id string
2078  *
2079  * @return volume object pointer
2080  *
2081  * @note A pre-attached volume will only have its partition
2082  *       and hashid fields initialized.  At first call to
2083  *       VGetVolume, the volume will be fully attached.
2084  *
2085  */
2086 Volume *
2087 VPreAttachVolumeByName(Error * ec, char *partition, char *name)
2088 {
2089     Volume * vp;
2090     VOL_LOCK;
2091     vp = VPreAttachVolumeByName_r(ec, partition, name);
2092     VOL_UNLOCK;
2093     return vp;
2094 }
2095
2096 /**
2097  * pre-attach a volume given its path.
2098  *
2099  * @param[out] ec         outbound error code
2100  * @param[in]  partition  path to vice partition
2101  * @param[in]  name       volume id string
2102  *
2103  * @return volume object pointer
2104  *
2105  * @pre VOL_LOCK held
2106  *
2107  * @internal volume package internal use only.
2108  */
2109 Volume *
2110 VPreAttachVolumeByName_r(Error * ec, char *partition, char *name)
2111 {
2112     return VPreAttachVolumeById_r(ec,
2113                                   partition,
2114                                   VolumeNumber(name));
2115 }
2116
2117 /**
2118  * pre-attach a volume given its path and numeric volume id.
2119  *
2120  * @param[out] ec          error code return
2121  * @param[in]  partition   path to vice partition
2122  * @param[in]  volumeId    numeric volume id
2123  *
2124  * @return volume object pointer
2125  *
2126  * @pre VOL_LOCK held
2127  *
2128  * @internal volume package internal use only.
2129  */
2130 Volume *
2131 VPreAttachVolumeById_r(Error * ec,
2132                        char * partition,
2133                        VolId volumeId)
2134 {
2135     Volume *vp;
2136     struct DiskPartition64 *partp;
2137
2138     *ec = 0;
2139
2140     osi_Assert(programType == fileServer);
2141
2142     if (!(partp = VGetPartition_r(partition, 0))) {
2143         *ec = VNOVOL;
2144         Log("VPreAttachVolumeById_r:  Error getting partition (%s)\n", partition);
2145         return NULL;
2146     }
2147
2148     vp = VLookupVolume_r(ec, volumeId, NULL);
2149     if (*ec) {
2150         return NULL;
2151     }
2152
2153     return VPreAttachVolumeByVp_r(ec, partp, vp, volumeId);
2154 }
2155
2156 /**
2157  * preattach a volume.
2158  *
2159  * @param[out] ec     outbound error code
2160  * @param[in]  partp  pointer to partition object
2161  * @param[in]  vp     pointer to volume object
2162  * @param[in]  vid    volume id
2163  *
2164  * @return volume object pointer
2165  *
2166  * @pre VOL_LOCK is held.
2167  *
2168  * @warning Returned volume object pointer does not have to
2169  *          equal the pointer passed in as argument vp.  There
2170  *          are potential race conditions which can result in
2171  *          the pointers having different values.  It is up to
2172  *          the caller to make sure that references are handled
2173  *          properly in this case.
2174  *
2175  * @note If there is already a volume object registered with
2176  *       the same volume id, its pointer MUST be passed as
2177  *       argument vp.  Failure to do so will result in a silent
2178  *       failure to preattach.
2179  *
2180  * @internal volume package internal use only.
2181  */
2182 Volume *
2183 VPreAttachVolumeByVp_r(Error * ec,
2184                        struct DiskPartition64 * partp,
2185                        Volume * vp,
2186                        VolId vid)
2187 {
2188     Volume *nvp = NULL;
2189
2190     *ec = 0;
2191
2192     /* check to see if pre-attach already happened */
2193     if (vp &&
2194         (V_attachState(vp) != VOL_STATE_UNATTACHED) &&
2195         (V_attachState(vp) != VOL_STATE_DELETED) &&
2196         (V_attachState(vp) != VOL_STATE_PREATTACHED) &&
2197         !VIsErrorState(V_attachState(vp))) {
2198         /*
2199          * pre-attach is a no-op in all but the following cases:
2200          *
2201          *   - volume is unattached
2202          *   - volume is in an error state
2203          *   - volume is pre-attached
2204          */
2205         Log("VPreattachVolumeByVp_r: volume %u not in quiescent state (state %u flags 0x%x)\n",
2206             vid, V_attachState(vp), V_attachFlags(vp));
2207         goto done;
2208     } else if (vp) {
2209         /* we're re-attaching a volume; clear out some old state */
2210         memset(&vp->salvage, 0, sizeof(struct VolumeOnlineSalvage));
2211
2212         if (V_partition(vp) != partp) {
2213             /* XXX potential race */
2214             DeleteVolumeFromVByPList_r(vp);
2215         }
2216     } else {
2217         /* if we need to allocate a new Volume struct,
2218          * go ahead and drop the vol glock, otherwise
2219          * do the basic setup synchronised, as it's
2220          * probably not worth dropping the lock */
2221         VOL_UNLOCK;
2222
2223         /* allocate the volume structure */
2224         vp = nvp = calloc(1, sizeof(Volume));
2225         osi_Assert(vp != NULL);
2226         queue_Init(&vp->vnode_list);
2227         queue_Init(&vp->rx_call_list);
2228         CV_INIT(&V_attachCV(vp), "vp attach", CV_DEFAULT, 0);
2229     }
2230
2231     /* link the volume with its associated vice partition */
2232     vp->device = partp->device;
2233     vp->partition = partp;
2234
2235     vp->hashid = vid;
2236     vp->specialStatus = 0;
2237
2238     /* if we dropped the lock, reacquire the lock,
2239      * check for pre-attach races, and then add
2240      * the volume to the hash table */
2241     if (nvp) {
2242         VOL_LOCK;
2243         nvp = VLookupVolume_r(ec, vid, NULL);
2244         if (*ec) {
2245             free(vp);
2246             vp = NULL;
2247             goto done;
2248         } else if (nvp) { /* race detected */
2249             free(vp);
2250             vp = nvp;
2251             goto done;
2252         } else {
2253           /* hack to make up for VChangeState_r() decrementing
2254            * the old state counter */
2255           VStats.state_levels[0]++;
2256         }
2257     }
2258
2259     /* put pre-attached volume onto the hash table
2260      * and bring it up to the pre-attached state */
2261     AddVolumeToHashTable(vp, vp->hashid);
2262     AddVolumeToVByPList_r(vp);
2263     VLRU_Init_Node_r(vp);
2264     VChangeState_r(vp, VOL_STATE_PREATTACHED);
2265
2266     if (LogLevel >= 5)
2267         Log("VPreAttachVolumeByVp_r:  volume %u pre-attached\n", vp->hashid);
2268
2269   done:
2270     if (*ec)
2271         return NULL;
2272     else
2273         return vp;
2274 }
2275 #endif /* AFS_DEMAND_ATTACH_FS */
2276
2277 /* Attach an existing volume, given its pathname, and return a
2278    pointer to the volume header information.  The volume also
2279    normally goes online at this time.  An offline volume
2280    must be reattached to make it go online */
2281 Volume *
2282 VAttachVolumeByName(Error * ec, char *partition, char *name, int mode)
2283 {
2284     Volume *retVal;
2285     VOL_LOCK;
2286     retVal = VAttachVolumeByName_r(ec, partition, name, mode);
2287     VOL_UNLOCK;
2288     return retVal;
2289 }
2290
2291 Volume *
2292 VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
2293 {
2294     Volume *vp = NULL;
2295     struct DiskPartition64 *partp;
2296     char path[64];
2297     int isbusy = 0;
2298     VolId volumeId;
2299     int checkedOut;
2300 #ifdef AFS_DEMAND_ATTACH_FS
2301     VolumeStats stats_save;
2302     Volume *svp = NULL;
2303 #endif /* AFS_DEMAND_ATTACH_FS */
2304
2305     *ec = 0;
2306
2307     volumeId = VolumeNumber(name);
2308
2309     if (!(partp = VGetPartition_r(partition, 0))) {
2310         *ec = VNOVOL;
2311         Log("VAttachVolume: Error getting partition (%s)\n", partition);
2312         goto done;
2313     }
2314
2315     if (VRequiresPartLock()) {
2316         osi_Assert(VInit == 3);
2317         VLockPartition_r(partition);
2318     } else if (programType == fileServer) {
2319 #ifdef AFS_DEMAND_ATTACH_FS
2320         /* lookup the volume in the hash table */
2321         vp = VLookupVolume_r(ec, volumeId, NULL);
2322         if (*ec) {
2323             return NULL;
2324         }
2325
2326         if (vp) {
2327             /* save any counters that are supposed to
2328              * be monotonically increasing over the
2329              * lifetime of the fileserver */
2330             memcpy(&stats_save, &vp->stats, sizeof(VolumeStats));
2331         } else {
2332             memset(&stats_save, 0, sizeof(VolumeStats));
2333         }
2334
2335         /* if there's something in the hash table, and it's not
2336          * in the pre-attach state, then we may need to detach
2337          * it before proceeding */
2338         if (vp && (V_attachState(vp) != VOL_STATE_PREATTACHED)) {
2339             VCreateReservation_r(vp);
2340             VWaitExclusiveState_r(vp);
2341
2342             /* at this point state must be one of:
2343              *   - UNATTACHED
2344              *   - ATTACHED
2345              *   - SHUTTING_DOWN
2346              *   - GOING_OFFLINE
2347              *   - SALVAGING
2348              *   - ERROR
2349              *   - DELETED
2350              */
2351
2352             if (vp->specialStatus == VBUSY)
2353                 isbusy = 1;
2354
2355             /* if it's already attached, see if we can return it */
2356             if (V_attachState(vp) == VOL_STATE_ATTACHED) {
2357                 VGetVolumeByVp_r(ec, vp);
2358                 if (V_inUse(vp) == fileServer) {
2359                     VCancelReservation_r(vp);
2360                     return vp;
2361                 }
2362
2363                 /* otherwise, we need to detach, and attempt to re-attach */
2364                 VDetachVolume_r(ec, vp);
2365                 if (*ec) {
2366                     Log("VAttachVolume: Error detaching old volume instance (%s)\n", name);
2367                 }
2368             } else {
2369                 /* if it isn't fully attached, delete from the hash tables,
2370                    and let the refcounter handle the rest */
2371                 DeleteVolumeFromHashTable(vp);
2372                 DeleteVolumeFromVByPList_r(vp);
2373             }
2374
2375             VCancelReservation_r(vp);
2376             vp = NULL;
2377         }
2378
2379         /* pre-attach volume if it hasn't been done yet */
2380         if (!vp ||
2381             (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2382             (V_attachState(vp) == VOL_STATE_DELETED) ||
2383             (V_attachState(vp) == VOL_STATE_ERROR)) {
2384             svp = vp;
2385             vp = VPreAttachVolumeByVp_r(ec, partp, vp, volumeId);
2386             if (*ec) {
2387                 return NULL;
2388             }
2389         }
2390
2391         osi_Assert(vp != NULL);
2392
2393         /* handle pre-attach races
2394          *
2395          * multiple threads can race to pre-attach a volume,
2396          * but we can't let them race beyond that
2397          *
2398          * our solution is to let the first thread to bring
2399          * the volume into an exclusive state win; the other
2400          * threads just wait until it finishes bringing the
2401          * volume online, and then they do a vgetvolumebyvp
2402          */
2403         if (svp && (svp != vp)) {
2404             /* wait for other exclusive ops to finish */
2405             VCreateReservation_r(vp);
2406             VWaitExclusiveState_r(vp);
2407
2408             /* get a heavyweight ref, kill the lightweight ref, and return */
2409             VGetVolumeByVp_r(ec, vp);
2410             VCancelReservation_r(vp);
2411             return vp;
2412         }
2413
2414         /* at this point, we are chosen as the thread to do
2415          * demand attachment for this volume. all other threads
2416          * doing a getvolume on vp->hashid will block until we finish */
2417
2418         /* make sure any old header cache entries are invalidated
2419          * before proceeding */
2420         FreeVolumeHeader(vp);
2421
2422         VChangeState_r(vp, VOL_STATE_ATTACHING);
2423
2424         /* restore any saved counters */
2425         memcpy(&vp->stats, &stats_save, sizeof(VolumeStats));
2426 #else /* AFS_DEMAND_ATTACH_FS */
2427         vp = VGetVolume_r(ec, volumeId);
2428         if (vp) {
2429             if (V_inUse(vp) == fileServer)
2430                 return vp;
2431             if (vp->specialStatus == VBUSY)
2432                 isbusy = 1;
2433             VDetachVolume_r(ec, vp);
2434             if (*ec) {
2435                 Log("VAttachVolume: Error detaching volume (%s)\n", name);
2436             }
2437             vp = NULL;
2438         }
2439 #endif /* AFS_DEMAND_ATTACH_FS */
2440     }
2441
2442     *ec = 0;
2443     strcpy(path, VPartitionPath(partp));
2444
2445     VOL_UNLOCK;
2446
2447     strcat(path, OS_DIRSEP);
2448     strcat(path, name);
2449
2450     if (!vp) {
2451       vp = (Volume *) calloc(1, sizeof(Volume));
2452       osi_Assert(vp != NULL);
2453       vp->hashid = volumeId;
2454       vp->device = partp->device;
2455       vp->partition = partp;
2456       queue_Init(&vp->vnode_list);
2457       queue_Init(&vp->rx_call_list);
2458 #ifdef AFS_DEMAND_ATTACH_FS
2459       CV_INIT(&V_attachCV(vp), "vp attach", CV_DEFAULT, 0);
2460 #endif /* AFS_DEMAND_ATTACH_FS */
2461     }
2462
2463     /* attach2 is entered without any locks, and returns
2464      * with vol_glock_mutex held */
2465     vp = attach2(ec, volumeId, path, partp, vp, isbusy, mode, &checkedOut);
2466
2467     if (VCanUseFSSYNC() && vp) {
2468 #ifdef AFS_DEMAND_ATTACH_FS
2469         if ((mode == V_VOLUPD) || (VolumeWriteable(vp) && (mode == V_CLONE))) {
2470             /* mark volume header as in use so that volser crashes lead to a
2471              * salvage attempt */
2472             VUpdateVolume_r(ec, vp, 0);
2473         }
2474         /* for dafs, we should tell the fileserver, except for V_PEEK
2475          * where we know it is not necessary */
2476         if (mode == V_PEEK) {
2477             vp->needsPutBack = 0;
2478         } else {
2479             vp->needsPutBack = VOL_PUTBACK;
2480         }
2481 #else /* !AFS_DEMAND_ATTACH_FS */
2482         /* duplicate computation in fssync.c about whether the server
2483          * takes the volume offline or not.  If the volume isn't
2484          * offline, we must not return it when we detach the volume,
2485          * or the server will abort */
2486         if (mode == V_READONLY || mode == V_PEEK
2487             || (!VolumeWriteable(vp) && (mode == V_CLONE || mode == V_DUMP)))
2488             vp->needsPutBack = 0;
2489         else
2490             vp->needsPutBack = VOL_PUTBACK;
2491 #endif /* !AFS_DEMAND_ATTACH_FS */
2492     }
2493 #ifdef FSSYNC_BUILD_CLIENT
2494     /* Only give back the vol to the fileserver if we checked it out; attach2
2495      * will set checkedOut only if we successfully checked it out from the
2496      * fileserver. */
2497     if (VCanUseFSSYNC() && vp == NULL && checkedOut) {
2498
2499 #ifdef AFS_DEMAND_ATTACH_FS
2500         /* If we couldn't attach but we scheduled a salvage, we already
2501          * notified the fileserver; don't online it now */
2502         if (*ec != VSALVAGING)
2503 #endif /* AFS_DEMAND_ATTACH_FS */
2504         FSYNC_VolOp(volumeId, partition, FSYNC_VOL_ON, 0, NULL);
2505     } else
2506 #endif
2507     if (programType == fileServer && vp) {
2508 #ifdef AFS_DEMAND_ATTACH_FS
2509         /*
2510          * we can get here in cases where we don't "own"
2511          * the volume (e.g. volume owned by a utility).
2512          * short circuit around potential disk header races.
2513          */
2514         if (V_attachState(vp) != VOL_STATE_ATTACHED) {
2515             goto done;
2516         }
2517 #endif
2518         VUpdateVolume_r(ec, vp, 0);
2519         if (*ec) {
2520             Log("VAttachVolume: Error updating volume\n");
2521             if (vp)
2522                 VPutVolume_r(vp);
2523             goto done;
2524         }
2525         if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
2526 #ifndef AFS_DEMAND_ATTACH_FS
2527             /* This is a hack: by temporarily setting the incore
2528              * dontSalvage flag ON, the volume will be put back on the
2529              * Update list (with dontSalvage OFF again).  It will then
2530              * come back in N minutes with DONT_SALVAGE eventually
2531              * set.  This is the way that volumes that have never had
2532              * it set get it set; or that volumes that have been
2533              * offline without DONT SALVAGE having been set also
2534              * eventually get it set */
2535             V_dontSalvage(vp) = DONT_SALVAGE;
2536 #endif /* !AFS_DEMAND_ATTACH_FS */
2537             VAddToVolumeUpdateList_r(ec, vp);
2538             if (*ec) {
2539                 Log("VAttachVolume: Error adding volume to update list\n");
2540                 if (vp)
2541                     VPutVolume_r(vp);
2542                 goto done;
2543             }
2544         }
2545         if (LogLevel)
2546             Log("VOnline:  volume %u (%s) attached and online\n", V_id(vp),
2547                 V_name(vp));
2548     }
2549
2550   done:
2551     if (VRequiresPartLock()) {
2552         VUnlockPartition_r(partition);
2553     }
2554     if (*ec) {
2555 #ifdef AFS_DEMAND_ATTACH_FS
2556         /* attach failed; make sure we're in error state */
2557         if (vp && !VIsErrorState(V_attachState(vp))) {
2558             VChangeState_r(vp, VOL_STATE_ERROR);
2559         }
2560 #endif /* AFS_DEMAND_ATTACH_FS */
2561         return NULL;
2562     } else {
2563         return vp;
2564     }
2565 }
2566
2567 #ifdef AFS_DEMAND_ATTACH_FS
2568 /* VAttachVolumeByVp_r
2569  *
2570  * finish attaching a volume that is
2571  * in a less than fully attached state
2572  */
2573 /* caller MUST hold a ref count on vp */
2574 static Volume *
2575 VAttachVolumeByVp_r(Error * ec, Volume * vp, int mode)
2576 {
2577     char name[VMAXPATHLEN];
2578     int reserve = 0;
2579     struct DiskPartition64 *partp;
2580     char path[64];
2581     int isbusy = 0;
2582     VolId volumeId;
2583     Volume * nvp = NULL;
2584     VolumeStats stats_save;
2585     int checkedOut;
2586     *ec = 0;
2587
2588     /* volume utility should never call AttachByVp */
2589     osi_Assert(programType == fileServer);
2590
2591     volumeId = vp->hashid;
2592     partp = vp->partition;
2593     VolumeExternalName_r(volumeId, name, sizeof(name));
2594
2595
2596     /* if another thread is performing a blocking op, wait */
2597     VWaitExclusiveState_r(vp);
2598
2599     memcpy(&stats_save, &vp->stats, sizeof(VolumeStats));
2600
2601     /* if it's already attached, see if we can return it */
2602     if (V_attachState(vp) == VOL_STATE_ATTACHED) {
2603         VGetVolumeByVp_r(ec, vp);
2604         if (V_inUse(vp) == fileServer) {
2605             return vp;
2606         } else {
2607             if (vp->specialStatus == VBUSY)
2608                 isbusy = 1;
2609             VDetachVolume_r(ec, vp);
2610             if (*ec) {
2611                 Log("VAttachVolume: Error detaching volume (%s)\n", name);
2612             }
2613             vp = NULL;
2614         }
2615     }
2616
2617     /* pre-attach volume if it hasn't been done yet */
2618     if (!vp ||
2619         (V_attachState(vp) == VOL_STATE_UNATTACHED) ||
2620         (V_attachState(vp) == VOL_STATE_DELETED) ||
2621         (V_attachState(vp) == VOL_STATE_ERROR)) {
2622         nvp = VPreAttachVolumeByVp_r(ec, partp, vp, volumeId);
2623         if (*ec) {
2624             return NULL;
2625         }
2626         if (nvp != vp) {
2627             reserve = 1;
2628             VCreateReservation_r(nvp);
2629             vp = nvp;
2630         }
2631     }
2632
2633     osi_Assert(vp != NULL);
2634     VChangeState_r(vp, VOL_STATE_ATTACHING);
2635
2636     /* restore monotonically increasing stats */
2637     memcpy(&vp->stats, &stats_save, sizeof(VolumeStats));
2638
2639     *ec = 0;
2640
2641     /* compute path to disk header */
2642     strcpy(path, VPartitionPath(partp));
2643
2644     VOL_UNLOCK;
2645
2646     strcat(path, OS_DIRSEP);
2647     strcat(path, name);
2648
2649     /* do volume attach
2650      *
2651      * NOTE: attach2 is entered without any locks, and returns
2652      * with vol_glock_mutex held */
2653     vp = attach2(ec, volumeId, path, partp, vp, isbusy, mode, &checkedOut);
2654
2655     /*
2656      * the event that an error was encountered, or
2657      * the volume was not brought to an attached state
2658      * for any reason, skip to the end.  We cannot
2659      * safely call VUpdateVolume unless we "own" it.
2660      */
2661     if (*ec ||
2662         (vp == NULL) ||
2663         (V_attachState(vp) != VOL_STATE_ATTACHED)) {
2664         goto done;
2665     }
2666
2667     VUpdateVolume_r(ec, vp, 0);
2668     if (*ec) {
2669         Log("VAttachVolume: Error updating volume %u\n", vp->hashid);
2670         VPutVolume_r(vp);
2671         goto done;
2672     }
2673     if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
2674 #ifndef AFS_DEMAND_ATTACH_FS
2675         /* This is a hack: by temporarily setting the incore
2676          * dontSalvage flag ON, the volume will be put back on the
2677          * Update list (with dontSalvage OFF again).  It will then
2678          * come back in N minutes with DONT_SALVAGE eventually
2679          * set.  This is the way that volumes that have never had
2680          * it set get it set; or that volumes that have been
2681          * offline without DONT SALVAGE having been set also
2682          * eventually get it set */
2683         V_dontSalvage(vp) = DONT_SALVAGE;
2684 #endif /* !AFS_DEMAND_ATTACH_FS */
2685         VAddToVolumeUpdateList_r(ec, vp);
2686         if (*ec) {
2687             Log("VAttachVolume: Error adding volume %u to update list\n", vp->hashid);
2688             if (vp)
2689                 VPutVolume_r(vp);
2690             goto done;
2691         }
2692     }
2693     if (LogLevel)
2694         Log("VOnline:  volume %u (%s) attached and online\n", V_id(vp),
2695             V_name(vp));
2696   done:
2697     if (reserve) {
2698         VCancelReservation_r(nvp);
2699         reserve = 0;
2700     }
2701     if (*ec && (*ec != VOFFLINE) && (*ec != VSALVAGE)) {
2702         if (vp && !VIsErrorState(V_attachState(vp))) {
2703             VChangeState_r(vp, VOL_STATE_ERROR);
2704         }
2705         return NULL;
2706     } else {
2707         return vp;
2708     }
2709 }
2710
2711 /**
2712  * lock a volume on disk (non-blocking).
2713  *
2714  * @param[in] vp  The volume to lock
2715  * @param[in] locktype READ_LOCK or WRITE_LOCK
2716  *
2717  * @return operation status
2718  *  @retval 0 success, lock was obtained
2719  *  @retval EBUSY a conflicting lock was held by another process
2720  *  @retval EIO   error acquiring lock
2721  *
2722  * @pre If we're in the fileserver, vp is in an exclusive state
2723  *
2724  * @pre vp is not already locked
2725  */
2726 static int
2727 VLockVolumeNB(Volume *vp, int locktype)
2728 {
2729     int code;
2730
2731     osi_Assert(programType != fileServer || VIsExclusiveState(V_attachState(vp)));
2732     osi_Assert(!(V_attachFlags(vp) & VOL_LOCKED));
2733
2734     code = VLockVolumeByIdNB(vp->hashid, vp->partition, locktype);
2735     if (code == 0) {
2736         V_attachFlags(vp) |= VOL_LOCKED;
2737     }
2738
2739     return code;
2740 }
2741
2742 /**
2743  * unlock a volume on disk that was locked with VLockVolumeNB.
2744  *
2745  * @param[in] vp  volume to unlock
2746  *
2747  * @pre If we're in the fileserver, vp is in an exclusive state
2748  *
2749  * @pre vp has already been locked
2750  */
2751 static void
2752 VUnlockVolume(Volume *vp)
2753 {
2754     osi_Assert(programType != fileServer || VIsExclusiveState(V_attachState(vp)));
2755     osi_Assert((V_attachFlags(vp) & VOL_LOCKED));
2756
2757     VUnlockVolumeById(vp->hashid, vp->partition);
2758
2759     V_attachFlags(vp) &= ~VOL_LOCKED;
2760 }
2761 #endif /* AFS_DEMAND_ATTACH_FS */
2762
2763 /**
2764  * read in a vol header, possibly lock the vol header, and possibly check out
2765  * the vol header from the fileserver, as part of volume attachment.
2766  *
2767  * @param[out] ec     error code
2768  * @param[in] vp      volume pointer object
2769  * @param[in] partp   disk partition object of the attaching partition
2770  * @param[in] mode    attachment mode such as V_VOLUPD, V_DUMP, etc (see
2771  *                    volume.h)
2772  * @param[in] peek    1 to just try to read in the volume header and make sure
2773  *                    we don't try to lock the vol, or check it out from
2774  *                    FSSYNC or anything like that; 0 otherwise, for 'normal'
2775  *                    operation
2776  * @param[out] acheckedOut   If we successfully checked-out the volume from
2777  *                           the fileserver (if we needed to), this is set
2778  *                           to 1, otherwise it is untouched.
2779  *
2780  * @note As part of DAFS volume attachment, the volume header may be either
2781  *       read- or write-locked to ensure mutual exclusion of certain volume
2782  *       operations. In some cases in order to determine whether we need to
2783  *       read- or write-lock the header, we need to read in the header to see
2784  *       if the volume is RW or not. So, if we read in the header under a
2785  *       read-lock and determine that we actually need a write-lock on the
2786  *       volume header, this function will drop the read lock, acquire a write
2787  *       lock, and read the header in again.
2788  */
2789 static void
2790 attach_volume_header(Error *ec, Volume *vp, struct DiskPartition64 *partp,
2791                      int mode, int peek, int *acheckedOut)
2792 {
2793     struct VolumeDiskHeader diskHeader;
2794     struct VolumeHeader header;
2795     int code;
2796     int first_try = 1;
2797     int lock_tries = 0, checkout_tries = 0;
2798     int retry;
2799     VolumeId volid = vp->hashid;
2800 #ifdef FSSYNC_BUILD_CLIENT
2801     int checkout, done_checkout = 0;
2802 #endif /* FSSYNC_BUILD_CLIENT */
2803 #ifdef AFS_DEMAND_ATTACH_FS
2804     int locktype = 0, use_locktype = -1;
2805 #endif /* AFS_DEMAND_ATTACH_FS */
2806
2807  retry:
2808     retry = 0;
2809     *ec = 0;
2810
2811     if (lock_tries > VOL_MAX_CHECKOUT_RETRIES) {
2812         Log("VAttachVolume: retried too many times trying to lock header for "
2813             "vol %lu part %s; giving up\n", afs_printable_uint32_lu(volid),
2814             VPartitionPath(partp));
2815         *ec = VNOVOL;
2816         goto done;
2817     }
2818     if (checkout_tries > VOL_MAX_CHECKOUT_RETRIES) {
2819         Log("VAttachVolume: retried too many times trying to checkout "
2820             "vol %lu part %s; giving up\n", afs_printable_uint32_lu(volid),
2821             VPartitionPath(partp));
2822         *ec = VNOVOL;
2823         goto done;
2824     }
2825
2826     if (VReadVolumeDiskHeader(volid, partp, NULL)) {
2827         /* short-circuit the 'volume does not exist' case */
2828         *ec = VNOVOL;
2829         goto done;
2830     }
2831
2832 #ifdef FSSYNC_BUILD_CLIENT
2833     checkout = !done_checkout;
2834     done_checkout = 1;
2835     if (!peek && checkout && VMustCheckoutVolume(mode)) {
2836         SYNC_response res;
2837         memset(&res, 0, sizeof(res));
2838
2839         if (FSYNC_VolOp(volid, partp->name, FSYNC_VOL_NEEDVOLUME, mode, &res)
2840             != SYNC_OK) {
2841
2842             if (res.hdr.reason == FSYNC_SALVAGE) {
2843                 Log("VAttachVolume: file server says volume %lu is salvaging\n",
2844                      afs_printable_uint32_lu(volid));
2845                 *ec = VSALVAGING;
2846             } else {
2847                 Log("VAttachVolume: attach of volume %lu apparently denied by file server\n",
2848                      afs_printable_uint32_lu(volid));
2849                 *ec = VNOVOL;   /* XXXX */
2850             }
2851             goto done;
2852         }
2853         *acheckedOut = 1;
2854     }
2855 #endif
2856
2857 #ifdef AFS_DEMAND_ATTACH_FS
2858     if (use_locktype < 0) {
2859         /* don't know whether vol is RO or RW; assume it's RO and we can retry
2860          * if it turns out to be RW */
2861         locktype = VVolLockType(mode, 0);
2862
2863     } else {
2864         /* a previous try says we should use use_locktype to lock the volume,
2865          * so use that */
2866         locktype = use_locktype;
2867     }
2868
2869     if (!peek && locktype) {
2870         code = VLockVolumeNB(vp, locktype);
2871         if (code) {
2872             if (code == EBUSY) {
2873                 Log("VAttachVolume: another program has vol %lu locked\n",
2874                     afs_printable_uint32_lu(volid));
2875             } else {
2876                 Log("VAttachVolume: error %d trying to lock vol %lu\n",
2877                     code, afs_printable_uint32_lu(volid));
2878             }
2879
2880             *ec = VNOVOL;
2881             goto done;
2882         }
2883     }
2884 #endif /* AFS_DEMAND_ATTACH_FS */
2885
2886     code = VReadVolumeDiskHeader(volid, partp, &diskHeader);
2887     if (code) {
2888         if (code == EIO) {
2889             *ec = VSALVAGE;
2890         } else {
2891             *ec = VNOVOL;
2892         }
2893         goto done;
2894     }
2895
2896     DiskToVolumeHeader(&header, &diskHeader);
2897
2898     IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header.parent,
2899             header.largeVnodeIndex);
2900     IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header.parent,
2901             header.smallVnodeIndex);
2902     IH_INIT(vp->diskDataHandle, partp->device, header.parent,
2903             header.volumeInfo);
2904     IH_INIT(vp->linkHandle, partp->device, header.parent, header.linkTable);
2905
2906     if (first_try) {
2907         /* only need to do this once */
2908         VOL_LOCK;
2909         GetVolumeHeader(vp);
2910         VOL_UNLOCK;
2911     }
2912
2913 #if defined(AFS_DEMAND_ATTACH_FS) && defined(FSSYNC_BUILD_CLIENT)
2914     /* demand attach changes the V_PEEK mechanism
2915      *
2916      * we can now suck the current disk data structure over
2917      * the fssync interface without going to disk
2918      *
2919      * (technically, we don't need to restrict this feature
2920      *  to demand attach fileservers.  However, I'm trying
2921      *  to limit the number of common code changes)
2922      */
2923     if (VCanUseFSSYNC() && (mode == V_PEEK || peek)) {
2924         SYNC_response res;
2925         res.payload.len = sizeof(VolumeDiskData);
2926         res.payload.buf = &vp->header->diskstuff;
2927
2928         if (FSYNC_VolOp(vp->hashid,
2929                         partp->name,
2930                         FSYNC_VOL_QUERY_HDR,
2931                         FSYNC_WHATEVER,
2932                         &res) == SYNC_OK) {
2933             goto disk_header_loaded;
2934         }
2935     }
2936 #endif /* AFS_DEMAND_ATTACH_FS && FSSYNC_BUILD_CLIENT */
2937     (void)ReadHeader(ec, V_diskDataHandle(vp), (char *)&V_disk(vp),
2938                      sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
2939
2940 #ifdef AFS_DEMAND_ATTACH_FS
2941     /* update stats */
2942     VOL_LOCK;
2943     IncUInt64(&VStats.hdr_loads);
2944     IncUInt64(&vp->stats.hdr_loads);
2945     VOL_UNLOCK;
2946 #endif /* AFS_DEMAND_ATTACH_FS */
2947
2948     if (*ec) {
2949         Log("VAttachVolume: Error reading diskDataHandle header for vol %lu; "
2950             "error=%u\n", afs_printable_uint32_lu(volid), *ec);
2951         goto done;
2952     }
2953
2954 #ifdef AFS_DEMAND_ATTACH_FS
2955 # ifdef FSSYNC_BUILD_CLIENT
2956  disk_header_loaded:
2957 # endif /* FSSYNC_BUILD_CLIENT */
2958
2959     /* if the lock type we actually used to lock the volume is different than
2960      * the lock type we should have used, retry with the lock type we should
2961      * use */
2962     use_locktype = VVolLockType(mode, VolumeWriteable(vp));
2963     if (locktype != use_locktype) {
2964         retry = 1;
2965         lock_tries++;
2966     }
2967 #endif /* AFS_DEMAND_ATTACH_FS */
2968
2969     *ec = 0;
2970
2971  done:
2972 #if defined(AFS_DEMAND_ATTACH_FS) && defined(FSSYNC_BUILD_CLIENT)
2973     if (!peek && *ec == 0 && retry == 0 && VMustCheckoutVolume(mode)) {
2974
2975         code = FSYNC_VerifyCheckout(volid, partp->name, FSYNC_VOL_NEEDVOLUME, mode);
2976
2977         if (code == SYNC_DENIED) {
2978             /* must retry checkout; fileserver no longer thinks we have
2979              * the volume */
2980             retry = 1;
2981             checkout_tries++;
2982             done_checkout = 0;
2983
2984         } else if (code != SYNC_OK) {
2985             *ec = VNOVOL;
2986         }
2987     }
2988 #endif /* AFS_DEMAND_ATTACH_FS && FSSYNC_BUILD_CLIENT */
2989
2990     if (*ec || retry) {
2991         /* either we are going to be called again for a second pass, or we
2992          * encountered an error; clean up in either case */
2993
2994 #ifdef AFS_DEMAND_ATTACH_FS
2995         if ((V_attachFlags(vp) & VOL_LOCKED)) {
2996             VUnlockVolume(vp);
2997         }
2998 #endif /* AFS_DEMAND_ATTACH_FS */
2999         if (vp->linkHandle) {
3000             IH_RELEASE(vp->vnodeIndex[vLarge].handle);
3001             IH_RELEASE(vp->vnodeIndex[vSmall].handle);
3002             IH_RELEASE(vp->diskDataHandle);
3003             IH_RELEASE(vp->linkHandle);
3004         }
3005     }
3006
3007     if (*ec) {
3008         VOL_LOCK;
3009         FreeVolumeHeader(vp);
3010         VOL_UNLOCK;
3011         return;
3012     }
3013     if (retry) {
3014         first_try = 0;
3015         goto retry;
3016     }
3017 }
3018
3019 #ifdef AFS_DEMAND_ATTACH_FS
3020 static void
3021 attach_check_vop(Error *ec, VolumeId volid, struct DiskPartition64 *partp,
3022                  Volume *vp, int *acheckedOut)
3023 {
3024     *ec = 0;
3025
3026     if (vp->pending_vol_op) {
3027
3028         VOL_LOCK;
3029
3030         if (vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningUnknown) {
3031             int code;
3032             code = VVolOpLeaveOnlineNoHeader_r(vp, vp->pending_vol_op);
3033             if (code == 1) {
3034                 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
3035             } else if (code == 0) {
3036                 vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
3037
3038             } else {
3039                 /* we need the vol header to determine if the volume can be
3040                  * left online for the vop, so... get the header */
3041
3042                 VOL_UNLOCK;
3043
3044                 /* attach header with peek=1 to avoid checking out the volume
3045                  * or locking it; we just want the header info, we're not
3046                  * messing with the volume itself at all */
3047                 attach_volume_header(ec, vp, partp, V_PEEK, 1, acheckedOut);
3048                 if (*ec) {
3049                     return;
3050                 }
3051
3052                 VOL_LOCK;
3053
3054                 if (VVolOpLeaveOnline_r(vp, vp->pending_vol_op)) {
3055                     vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOnline;
3056                 } else {
3057                     vp->pending_vol_op->vol_op_state = FSSYNC_VolOpRunningOffline;
3058                 }
3059
3060                 /* make sure we grab a new vol header and re-open stuff on
3061                  * actual attachment; we can't keep the data we grabbed, since
3062                  * it was not done under a lock and thus not safe */
3063                 FreeVolumeHeader(vp);
3064                 VReleaseVolumeHandles_r(vp);
3065             }
3066         }
3067         /* see if the pending volume op requires exclusive access */
3068         switch (vp->pending_vol_op->vol_op_state) {
3069         case FSSYNC_VolOpPending:
3070             /* this should never happen */
3071             osi_Assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpPending);
3072             break;
3073
3074         case FSSYNC_VolOpRunningUnknown:
3075             /* this should never happen; we resolved 'unknown' above */
3076             osi_Assert(vp->pending_vol_op->vol_op_state != FSSYNC_VolOpRunningUnknown);
3077             break;
3078
3079         case FSSYNC_VolOpRunningOffline:
3080             /* mark the volume down */
3081             *ec = VOFFLINE;
3082             VChangeState_r(vp, VOL_STATE_UNATTACHED);
3083
3084             /* do not set V_offlineMessage here; we don't have ownership of
3085              * the volume (and probably do not have the header loaded), so we
3086              * can't alter the disk header */
3087
3088             /* check to see if we should set the specialStatus flag */
3089             if (VVolOpSetVBusy_r(vp, vp->pending_vol_op)) {
3090                 /* don't overwrite specialStatus if it was already set to
3091                  * something else (e.g. VMOVED) */
3092                 if (!vp->specialStatus) {
3093                     vp->specialStatus = VBUSY;
3094                 }
3095             }
3096             break;
3097
3098         default:
3099             break;
3100         }
3101
3102         VOL_UNLOCK;
3103     }
3104 }
3105 #endif /* AFS_DEMAND_ATTACH_FS */
3106
3107 /**
3108  * volume attachment helper function.
3109  *
3110  * @param[out] ec      error code
3111  * @param[in] volumeId volume ID of the attaching volume
3112  * @param[in] path     full path to the volume header .vol file
3113  * @param[in] partp    disk partition object for the attaching partition
3114  * @param[in] vp       volume object; vp->hashid, vp->device, vp->partition,
3115  *                     vp->vnode_list, vp->rx_call_list, and V_attachCV (for
3116  *                     DAFS) should already be initialized
3117  * @param[in] isbusy   1 if vp->specialStatus should be set to VBUSY; that is,
3118  *                     if there is a volume operation running for this volume
3119  *                     that should set the volume to VBUSY during its run. 0
3120  *                     otherwise. (see VVolOpSetVBusy_r)
3121  * @param[in] mode     attachment mode such as V_VOLUPD, V_DUMP, etc (see
3122  *                     volume.h)
3123  * @param[out] acheckedOut   If we successfully checked-out the volume from
3124  *                           the fileserver (if we needed to), this is set
3125  *                           to 1, otherwise it is 0.
3126  *
3127  * @return pointer to the semi-attached volume pointer
3128  *  @retval NULL an error occurred (check value of *ec)
3129  *  @retval vp volume successfully attaching
3130  *
3131  * @pre no locks held
3132  *
3133  * @post VOL_LOCK held
3134  */
3135 static Volume *
3136 attach2(Error * ec, VolId volumeId, char *path, struct DiskPartition64 *partp,
3137         Volume * vp, int isbusy, int mode, int *acheckedOut)
3138 {
3139     /* have we read in the header successfully? */
3140     int read_header = 0;
3141
3142 #ifdef AFS_DEMAND_ATTACH_FS
3143     /* should we FreeVolume(vp) instead of VCheckFree(vp) in the error
3144      * cleanup? */
3145     int forcefree = 0;
3146
3147     /* in the case of an error, to what state should the volume be
3148      * transitioned? */
3149     VolState error_state = VOL_STATE_ERROR;
3150 #endif /* AFS_DEMAND_ATTACH_FS */
3151
3152     *ec = 0;
3153
3154     vp->vnodeIndex[vLarge].handle = NULL;
3155     vp->vnodeIndex[vSmall].handle = NULL;
3156     vp->diskDataHandle = NULL;
3157     vp->linkHandle = NULL;
3158
3159     *acheckedOut = 0;
3160
3161 #ifdef AFS_DEMAND_ATTACH_FS
3162     attach_check_vop(ec, volumeId, partp, vp, acheckedOut);
3163     if (!*ec) {
3164         attach_volume_header(ec, vp, partp, mode, 0, acheckedOut);
3165     }
3166 #else
3167     attach_volume_header(ec, vp, partp, mode, 0, acheckedOut);
3168 #endif /* !AFS_DEMAND_ATTACH_FS */
3169
3170     if (*ec == VNOVOL) {
3171         /* if the volume doesn't exist, skip straight to 'error' so we don't
3172          * request a salvage */
3173         goto unlocked_error;
3174     }
3175
3176     if (!*ec) {
3177         read_header = 1;
3178
3179         /* ensure that we don't override specialStatus if it was set to
3180          * something else (e.g. VMOVED) */
3181         if (isbusy && !vp->specialStatus) {
3182             vp->specialStatus = VBUSY;
3183         }
3184         vp->shuttingDown = 0;
3185         vp->goingOffline = 0;
3186         vp->nUsers = 1;
3187 #ifdef AFS_DEMAND_ATTACH_FS
3188         vp->stats.last_attach = FT_ApproxTime();
3189         vp->stats.attaches++;
3190 #endif
3191
3192         VOL_LOCK;
3193         IncUInt64(&VStats.attaches);
3194         vp->cacheCheck = ++VolumeCacheCheck;
3195         /* just in case this ever rolls over */
3196         if (!vp->cacheCheck)
3197             vp->cacheCheck = ++VolumeCacheCheck;
3198         VOL_UNLOCK;
3199
3200 #ifdef AFS_DEMAND_ATTACH_FS
3201         V_attachFlags(vp) |= VOL_HDR_LOADED;
3202         vp->stats.last_hdr_load = vp->stats.last_attach;
3203 #endif /* AFS_DEMAND_ATTACH_FS */
3204     }
3205
3206     if (!*ec) {
3207         struct IndexFileHeader iHead;
3208
3209         /*
3210          * We just read in the diskstuff part of the header.  If the detailed
3211          * volume stats area has not yet been initialized, we should bzero the
3212          * area and mark it as initialized.
3213          */
3214         if (!(V_stat_initialized(vp))) {
3215             memset((V_stat_area(vp)), 0, VOL_STATS_BYTES);
3216             V_stat_initialized(vp) = 1;
3217         }
3218
3219         (void)ReadHeader(ec, vp->vnodeIndex[vSmall].handle,
3220                          (char *)&iHead, sizeof(iHead),
3221                          SMALLINDEXMAGIC, SMALLINDEXVERSION);
3222
3223         if (*ec) {
3224             Log("VAttachVolume: Error reading smallVnode vol header %s; error=%u\n", path, *ec);
3225         }
3226     }
3227
3228     if (!*ec) {
3229         struct IndexFileHeader iHead;
3230
3231         (void)ReadHeader(ec, vp->vnodeIndex[vLarge].handle,
3232                          (char *)&iHead, sizeof(iHead),
3233                          LARGEINDEXMAGIC, LARGEINDEXVERSION);
3234
3235         if (*ec) {
3236             Log("VAttachVolume: Error reading largeVnode vol header %s; error=%u\n", path, *ec);
3237         }
3238     }
3239
3240 #ifdef AFS_NAMEI_ENV
3241     if (!*ec) {
3242         struct versionStamp stamp;
3243
3244         (void)ReadHeader(ec, V_linkHandle(vp), (char *)&stamp,
3245                          sizeof(stamp), LINKTABLEMAGIC, LINKTABLEVERSION);
3246
3247         if (*ec) {
3248             Log("VAttachVolume: Error reading namei vol header %s; error=%u\n", path, *ec);
3249         }
3250     }
3251 #endif /* AFS_NAMEI_ENV */
3252
3253 #if defined(AFS_DEMAND_ATTACH_FS)
3254     if (*ec && ((*ec != VOFFLINE) || (V_attachState(vp) != VOL_STATE_UNATTACHED))) {
3255         VOL_LOCK;
3256         if (!VCanScheduleSalvage()) {
3257             Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%u\n", path, *ec);
3258         }
3259         VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
3260         vp->nUsers = 0;
3261
3262         goto locked_error;
3263     } else if (*ec) {
3264         /* volume operation in progress */
3265         VOL_LOCK;
3266         /* we have already transitioned the vp away from ATTACHING state, so we
3267          * can go right to the end of attach2, and we do not need to transition
3268          * to ERROR. */
3269         goto error_notbroken;
3270     }
3271 #else /* AFS_DEMAND_ATTACH_FS */
3272     if (*ec) {
3273         Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%u\n", path, *ec);
3274         goto unlocked_error;
3275     }
3276 #endif /* AFS_DEMAND_ATTACH_FS */
3277
3278     if (V_needsSalvaged(vp)) {
3279         if (vp->specialStatus)
3280             vp->specialStatus = 0;
3281         VOL_LOCK;
3282 #if defined(AFS_DEMAND_ATTACH_FS)
3283         if (!VCanScheduleSalvage()) {
3284             Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
3285         }
3286         VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_NO_OFFLINE);
3287         vp->nUsers = 0;
3288
3289 #else /* AFS_DEMAND_ATTACH_FS */
3290         *ec = VSALVAGE;
3291 #endif /* AFS_DEMAND_ATTACH_FS */
3292
3293         goto locked_error;
3294     }
3295
3296     VOL_LOCK;
3297     vp->nextVnodeUnique = V_uniquifier(vp);
3298
3299     if (VShouldCheckInUse(mode) && V_inUse(vp) && VolumeWriteable(vp)) {
3300         if (!V_needsSalvaged(vp)) {
3301             V_needsSalvaged(vp) = 1;
3302             VUpdateVolume_r(ec, vp, 0);
3303         }
3304 #if defined(AFS_DEMAND_ATTACH_FS)
3305         if (!VCanScheduleSalvage()) {
3306             Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
3307         }
3308         VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, VOL_SALVAGE_NO_OFFLINE);
3309         vp->nUsers = 0;
3310
3311 #else /* AFS_DEMAND_ATTACH_FS */
3312         Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
3313         *ec = VSALVAGE;
3314 #endif /* AFS_DEMAND_ATTACH_FS */
3315
3316         goto locked_error;
3317     }
3318
3319     if (programType == fileServer && V_destroyMe(vp) == DESTROY_ME) {
3320         /* Only check destroyMe if we are the fileserver, since the
3321          * volserver et al sometimes need to work with volumes with
3322          * destroyMe set. Examples are 'temporary' volumes the
3323          * volserver creates, and when we create a volume (destroyMe
3324          * is set on creation; sometimes a separate volserver
3325          * transaction is created to clear destroyMe).
3326          */
3327
3328 #if defined(AFS_DEMAND_ATTACH_FS)
3329         /* schedule a salvage so the volume goes away on disk */
3330         VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
3331         VChangeState_r(vp, VOL_STATE_ERROR);
3332         vp->nUsers = 0;
3333         forcefree = 1;
3334 #endif /* AFS_DEMAND_ATTACH_FS */
3335         Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
3336         *ec = VNOVOL;
3337         goto locked_error;
3338     }
3339
3340     vp->vnodeIndex[vSmall].bitmap = vp->vnodeIndex[vLarge].bitmap = NULL;
3341 #ifndef BITMAP_LATER
3342     if (programType == fileServer && VolumeWriteable(vp)) {
3343         int i;
3344         for (i = 0; i < nVNODECLASSES; i++) {
3345             VGetBitmap_r(ec, vp, i);
3346             if (*ec) {
3347 #ifdef AFS_DEMAND_ATTACH_FS
3348                 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
3349                 vp->nUsers = 0;
3350 #endif /* AFS_DEMAND_ATTACH_FS */
3351                 Log("VAttachVolume: error getting bitmap for volume (%s)\n",
3352                     path);
3353                 goto locked_error;
3354             }
3355         }
3356     }
3357 #endif /* BITMAP_LATER */
3358
3359     if (VInit >= 2 && V_needsCallback(vp)) {
3360         if (V_BreakVolumeCallbacks) {
3361             Log("VAttachVolume: Volume %lu was changed externally; breaking callbacks\n",
3362                 afs_printable_uint32_lu(V_id(vp)));
3363             V_needsCallback(vp) = 0;
3364             VOL_UNLOCK;
3365             (*V_BreakVolumeCallbacks) (V_id(vp));
3366             VOL_LOCK;
3367
3368             VUpdateVolume_r(ec, vp, 0);
3369         }
3370 #ifdef FSSYNC_BUILD_CLIENT
3371         else if (VCanUseFSSYNC()) {
3372             afs_int32 fsync_code;
3373
3374             V_needsCallback(vp) = 0;
3375             VOL_UNLOCK;
3376             fsync_code = FSYNC_VolOp(V_id(vp), NULL, FSYNC_VOL_BREAKCBKS, FSYNC_WHATEVER, NULL);
3377             VOL_LOCK;
3378
3379             if (fsync_code) {
3380                 V_needsCallback(vp) = 1;
3381                 Log("Error trying to tell the fileserver to break callbacks for "
3382                     "changed volume %lu; error code %ld\n",
3383                     afs_printable_uint32_lu(V_id(vp)),
3384                     afs_printable_int32_ld(fsync_code));
3385             } else {
3386                 VUpdateVolume_r(ec, vp, 0);
3387             }
3388         }
3389 #endif /* FSSYNC_BUILD_CLIENT */
3390
3391         if (*ec) {
3392             Log("VAttachVolume: error %d clearing needsCallback on volume "
3393                 "%lu; needs salvage\n", (int)*ec,
3394                 afs_printable_uint32_lu(V_id(vp)));
3395 #ifdef AFS_DEMAND_ATTACH_FS
3396             VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, VOL_SALVAGE_NO_OFFLINE);
3397             vp->nUsers = 0;
3398 #else /* !AFS_DEMAND_ATTACH_FS */
3399             *ec = VSALVAGE;
3400 #endif /* !AFS_DEMAND_ATTACh_FS */
3401             goto locked_error;
3402         }
3403     }
3404
3405     if (programType == fileServer) {
3406         if (vp->specialStatus)
3407             vp->specialStatus = 0;
3408         if (V_blessed(vp) && V_inService(vp) && !V_needsSalvaged(vp)) {
3409             V_inUse(vp) = fileServer;
3410             V_offlineMessage(vp)[0] = '\0';
3411         }
3412         if (!V_inUse(vp)) {
3413             *ec = VNOVOL;
3414 #ifdef AFS_DEMAND_ATTACH_FS
3415             /* Put the vol into PREATTACHED state, so if someone tries to
3416              * access it again, we try to attach, see that we're not blessed,
3417              * and give a VNOVOL error again. Putting it into UNATTACHED state
3418              * would result in a VOFFLINE error instead. */
3419             error_state = VOL_STATE_PREATTACHED;
3420 #endif /* AFS_DEMAND_ATTACH_FS */
3421
3422             /* mimic e.g. GetVolume errors */
3423             if (!V_blessed(vp)) {
3424                 Log("Volume %lu offline: not blessed\n", afs_printable_uint32_lu(V_id(vp)));
3425                 FreeVolumeHeader(vp);
3426             } else if (!V_inService(vp)) {
3427                 Log("Volume %lu offline: not in service\n", afs_printable_uint32_lu(V_id(vp)));
3428                 FreeVolumeHeader(vp);
3429             } else {
3430                 Log("Volume %lu offline: needs salvage\n", afs_printable_uint32_lu(V_id(vp)));
3431                 *ec = VSALVAGE;
3432 #ifdef AFS_DEMAND_ATTACH_FS
3433                 error_state = VOL_STATE_ERROR;
3434                 /* see if we can recover */
3435                 VRequestSalvage_r(ec, vp, SALVSYNC_NEEDED, 0 /*flags*/);
3436 #endif
3437             }
3438 #ifdef AFS_DEMAND_ATTACH_FS
3439             vp->nUsers = 0;
3440 #endif
3441             goto locked_error;
3442         }
3443     } else {
3444 #ifdef AFS_DEMAND_ATTACH_FS
3445         if ((mode != V_PEEK) && (mode != V_SECRETLY))
3446             V_inUse(vp) = programType;
3447 #endif /* AFS_DEMAND_ATTACH_FS */
3448         V_checkoutMode(vp) = mode;
3449     }
3450
3451     AddVolumeToHashTable(vp, V_id(vp));
3452 #ifdef AFS_DEMAND_ATTACH_FS
3453     if (VCanUnlockAttached() && (V_attachFlags(vp) & VOL_LOCKED)) {
3454         VUnlockVolume(vp);
3455     }
3456     if ((programType != fileServer) ||
3457         (V_inUse(vp) == fileServer)) {
3458         AddVolumeToVByPList_r(vp);
3459         VLRU_Add_r(vp);
3460         VChangeState_r(vp, VOL_STATE_ATTACHED);
3461     } else {
3462         VChangeState_r(vp, VOL_STATE_UNATTACHED);
3463     }
3464 #endif
3465
3466     return vp;
3467
3468 unlocked_error:
3469     VOL_LOCK;
3470 locked_error:
3471 #ifdef AFS_DEMAND_ATTACH_FS
3472     if (!VIsErrorState(V_attachState(vp))) {
3473         if (VIsErrorState(error_state)) {
3474             Log("attach2: forcing vol %u to error state (state %u flags 0x%x ec %d)\n",
3475                 vp->hashid, V_attachState(vp), V_attachFlags(vp), *ec);
3476         }
3477         VChangeState_r(vp, error_state);
3478     }
3479 #endif /* AFS_DEMAND_ATTACH_FS */
3480
3481     if (read_header) {
3482         VReleaseVolumeHandles_r(vp);
3483     }
3484
3485 #ifdef AFS_DEMAND_ATTACH_FS
3486  error_notbroken:
3487     if (VCheckSalvage(vp) == VCHECK_SALVAGE_FAIL) {
3488         /* The salvage could not be scheduled with the salvage server
3489          * due to a hard error. Reset the error code to prevent retry loops by
3490          * callers. */
3491         if (*ec == VSALVAGING) {
3492             *ec = VSALVAGE;
3493         }
3494     }
3495     if (forcefree) {
3496         FreeVolume(vp);
3497     } else {
3498         VCheckFree(vp);
3499     }
3500 #else /* !AFS_DEMAND_ATTACH_FS */
3501     FreeVolume(vp);
3502 #endif /* !AFS_DEMAND_ATTACH_FS */
3503     return NULL;
3504 }
3505
3506 /* Attach an existing volume.
3507    The volume also normally goes online at this time.
3508    An offline volume must be reattached to make it go online.
3509  */
3510
3511 Volume *
3512 VAttachVolume(Error * ec, VolumeId volumeId, int mode)
3513 {
3514     Volume *retVal;
3515     VOL_LOCK;
3516     retVal = VAttachVolume_r(ec, volumeId, mode);
3517     VOL_UNLOCK;
3518     return retVal;
3519 }
3520
3521 Volume *
3522 VAttachVolume_r(Error * ec, VolumeId volumeId, int mode)
3523 {
3524     char *part, *name;
3525     VGetVolumePath(ec, volumeId, &part, &name);
3526     if (*ec) {
3527         Volume *vp;
3528         Error error;
3529         vp = VGetVolume_r(&error, volumeId);
3530         if (vp) {
3531             osi_Assert(V_inUse(vp) == 0);
3532             VDetachVolume_r(ec, vp);
3533         }
3534         return NULL;
3535     }
3536     return VAttachVolumeByName_r(ec, part, name, mode);
3537 }
3538
3539 /* Increment a reference count to a volume, sans context swaps.  Requires
3540  * possibly reading the volume header in from the disk, since there's
3541  * an invariant in the volume package that nUsers>0 ==> vp->header is valid.
3542  *
3543  * N.B. This call can fail if we can't read in the header!!  In this case
3544  * we still guarantee we won't context swap, but the ref count won't be
3545  * incremented (otherwise we'd violate the invariant).
3546  */
3547 /* NOTE: with the demand attach fileserver extensions, the global lock
3548  * is dropped within VHold */
3549 #ifdef AFS_DEMAND_ATTACH_FS
3550 static int
3551 VHold_r(Volume * vp)
3552 {
3553     Error error;
3554
3555     VCreateReservation_r(vp);
3556     VWaitExclusiveState_r(vp);
3557
3558     LoadVolumeHeader(&error, vp);
3559     if (error) {
3560         VCancelReservation_r(vp);
3561         return error;
3562     }
3563     vp->nUsers++;
3564     VCancelReservation_r(vp);
3565     return 0;
3566 }
3567 #else /* AFS_DEMAND_ATTACH_FS */
3568 static int
3569 VHold_r(Volume * vp)
3570 {
3571     Error error;
3572
3573     LoadVolumeHeader(&error, vp);
3574     if (error)
3575         return error;
3576     vp->nUsers++;
3577     return 0;
3578 }
3579 #endif /* AFS_DEMAND_ATTACH_FS */
3580
3581 /**** volume timeout-related stuff ****/
3582
3583 #ifdef AFS_PTHREAD_ENV
3584
3585 static struct timespec *shutdown_timeout;
3586 static pthread_once_t shutdown_timeout_once = PTHREAD_ONCE_INIT;
3587
3588 static_inline int
3589 VTimedOut(const struct timespec *ts)
3590 {
3591     struct timeval tv;
3592     int code;
3593
3594     if (ts->tv_sec == 0) {
3595         /* short-circuit; this will have always timed out */
3596         return 1;
3597     }
3598
3599     code = gettimeofday(&tv, NULL);
3600     if (code) {
3601         Log("Error %d from gettimeofday, assuming we have not timed out\n", errno);
3602         /* assume no timeout; failure mode is we just wait longer than normal
3603          * instead of returning errors when we shouldn't */
3604         return 0;
3605     }
3606
3607     if (tv.tv_sec < ts->tv_sec ||
3608         (tv.tv_sec == ts->tv_sec && tv.tv_usec*1000 < ts->tv_nsec)) {
3609
3610         return 0;
3611     }
3612
3613     return 1;
3614 }
3615
3616 /**
3617  * Calculate an absolute timeout.
3618  *
3619  * @param[out] ts  A timeout that is "timeout" seconds from now, if we return
3620  *                 NULL, the memory is not touched
3621  * @param[in]  timeout  How long the timeout should be from now
3622  *
3623  * @return timeout to use
3624  *  @retval NULL      no timeout; wait forever
3625  *  @retval non-NULL  the given value for "ts"
3626  *
3627  * @internal
3628  */
3629 static struct timespec *
3630 VCalcTimeout(struct timespec *ts, afs_int32 timeout)
3631 {
3632     struct timeval now;
3633     int code;
3634
3635     if (timeout < 0) {
3636         return NULL;
3637     }
3638
3639     if (timeout == 0) {
3640         ts->tv_sec = ts->tv_nsec = 0;
3641         return ts;
3642     }
3643
3644     code = gettimeofday(&now, NULL);
3645     if (code) {
3646         Log("Error %d from gettimeofday, falling back to 'forever' timeout\n", errno);
3647         return NULL;
3648     }
3649
3650     ts->tv_sec = now.tv_sec + timeout;
3651     ts->tv_nsec = now.tv_usec * 1000;
3652
3653     return ts;
3654 }
3655
3656 /**
3657  * Initialize the shutdown_timeout global.
3658  */
3659 static void
3660 VShutdownTimeoutInit(void)
3661 {
3662     struct timespec *ts;
3663
3664     ts = malloc(sizeof(*ts));
3665
3666     shutdown_timeout = VCalcTimeout(ts, vol_opts.offline_shutdown_timeout);
3667
3668     if (!shutdown_timeout) {
3669         free(ts);
3670     }
3671 }
3672
3673 /**
3674  * Figure out the timeout that should be used for waiting for offline volumes.
3675  *
3676  * @param[out] ats  Storage space for a local timeout value if needed
3677  *
3678  * @return The timeout value that should be used
3679  *   @retval NULL      No timeout; wait forever for offlining volumes
3680  *   @retval non-NULL  A pointer to the absolute time that should be used as
3681  *                     the deadline for waiting for offlining volumes.
3682  *
3683  * @note If we return non-NULL, the pointer we return may or may not be the
3684  *       same as "ats"
3685  */
3686 static const struct timespec *
3687 VOfflineTimeout(struct timespec *ats)
3688 {
3689     if (vol_shutting_down) {
3690         osi_Assert(pthread_once(&shutdown_timeout_once, VShutdownTimeoutInit) == 0);
3691         return shutdown_timeout;
3692     } else {
3693         return VCalcTimeout(ats, vol_opts.offline_timeout);
3694     }
3695 }
3696
3697 #else /* AFS_PTHREAD_ENV */
3698
3699 /* Waiting a certain amount of time for offlining volumes is not supported
3700  * for LWP due to a lack of primitives. So, we never time out */
3701 # define VTimedOut(x) (0)
3702 # define VOfflineTimeout(x) (NULL)
3703
3704 #endif /* !AFS_PTHREAD_ENV */
3705
3706 #if 0
3707 static int
3708 VHold(Volume * vp)
3709 {
3710     int retVal;
3711     VOL_LOCK;
3712     retVal = VHold_r(vp);
3713     VOL_UNLOCK;
3714     return retVal;
3715 }
3716 #endif
3717
3718 static afs_int32
3719 VIsGoingOffline_r(struct Volume *vp)
3720 {
3721     afs_int32 code = 0;
3722
3723     if (vp->goingOffline) {
3724         if (vp->specialStatus) {
3725             code = vp->specialStatus;
3726         } else if (V_inService(vp) == 0 || V_blessed(vp) == 0) {
3727             code = VNOVOL;
3728         } else {
3729             code = VOFFLINE;
3730         }
3731     }
3732
3733     return code;
3734 }
3735
3736 /**
3737  * Tell the caller if a volume is waiting to go offline.
3738  *
3739  * @param[in] vp  The volume we want to know about
3740  *
3741  * @return volume status
3742  *   @retval 0 volume is not waiting to go offline, go ahead and use it
3743  *   @retval nonzero volume is waiting to offline, and give the returned code
3744  *           as an error to anyone accessing the volume
3745  *
3746  * @pre VOL_LOCK is NOT held
3747  * @pre caller holds a heavyweight reference on vp
3748  */
3749 afs_int32
3750 VIsGoingOffline(struct Volume *vp)
3751 {
3752     afs_int32 code;
3753
3754     VOL_LOCK;
3755     code = VIsGoingOffline_r(vp);
3756     VOL_UNLOCK;
3757
3758     return code;
3759 }
3760
3761 /**
3762  * Register an RX call with a volume.
3763  *
3764  * @param[inout] ec        Error code; if unset when passed in, may be set if
3765  *                         the volume starts going offline
3766  * @param[out]   client_ec @see GetVolume
3767  * @param[in] vp   Volume struct
3768  * @param[in] cbv  VCallByVol struct containing the RX call to register
3769  *
3770  * @pre VOL_LOCK held
3771  * @pre caller holds heavy ref on vp
3772  *
3773  * @internal
3774  */
3775 static void
3776 VRegisterCall_r(Error *ec, Error *client_ec, Volume *vp, struct VCallByVol *cbv)
3777 {
3778     if (vp && cbv) {
3779 #ifdef AFS_DEMAND_ATTACH_FS
3780         if (!*ec) {
3781             /* just in case the volume started going offline after we got the
3782              * reference to it... otherwise, if the volume started going
3783              * offline right at the end of GetVolume(), we might race with the
3784              * RX call scanner, and return success and add our cbv to the
3785              * rx_call_list _after_ the scanner has scanned the list. */
3786             *ec = VIsGoingOffline_r(vp);
3787             if (client_ec) {
3788                 *client_ec = *ec;
3789             }
3790         }
3791
3792         while (V_attachState(vp) == VOL_STATE_SCANNING_RXCALLS) {
3793             VWaitStateChange_r(vp);
3794         }
3795 #endif /* AFS_DEMAND_ATTACH_FS */
3796
3797         queue_Prepend(&vp->rx_call_list, cbv);
3798     }
3799 }
3800
3801 /**
3802  * Deregister an RX call with a volume.
3803  *
3804  * @param[in] vp   Volume struct
3805  * @param[in] cbv  VCallByVol struct containing the RX call to deregister
3806  *
3807  * @pre VOL_LOCK held
3808  * @pre caller holds heavy ref on vp
3809  *
3810  * @internal
3811  */
3812 static void
3813 VDeregisterCall_r(Volume *vp, struct VCallByVol *cbv)
3814 {
3815     if (cbv && queue_IsOnQueue(cbv)) {
3816 #ifdef AFS_DEMAND_ATTACH_FS
3817         while (V_attachState(vp) == VOL_STATE_SCANNING_RXCALLS) {
3818             VWaitStateChange_r(vp);
3819         }
3820 #endif /* AFS_DEMAND_ATTACH_FS */
3821
3822         queue_Remove(cbv);
3823     }
3824 }
3825
3826 /***************************************************/
3827 /* get and put volume routines                     */
3828 /***************************************************/
3829
3830 /**
3831  * put back a heavyweight reference to a volume object.
3832  *
3833  * @param[in] vp  volume object pointer
3834  *
3835  * @pre VOL_LOCK held
3836  *
3837  * @post heavyweight volume reference put back.
3838  *       depending on state, volume may have been taken offline,
3839  *       detached, salvaged, freed, etc.
3840  *
3841  * @internal volume package internal use only
3842  */
3843 void
3844 VPutVolume_r(Volume * vp)
3845 {
3846     osi_Assert(--vp->nUsers >= 0);
3847     if (vp->nUsers == 0) {
3848         VCheckOffline(vp);
3849         ReleaseVolumeHeader(vp->header);
3850 #ifdef AFS_DEMAND_ATTACH_FS
3851         if (!VCheckDetach(vp)) {
3852             VCheckSalvage(vp);
3853             VCheckFree(vp);
3854         }
3855 #else /* AFS_DEMAND_ATTACH_FS */
3856         VCheckDetach(vp);
3857 #endif /* AFS_DEMAND_ATTACH_FS */
3858     }
3859 }
3860
3861 void
3862 VPutVolume(Volume * vp)
3863 {
3864     VOL_LOCK;
3865     VPutVolume_r(vp);
3866     VOL_UNLOCK;
3867 }
3868
3869 /**
3870  * Puts a volume reference obtained with VGetVolumeWithCall.
3871  *
3872  * @param[in] vp  Volume struct
3873  * @param[in] cbv VCallByVol struct given to VGetVolumeWithCall, or NULL if none
3874  *
3875  * @pre VOL_LOCK is NOT held
3876  */
3877 void
3878 VPutVolumeWithCall(Volume *vp, struct VCallByVol *cbv)
3879 {
3880     VOL_LOCK;
3881     VDeregisterCall_r(vp, cbv);
3882     VPutVolume_r(vp);
3883     VOL_UNLOCK;
3884 }
3885
3886 /* Get a pointer to an attached volume.  The pointer is returned regardless
3887    of whether or not the volume is in service or on/off line.  An error
3888    code, however, is returned with an indication of the volume's status */
3889 Volume *
3890 VGetVolume(Error * ec, Error * client_ec, VolId volumeId)
3891 {
3892     Volume *retVal;
3893     VOL_LOCK;
3894     retVal = GetVolume(ec, client_ec, volumeId, NULL, 0);
3895     VOL_UNLOCK;
3896     return retVal;
3897 }
3898
3899 /**
3900  * Get a volume reference associated with an RX call.
3901  *
3902  * @param[out] ec @see GetVolume
3903  * @param[out] client_ec @see GetVolume
3904  * @param[in] volumeId @see GetVolume
3905  * @param[in] ts  How long to wait for going-offline volumes (absolute time).
3906  *                If NULL, wait forever. If ts->tv_sec == 0, return immediately
3907  *                with an error if the volume is going offline.
3908  * @param[in] cbv Contains an RX call to be associated with this volume
3909  *                reference. This call may be interrupted if the volume is
3910  *                requested to go offline while we hold a ref on it. Give NULL
3911  *                to not associate an RX call with this reference.
3912  *
3913  * @return @see GetVolume
3914  *
3915  * @note for LWP builds, ts must be NULL
3916  *
3917  * @note A reference obtained with this function MUST be put back with
3918  *       VPutVolumeWithCall
3919  */
3920 Volume *
3921 VGetVolumeWithCall(Error * ec, Error * client_ec, VolId volumeId,
3922                    const struct timespec *ts, struct VCallByVol *cbv)
3923 {
3924     Volume *retVal;
3925     VOL_LOCK;
3926     retVal = GetVolume(ec, client_ec, volumeId, NULL, ts);
3927     VRegisterCall_r(ec, client_ec, retVal, cbv);
3928     VOL_UNLOCK;
3929     return retVal;
3930 }
3931
3932 Volume *
3933 VGetVolume_r(Error * ec, VolId volumeId)
3934 {
3935     return GetVolume(ec, NULL, volumeId, NULL, NULL);
3936 }
3937
3938 /* try to get a volume we've previously looked up */
3939 /* for demand attach fs, caller MUST NOT hold a ref count on vp */
3940 Volume *
3941 VGetVolumeByVp_r(Error * ec, Volume * vp)
3942 {
3943     return GetVolume(ec, NULL, vp->hashid, vp, NULL);
3944 }
3945
3946 /**
3947  * private interface for getting a volume handle
3948  *
3949  * @param[out] ec         error code (0 if no error)
3950  * @param[out] client_ec  wire error code to be given to clients
3951  * @param[in]  volumeId   ID of the volume we want
3952  * @param[in]  hint       optional hint for hash lookups, or NULL
3953  * @param[in]  timeout    absolute deadline for waiting for the volume to go
3954  *                        offline, if it is going offline. NULL to wait forever.
3955  *
3956  * @return a volume handle for the specified volume
3957  *  @retval NULL an error occurred, or the volume is in such a state that
3958  *               we cannot load a header or return any volume struct
3959  *
3960  * @note for DAFS, caller must NOT hold a ref count on 'hint'
3961  *
3962  * @note 'timeout' is only checked if the volume is actually going offline; so
3963  *       if you pass timeout->tv_sec = 0, this will exhibit typical
3964  *       nonblocking behavior.
3965  *
3966  * @note for LWP builds, 'timeout' must be NULL
3967  */
3968 static Volume *
3969 GetVolume(Error * ec, Error * client_ec, VolId volumeId, Volume * hint,
3970           const struct timespec *timeout)
3971 {
3972     Volume *vp = hint;
3973     /* pull this profiling/debugging code out of regular builds */
3974 #ifdef notdef
3975 #define VGET_CTR_INC(x) x++
3976     unsigned short V0 = 0, V1 = 0, V2 = 0, V3 = 0, V5 = 0, V6 =
3977         0, V7 = 0, V8 = 0, V9 = 0;
3978     unsigned short V10 = 0, V11 = 0, V12 = 0, V13 = 0, V14 = 0, V15 = 0;
3979 #else
3980 #define VGET_CTR_INC(x)
3981 #endif
3982 #ifdef AFS_DEMAND_ATTACH_FS
3983     Volume *avp, * rvp = hint;
3984 #endif
3985
3986     /*
3987      * if VInit is zero, the volume package dynamic
3988      * data structures have not been initialized yet,
3989      * and we must immediately return an error
3990      */
3991     if (VInit == 0) {
3992         vp = NULL;
3993         *ec = VOFFLINE;
3994         if (client_ec) {
3995             *client_ec = VOFFLINE;
3996         }
3997         goto not_inited;
3998     }
3999
4000 #ifdef AFS_DEMAND_ATTACH_FS
4001     if (rvp) {
4002         VCreateReservation_r(rvp);
4003     }
4004 #endif /* AFS_DEMAND_ATTACH_FS */
4005
4006     for (;;) {
4007         *ec = 0;
4008         if (client_ec)
4009             *client_ec = 0;
4010         VGET_CTR_INC(V0);
4011
4012         vp = VLookupVolume_r(ec, volumeId, vp);
4013         if (*ec) {
4014             vp = NULL;
4015             break;
4016         }
4017
4018 #ifdef AFS_DEMAND_ATTACH_FS
4019         if (rvp && (rvp != vp)) {
4020             /* break reservation on old vp */
4021             VCancelReservation_r(rvp);
4022             rvp = NULL;
4023         }
4024 #endif /* AFS_DEMAND_ATTACH_FS */
4025
4026         if (!vp) {
4027             VGET_CTR_INC(V1);
4028             if (VInit < 2) {
4029                 VGET_CTR_INC(V2);
4030                 /* Until we have reached an initialization level of 2
4031                  * we don't know whether this volume exists or not.
4032                  * We can't sleep and retry later because before a volume
4033                  * is attached, the caller tries to get it first.  Just
4034                  * return VOFFLINE and the caller can choose whether to
4035                  * retry the command or not. */
4036                 *ec = VOFFLINE;
4037                 break;
4038             }
4039
4040             *ec = VNOVOL;
4041             break;
4042         }
4043
4044         VGET_CTR_INC(V3);
4045         IncUInt64(&VStats.hdr_gets);
4046
4047 #ifdef AFS_DEMAND_ATTACH_FS
4048         /* block if someone else is performing an exclusive op on this volume */
4049         if (rvp != vp) {
4050             rvp = vp;
4051             VCreateReservation_r(rvp);
4052         }
4053         VWaitExclusiveState_r(vp);
4054
4055         /* short circuit with VNOVOL in the following circumstances:
4056          *
4057          *   - VOL_STATE_ERROR
4058          *   - VOL_STATE_SHUTTING_DOWN
4059          */
4060         if ((V_attachState(vp) == VOL_STATE_ERROR) ||
4061             (V_attachState(vp) == VOL_STATE_SHUTTING_DOWN)) {
4062             *ec = VNOVOL;
4063             vp = NULL;
4064             break;
4065         }
4066
4067         /*
4068          * short circuit with VOFFLINE for VOL_STATE_UNATTACHED/GOING_OFFLINE and
4069          *                    VNOVOL   for VOL_STATE_DELETED
4070          */
4071        if ((V_attachState(vp) == VOL_STATE_UNATTACHED) ||
4072            (V_attachState(vp) == VOL_STATE_GOING_OFFLINE) ||
4073            (V_attachState(vp) == VOL_STATE_DELETED)) {
4074            if (vp->specialStatus) {
4075                *ec = vp->specialStatus;
4076            } else if (V_attachState(vp) == VOL_STATE_DELETED) {
4077                *ec = VNOVOL;
4078            } else {
4079                *ec = VOFFLINE;
4080            }
4081            vp = NULL;
4082            break;
4083        }
4084
4085         /* allowable states:
4086          *   - PREATTACHED
4087          *   - ATTACHED
4088          *   - SALVAGING
4089          *   - SALVAGE_REQ
4090          */
4091
4092         if (vp->salvage.requested) {
4093             VUpdateSalvagePriority_r(vp);
4094         }
4095
4096         if (V_attachState(vp) == VOL_STATE_PREATTACHED) {
4097             if (vp->specialStatus) {
4098                 *ec = vp->specialStatus;
4099                 vp = NULL;
4100                 break;
4101             }
4102             avp = VAttachVolumeByVp_r(ec, vp, 0);
4103             if (avp) {
4104                 if (vp != avp) {
4105                     /* VAttachVolumeByVp_r can return a pointer
4106                      * != the vp passed to it under certain
4107                      * conditions; make sure we don't leak
4108                      * reservations if that happens */
4109                     vp = avp;
4110                     VCancelReservation_r(rvp);
4111                     rvp = avp;
4112                     VCreateReservation_r(rvp);
4113                 }
4114                 VPutVolume_r(avp);
4115             }
4116             if (*ec) {
4117                 int endloop = 0;
4118                 switch (*ec) {
4119                 case VSALVAGING:
4120                     break;
4121                 case VOFFLINE:
4122                     endloop = 1;
4123                     if (vp->specialStatus) {
4124                         *ec = vp->specialStatus;
4125                     }
4126                     break;
4127
4128                 default:
4129                     if (vp->specialStatus) {
4130                         *ec = vp->specialStatus;
4131                     } else {
4132                         *ec = VNOVOL;
4133                     }
4134                     endloop = 1;
4135                 }
4136                 if (endloop) {
4137                     vp = NULL;
4138                     break;
4139                 }
4140             }
4141         }
4142
4143         if (VIsSalvaging(vp) || (*ec == VSALVAGING)) {
4144             if (client_ec) {
4145                 /* see CheckVnode() in afsfileprocs.c for an explanation
4146                  * of this error code logic */
4147                 afs_uint32 now = FT_ApproxTime();
4148                 if ((vp->stats.last_salvage + (10 * 60)) >= now) {
4149                     *client_ec = VBUSY;
4150                 } else {
4151                     *client_ec = VRESTARTING;
4152                 }
4153             }
4154             *ec = VSALVAGING;
4155             vp = NULL;
4156             break;
4157         }
4158
4159         if (VIsErrorState(V_attachState(vp))) {
4160             /* make sure we don't take a vp in VOL_STATE_ERROR state and use
4161              * it, or transition it out of that state */
4162             if (!*ec) {
4163                 *ec = VNOVOL;
4164             }
4165             vp = NULL;
4166             break;
4167         }
4168
4169         /*
4170          * this test MUST happen after VAttachVolymeByVp, so we have no
4171          * conflicting vol op. (attach2 would have errored out if we had one;
4172          * specifically attach_check_vop must have detected a conflicting vop)
4173          */
4174          osi_Assert(!vp->pending_vol_op || vp->pending_vol_op->vol_op_state == FSSYNC_VolOpRunningOnline);
4175
4176 #endif /* AFS_DEMAND_ATTACH_FS */
4177
4178         LoadVolumeHeader(ec, vp);
4179         if (*ec) {
4180             VGET_CTR_INC(V6);
4181             /* Only log the error if it was a totally unexpected error.  Simply
4182              * a missing inode is likely to be caused by the volume being deleted */
4183             if (errno != ENXIO || LogLevel)
4184                 Log("Volume %u: couldn't reread volume header\n",
4185                     vp->hashid);
4186 #ifdef AFS_DEMAND_ATTACH_FS
4187             if (VCanScheduleSalvage()) {
4188                 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0 /*flags*/);
4189             } else {
4190                 FreeVolume(vp);
4191                 vp = NULL;
4192             }
4193 #else /* AFS_DEMAND_ATTACH_FS */
4194             FreeVolume(vp);
4195             vp = NULL;
4196 #endif /* AFS_DEMAND_ATTACH_FS */
4197             break;
4198         }
4199
4200         VGET_CTR_INC(V7);
4201         if (vp->shuttingDown) {
4202             VGET_CTR_INC(V8);
4203             *ec = VNOVOL;
4204             vp = NULL;
4205             break;
4206         }
4207
4208         if (programType == fileServer) {
4209             VGET_CTR_INC(V9);
4210             if (vp->goingOffline) {
4211                 if (timeout && VTimedOut(timeout)) {
4212                     /* we've timed out; don't wait for the vol */
4213                 } else {
4214                     VGET_CTR_INC(V10);
4215 #ifdef AFS_DEMAND_ATTACH_FS
4216                     /* wait for the volume to go offline */
4217                     if (V_attachState(vp) == VOL_STATE_GOING_OFFLINE) {
4218                         VTimedWaitStateChange_r(vp, timeout, NULL);
4219                     }
4220 #elif defined(AFS_PTHREAD_ENV)
4221                     VOL_CV_TIMEDWAIT(&vol_put_volume_cond, timeout, NULL);
4222 #else /* AFS_PTHREAD_ENV */
4223                     /* LWP has no timed wait, so the caller better not be
4224                      * expecting one */
4225                     osi_Assert(!timeout);
4226                     LWP_WaitProcess(VPutVolume);
4227 #endif /* AFS_PTHREAD_ENV */
4228                     continue;
4229                 }
4230             }
4231             if (vp->specialStatus) {
4232                 VGET_CTR_INC(V11);
4233                 *ec = vp->specialStatus;
4234             } else if (V_inService(vp) == 0 || V_blessed(vp) == 0) {
4235                 VGET_CTR_INC(V12);
4236                 *ec = VNOVOL;
4237             } else if (V_inUse(vp) == 0 || vp->goingOffline) {
4238                 VGET_CTR_INC(V13);
4239                 *ec = VOFFLINE;
4240             } else {
4241                 VGET_CTR_INC(V14);
4242             }
4243         }
4244         break;
4245     }
4246     VGET_CTR_INC(V15);
4247
4248 #ifdef AFS_DEMAND_ATTACH_FS
4249     /* if no error, bump nUsers */
4250     if (vp) {
4251         vp->nUsers++;
4252         VLRU_UpdateAccess_r(vp);
4253     }
4254     if (rvp) {
4255         VCancelReservation_r(rvp);
4256         rvp = NULL;
4257     }
4258     if (client_ec && !*client_ec) {
4259         *client_ec = *ec;
4260     }
4261 #else /* AFS_DEMAND_ATTACH_FS */
4262     /* if no error, bump nUsers */
4263     if (vp) {
4264         vp->nUsers++;
4265     }
4266     if (client_ec) {
4267         *client_ec = *ec;
4268     }
4269 #endif /* AFS_DEMAND_ATTACH_FS */
4270
4271  not_inited:
4272     osi_Assert(vp || *ec);
4273     return vp;
4274 }
4275
4276
4277 /***************************************************/
4278 /* Volume offline/detach routines                  */
4279 /***************************************************/
4280
4281 /* caller MUST hold a heavyweight ref on vp */
4282 #ifdef AFS_DEMAND_ATTACH_FS
4283 void
4284 VTakeOffline_r(Volume * vp)
4285 {
4286     Error error;
4287
4288     osi_Assert(vp->nUsers > 0);
4289     osi_Assert(programType == fileServer);
4290
4291     VCreateReservation_r(vp);
4292     VWaitExclusiveState_r(vp);
4293
4294     vp->goingOffline = 1;
4295     V_needsSalvaged(vp) = 1;
4296
4297     VRequestSalvage_r(&error, vp, SALVSYNC_ERROR, 0);
4298     VCancelReservation_r(vp);
4299 }
4300 #else /* AFS_DEMAND_ATTACH_FS */
4301 void
4302 VTakeOffline_r(Volume * vp)
4303 {
4304     osi_Assert(vp->nUsers > 0);
4305     osi_Assert(programType == fileServer);
4306
4307     vp->goingOffline = 1;
4308     V_needsSalvaged(vp) = 1;
4309 }
4310 #endif /* AFS_DEMAND_ATTACH_FS */
4311
4312 void
4313 VTakeOffline(Volume * vp)
4314 {
4315     VOL_LOCK;
4316     VTakeOffline_r(vp);
4317     VOL_UNLOCK;
4318 }
4319
4320 /**
4321  * force a volume offline.
4322  *
4323  * @param[in] vp     volume object pointer
4324  * @param[in] flags  flags (see note below)
4325  *
4326  * @note the flag VOL_FORCEOFF_NOUPDATE is a recursion control flag
4327  *       used when VUpdateVolume_r needs to call VForceOffline_r
4328  *       (which in turn would normally call VUpdateVolume_r)
4329  *
4330  * @see VUpdateVolume_r
4331  *
4332  * @pre VOL_LOCK must be held.
4333  *      for DAFS, caller must hold ref.
4334  *
4335  * @note for DAFS, it _is safe_ to call this function from an
4336  *       exclusive state
4337  *
4338  * @post needsSalvaged flag is set.
4339  *       for DAFS, salvage is requested.
4340  *       no further references to the volume through the volume
4341  *       package will be honored.
4342  *       all file descriptor and vnode caches are invalidated.
4343  *
4344  * @warning this is a heavy-handed interface.  it results in
4345  *          a volume going offline regardless of the current
4346  *          reference count state.
4347  *
4348  * @internal  volume package internal use only
4349  */
4350 void
4351 VForceOffline_r(Volume * vp, int flags)
4352 {
4353     Error error;
4354     if (!V_inUse(vp)) {
4355 #ifdef AFS_DEMAND_ATTACH_FS
4356         VChangeState_r(vp, VOL_STATE_ERROR);
4357 #endif
4358         return;
4359     }
4360
4361     strcpy(V_offlineMessage(vp),
4362            "Forced offline due to internal error: volume needs to be salvaged");
4363     Log("Volume %u forced offline:  it needs salvaging!\n", V_id(vp));
4364
4365     V_inUse(vp) = 0;
4366     vp->goingOffline = 0;
4367     V_needsSalvaged(vp) = 1;
4368     if (!(flags & VOL_FORCEOFF_NOUPDATE)) {
4369         VUpdateVolume_r(&error, vp, VOL_UPDATE_NOFORCEOFF);
4370     }
4371
4372 #ifdef AFS_DEMAND_ATTACH_FS
4373     VRequestSalvage_r(&error, vp, SALVSYNC_ERROR, 0 /*flags*/);
4374 #endif /* AFS_DEMAND_ATTACH_FS */
4375
4376 #ifdef AFS_PTHREAD_ENV
4377     CV_BROADCAST(&vol_put_volume_cond);
4378 #else /* AFS_PTHREAD_ENV */
4379     LWP_NoYieldSignal(VPutVolume);
4380 #endif /* AFS_PTHREAD_ENV */
4381
4382     VReleaseVolumeHandles_r(vp);
4383 }
4384
4385 /**
4386  * force a volume offline.
4387  *
4388  * @param[in] vp  volume object pointer
4389  *
4390  * @see VForceOffline_r
4391  */
4392 void
4393 VForceOffline(Volume * vp)
4394 {
4395     VOL_LOCK;
4396     VForceOffline_r(vp, 0);
4397     VOL_UNLOCK;
4398 }
4399
4400 /**
4401  * Iterate over the RX calls associated with a volume, and interrupt them.
4402  *
4403  * @param[in] vp The volume whose RX calls we want to scan
4404  *
4405  * @pre VOL_LOCK held
4406  */
4407 static void
4408 VScanCalls_r(struct Volume *vp)
4409 {
4410     struct VCallByVol *cbv, *ncbv;
4411     afs_int32 err;
4412 #ifdef AFS_DEMAND_ATTACH_FS
4413     VolState state_save;
4414 #endif
4415
4416     if (queue_IsEmpty(&vp->rx_call_list))
4417         return; /* no calls to interrupt */
4418     if (!vol_opts.interrupt_rxcall)
4419         return; /* we have no function with which to interrupt calls */
4420     err = VIsGoingOffline_r(vp);
4421     if (!err)
4422         return; /* we're not going offline anymore */
4423
4424 #ifdef AFS_DEMAND_ATTACH_FS
4425     VWaitExclusiveState_r(vp);
4426     state_save = VChangeState_r(vp, VOL_STATE_SCANNING_RXCALLS);
4427     VOL_UNLOCK;
4428 #endif /* AFS_DEMAND_ATTACH_FS */
4429
4430     for(queue_Scan(&vp->rx_call_list, cbv, ncbv, VCallByVol)) {
4431         if (LogLevel > 0) {
4432             struct rx_peer *peer;
4433             char hoststr[16];
4434             peer = rx_PeerOf(rx_ConnectionOf(cbv->call));
4435
4436             Log("Offlining volume %lu while client %s:%u is trying to read "
4437                 "from it; kicking client off with error %ld\n",
4438                 (long unsigned) vp->hashid,
4439                 afs_inet_ntoa_r(rx_HostOf(peer), hoststr),
4440                 (unsigned) ntohs(rx_PortOf(peer)),
4441                 (long) err);
4442         }
4443         (*vol_opts.interrupt_rxcall) (cbv->call, err);
4444     }
4445
4446 #ifdef AFS_DEMAND_ATTACH_FS
4447     VOL_LOCK;
4448     VChangeState_r(vp, state_save);
4449 #endif /* AFS_DEMAND_ATTACH_FS */
4450 }
4451
4452 #ifdef AFS_DEMAND_ATTACH_FS
4453 /**
4454  * Wait for a vp to go offline.
4455  *
4456  * @param[out] ec 1 if a salvage on the volume has been requested and
4457  *                salvok == 0, 0 otherwise
4458  * @param[in] vp  The volume to wait for
4459  * @param[in] salvok  If 0, we return immediately with *ec = 1 if the volume
4460  *                    has been requested to salvage. Otherwise we keep waiting
4461  *                    until the volume has gone offline.
4462  *
4463  * @pre VOL_LOCK held
4464  * @pre caller holds a lightweight ref on vp
4465  *
4466  * @note DAFS only
4467  */
4468 static void
4469 VWaitForOfflineByVp_r(Error *ec, struct Volume *vp, int salvok)
4470 {
4471     struct timespec timeout_ts;
4472     const struct timespec *ts;
4473     int timedout = 0;
4474
4475     ts = VOfflineTimeout(&timeout_ts);
4476
4477     *ec = 0;
4478
4479     while (!VIsOfflineState(V_attachState(vp)) && !timedout) {
4480         if (!salvok && vp->salvage.requested) {
4481             *ec = 1;
4482             return;
4483         }
4484         VTimedWaitStateChange_r(vp, ts, &timedout);
4485     }
4486     if (!timedout) {
4487         /* we didn't time out, so the volume must be offline, so we're done */
4488         return;
4489     }
4490
4491     /* If we got here, we timed out waiting for the volume to go offline.
4492      * Kick off the accessing RX calls and wait again */
4493
4494     VScanCalls_r(vp);
4495
4496     while (!VIsOfflineState(V_attachState(vp))) {
4497         if (!salvok && vp->salvage.requested) {
4498             *ec = 1;
4499             return;
4500         }
4501
4502         VWaitStateChange_r(vp);
4503     }
4504 }
4505
4506 #else /* AFS_DEMAND_ATTACH_FS */
4507
4508 /**
4509  * Wait for a volume to go offline.
4510  *
4511  * @pre VOL_LOCK held
4512  *
4513  * @note non-DAFS only (for DAFS, use @see WaitForOfflineByVp_r)
4514  */
4515 static void
4516 VWaitForOffline_r(Error *ec, VolumeId volid)
4517 {
4518     struct Volume *vp;
4519     const struct timespec *ts;
4520 #ifdef AFS_PTHREAD_ENV
4521     struct timespec timeout_ts;
4522 #endif
4523
4524     ts = VOfflineTimeout(&timeout_ts);
4525
4526     vp = GetVolume(ec, NULL, volid, NULL, ts);
4527     if (!vp) {
4528         /* error occurred so bad that we can't even get a vp; we have no
4529          * information on the vol so we don't know whether to wait, so just
4530          * return */
4531         return;
4532     }
4533     if (!VIsGoingOffline_r(vp)) {
4534         /* volume is no longer going offline, so we're done */
4535         VPutVolume_r(vp);
4536         return;
4537     }
4538