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