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