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