4394ffd5c779f27e498b75063dce5f605289324a
[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
10 /* 1/1/89: NB:  this stuff is all going to be replaced.  Don't take it too seriously */
11 /*
12
13         System:         VICE-TWO
14         Module:         volume.c
15         Institution:    The Information Technology Center, Carnegie-Mellon University
16
17  */
18
19 #include <afsconfig.h>
20 #include <afs/param.h>
21
22 RCSID("$Header$");
23
24 #include <rx/xdr.h>
25 #include <afs/afsint.h>
26 #include <ctype.h>
27 #ifndef AFS_NT40_ENV
28 #include <sys/param.h>
29 #if !defined(AFS_SGI_ENV)
30 #ifdef  AFS_OSF_ENV
31 #include <ufs/fs.h>
32 #else   /* AFS_OSF_ENV */
33 #ifdef AFS_VFSINCL_ENV
34 #define VFS
35 #ifdef  AFS_SUN5_ENV
36 #include <sys/fs/ufs_fs.h>
37 #else
38 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
39 #include <ufs/ufs/dinode.h>
40 #include <ufs/ffs/fs.h>
41 #else
42 #include <ufs/fs.h>
43 #endif
44 #endif
45 #else /* AFS_VFSINCL_ENV */
46 #if !defined(AFS_AIX_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV)
47 #include <sys/fs.h>
48 #endif
49 #endif /* AFS_VFSINCL_ENV */
50 #endif  /* AFS_OSF_ENV */
51 #endif /* AFS_SGI_ENV */
52 #endif /* AFS_NT40_ENV */
53 #include <errno.h>
54 #include <sys/stat.h>
55 #include <stdio.h>
56 #ifdef AFS_NT40_ENV
57 #include <fcntl.h>
58 #else
59 #include <sys/file.h>
60 #endif
61 #include <dirent.h>
62 #ifdef  AFS_AIX_ENV
63 #include <sys/vfs.h>
64 #include <fcntl.h>
65 #else
66 #ifdef  AFS_HPUX_ENV
67 #include <fcntl.h>
68 #include <mntent.h>
69 #else
70 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
71 #ifdef  AFS_SUN5_ENV
72 #include <sys/mnttab.h>
73 #include <sys/mntent.h>
74 #else
75 #include <mntent.h>
76 #endif
77 #else
78 #ifndef AFS_NT40_ENV
79 #if defined(AFS_SGI_ENV)
80 #include <fcntl.h>
81 #include <mntent.h>
82 #ifdef AFS_SGI_EFS_IOPS_ENV
83 #define ROOTINO EFS_ROOTINO
84 #include <sys/fs/efs.h>
85 #include "../sgiefs/efs.h" /* until 5.1 release */ 
86 #endif
87
88
89 #else
90 #ifndef AFS_LINUX20_ENV
91 #include <fstab.h> /* Need to find in libc 5, present in libc 6 */
92 #endif
93 #endif
94 #endif /* AFS_SGI_ENV */
95 #endif
96 #endif /* AFS_HPUX_ENV */
97 #endif
98 #ifndef AFS_NT40_ENV
99 #include <netdb.h>
100 #include <netinet/in.h>
101 #include <sys/wait.h>
102 #include <setjmp.h>
103 #ifndef ITIMER_REAL
104 #include <sys/time.h>
105 #endif /* ITIMER_REAL */
106 #endif /* AFS_NT40_ENV */
107 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
108 #include <string.h>
109 #else
110 #include <strings.h>
111 #endif
112
113 #include "nfs.h"
114 #include <afs/errors.h>
115 #include "lock.h"
116 #include "lwp.h"
117 #include <afs/afssyscalls.h>
118 #include "ihandle.h"
119 #ifdef AFS_NT40_ENV
120 #include <afs/afsutil.h>
121 #include <io.h>
122 #endif
123 #include "vnode.h"
124 #include "volume.h"
125 #include "partition.h"
126 #ifdef AFS_PTHREAD_ENV
127 #include <assert.h>
128 #else /* AFS_PTHREAD_ENV */
129 #include "afs/assert.h"
130 #endif /* AFS_PTHREAD_ENV */
131 #include "vutils.h"
132 #include "fssync.h"
133 #ifndef AFS_NT40_ENV
134 #include <unistd.h>
135 #endif
136
137 #ifdef AFS_PTHREAD_ENV
138 pthread_mutex_t vol_glock_mutex;
139 pthread_mutex_t vol_attach_mutex;
140 pthread_cond_t vol_put_volume_cond;
141 pthread_cond_t vol_sleep_cond;
142 #endif /* AFS_PTHREAD_ENV */
143
144 #ifdef  AFS_OSF_ENV
145 extern void *calloc(), *realloc();
146 #endif
147
148 /* Forward declarations */
149 static Volume *attach2();
150 static void FreeVolume();
151 static void VScanUpdateList();
152 static void InitLRU();
153 static int GetVolumeHeader();
154 static void ReleaseVolumeHeader();
155 static void FreeVolumeHeader();
156 static void AddVolumeToHashTable();
157 static void DeleteVolumeFromHashTable();
158 static int VHold(Volume *vp);
159 static int VHold_r(Volume *vp);
160 static void GetBitmap(Error *ec, Volume *vp, VnodeClass class);
161 static void GetVolumePath(Error *ec, VolId volumeId, char **partitionp,
162                      char **namep);
163 static void VReleaseVolumeHandles_r(Volume *vp);
164 static void VCloseVolumeHandles_r(Volume *vp);
165
166 int LogLevel; /* Vice loglevel--not defined as extern so that it will be
167                  defined when not linked with vice, XXXX */
168 ProgramType programType;        /* The type of program using the package */
169
170
171 #define VOLUME_BITMAP_GROWSIZE  16      /* bytes, => 128vnodes */
172                                         /* Must be a multiple of 4 (1 word) !!*/
173 #define VOLUME_HASH_TABLE_SIZE 128      /* Must be a power of 2!! */
174 #define VOLUME_HASH(volumeId) (volumeId&(VOLUME_HASH_TABLE_SIZE-1))
175 private Volume *VolumeHashTable[VOLUME_HASH_TABLE_SIZE];
176
177 #ifndef AFS_HAVE_FFS
178 /* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
179 ffs(x) { \
180         afs_int32 ffs_i; \
181         afs_int32 ffs_tmp = x; \
182         if (ffs_tmp == 0) return(-1); \
183         else \
184             for (ffs_i = 1;; ffs_i++) { \
185                 if (ffs_tmp & 1) return(ffs_i); \
186                 else ffs_tmp >>= 1; \
187             } \
188     }
189 #endif /* !AFS_HAVE_FFS */
190
191 struct Lock vol_listLock;               /* Lock obtained when listing volumes:  prevents a volume from being missed if the volume is attached during a list volumes */
192
193 extern struct Lock FSYNC_handler_lock;
194
195 Volume *VAttachVolumeByName();
196 Volume *VAttachVolumeByName_r();
197
198 static int TimeZoneCorrection; /* Number of seconds west of GMT */
199
200 /* Common message used when the volume goes off line */
201 char *VSalvageMessage =
202 "Files in this volume are currently unavailable; call operations";
203
204 int VInit;    /* 0 - uninitialized,
205                  1 - initialized but not all volumes have been attached,
206                  2 - initialized and all volumes have been attached,
207                  3 - initialized, all volumes have been attached, and
208                      VConnectFS() has completed. */
209
210
211 int VolumeCacheCheck;   /* Incremented everytime a volume goes on line--
212                          * used to stamp volume headers and in-core
213                          * vnodes.  When the volume goes on-line the
214                          * vnode will be invalidated */
215
216 int VolumeCacheSize = 200, VolumeGets=0, VolumeReplacements=0, Vlooks = 0;
217
218
219 int VInitVolumePackage(ProgramType pt, int nLargeVnodes, int nSmallVnodes,
220                    int connect, int volcache)
221 {
222     int errors = 0; /* Number of errors while finding vice partitions. */
223     struct timeval tv;
224     struct timezone tz;
225
226     programType = pt;
227     
228 #ifdef AFS_PTHREAD_ENV
229     assert(pthread_mutex_init(&vol_glock_mutex, NULL) == 0);
230     assert(pthread_mutex_init(&vol_attach_mutex, NULL) == 0);
231     assert(pthread_cond_init(&vol_put_volume_cond, NULL) == 0);
232     assert(pthread_cond_init(&vol_sleep_cond, NULL) == 0);
233 #else /* AFS_PTHREAD_ENV */
234     IOMGR_Initialize();
235 #endif /* AFS_PTHREAD_ENV */
236     Lock_Init(&vol_listLock);
237     Lock_Init(&FSYNC_handler_lock);
238     srandom(time(0));   /* For VGetVolumeInfo */
239     gettimeofday(&tv, &tz);
240     TimeZoneCorrection = tz.tz_minuteswest*60;
241     
242     /* Ok, we have done enough initialization that fileserver can 
243      * start accepting calls, even though the volumes may not be 
244      * available just yet.
245      */
246     VInit = 1;
247
248     if (programType == fileServer) {
249         /* File server or "stand" */
250         FSYNC_fsInit();
251     }
252
253     if (volcache > VolumeCacheSize)
254         VolumeCacheSize = volcache;
255     InitLRU(VolumeCacheSize);
256
257     VInitVnodes(vLarge, nLargeVnodes);
258     VInitVnodes(vSmall, nSmallVnodes);
259
260
261     errors = VAttachPartitions();
262     if (errors) 
263         return -1;
264
265     if (programType == fileServer) {
266         DIR *dirp;
267         struct dirent *dp;
268         struct DiskPartition *diskP;
269
270
271         /* Attach all the volumes in this partition */
272         for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
273             int nAttached = 0, nUnattached = 0;
274             dirp = opendir(VPartitionPath(diskP));
275             assert(dirp);
276             while (dp = readdir(dirp)) {
277                 char *p;
278                 p = strrchr(dp->d_name, '.');
279                 if (p != NULL && strcmp(p, VHDREXT) == 0) {
280                     Error error;
281                     Volume *vp;
282                     vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
283                                              V_VOLUPD);
284                     (*(vp?&nAttached:&nUnattached))++;
285                     if (error == VOFFLINE)
286                         Log("Volume %u stays offline (/vice/offline/%s exists)\n", 
287                             VolumeNumber(dp->d_name), dp->d_name);
288                     if (vp) {
289                         VPutVolume(vp);
290                     }
291                 }
292             }
293             Log("Partition %s: attached %d volumes; %d volumes not attached\n",
294                 diskP->name, nAttached, nUnattached);
295             closedir(dirp);
296         }
297     }
298
299     VInit = 2;  /* Initialized, and all volumes have been attached */
300     if (programType == volumeUtility && connect) {
301         if (!VConnectFS()) {
302             Log("Unable to connect to file server; aborted\n");
303             exit(1);
304         }
305     }
306     return 0;
307 }
308
309 /* This must be called by any volume utility which needs to run while the
310    file server is also running.  This is separated from VInitVolumePackage so
311    that a utility can fork--and each of the children can independently
312    initialize communication with the file server */
313 int VConnectFS(void)
314 {
315     int retVal;
316     VOL_LOCK
317     retVal = VConnectFS_r();
318     VOL_UNLOCK
319     return retVal;
320 }
321
322 int VConnectFS_r(void)
323 {
324     int rc;
325     assert(VInit == 2 && programType == volumeUtility);
326     rc = FSYNC_clientInit();
327     if (rc)
328         VInit = 3;
329     return rc;
330 }
331
332 void VDisconnectFS_r(void) {
333     assert(programType == volumeUtility);
334     FSYNC_clientFinis();
335     VInit = 2;
336 }
337
338 void VDisconnectFS(void) {
339     VOL_LOCK
340     VDisconnectFS_r();
341     VOL_UNLOCK
342 }
343
344 void VShutdown_r(void)
345 {
346     int i;
347     register Volume *vp, *np;
348     register afs_int32 code;
349
350     Log("VShutdown:  shutting down on-line volumes...\n");
351     for (i=0; i<VOLUME_HASH_TABLE_SIZE; i++) {
352         /* try to hold first volume in the hash table */
353         for(vp = VolumeHashTable[i]; vp; vp=vp->hashNext) {
354             code = VHold_r(vp);
355             if (code == 0) break;       /* got it */
356             /* otherwise we go around again, trying another volume */
357         }
358         while(vp) {
359             /* first compute np before releasing vp, in case vp disappears
360              * after releasing.  Hold it, so it doesn't disapear.  If we
361              * can't hold it, try the next one in the chain.  Invariant
362              * at the top of this loop is that vp is held (has extra ref count).
363              */
364             for(np=vp->hashNext; np; np=np->hashNext) {
365                 code = VHold_r(np);
366                 if (code == 0) break;   /* got it */
367             }
368             /* next, take the volume offline (drops reference count) */
369             VOffline_r(vp, "File server was shut down");
370             vp = np;    /* next guy to try */
371         }
372     }
373     Log("VShutdown:  complete.\n");
374 }
375
376 void VShutdown(void)
377 {
378     VOL_LOCK
379     VShutdown_r();
380     VOL_UNLOCK
381 }
382
383
384 static void ReadHeader(Error *ec, IHandle_t *h, char *to, int size,
385                      int magic, int version)
386 {
387     struct versionStamp *vsn;
388     FdHandle_t *fdP;
389
390     *ec = 0;
391     fdP = IH_OPEN(h);
392     if (fdP == NULL) {
393         *ec = VSALVAGE;
394         return;
395     }
396
397     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
398         *ec = VSALVAGE;
399         FDH_REALLYCLOSE(fdP);
400         return;
401     }
402     vsn = (struct versionStamp *) to;
403     if (FDH_READ(fdP, to, size) != size || vsn->magic != magic) {
404         *ec = VSALVAGE;
405         FDH_REALLYCLOSE(fdP);
406         return;
407     }
408     FDH_CLOSE(fdP);
409
410     /* Check is conditional, in case caller wants to inspect version himself */
411     if (version && vsn->version != version) {
412         *ec = VSALVAGE;
413     }
414 }
415
416 /* VolumeHeaderToDisk
417  * Allows for storing 64 bit inode numbers in on-disk volume header
418  * file.
419  */
420 void VolumeHeaderToDisk(VolumeDiskHeader_t *dh, VolumeHeader_t *h)
421 {
422
423     memset((char*)dh, 0, sizeof(VolumeDiskHeader_t));
424     dh->stamp = h->stamp;
425     dh->id = h->id;
426     dh->parent = h->parent;
427
428 #ifdef AFS_64BIT_IOPS_ENV
429     dh->volumeInfo_lo = (afs_int32) h->volumeInfo & 0xffffffff;
430     dh->volumeInfo_hi = (afs_int32) (h->volumeInfo >> 32) & 0xffffffff;
431     dh->smallVnodeIndex_lo = (afs_int32) h->smallVnodeIndex & 0xffffffff;
432     dh->smallVnodeIndex_hi = (afs_int32) (h->smallVnodeIndex >> 32) & 0xffffffff;
433     dh->largeVnodeIndex_lo = (afs_int32) h->largeVnodeIndex & 0xffffffff;
434     dh->largeVnodeIndex_hi = (afs_int32) (h->largeVnodeIndex >> 32) & 0xffffffff;
435     dh->linkTable_lo = (afs_int32) h->linkTable & 0xffffffff;
436     dh->linkTable_hi = (afs_int32) (h->linkTable >> 32) & 0xffffffff;
437 #else
438     dh->volumeInfo_lo = h->volumeInfo;
439     dh->smallVnodeIndex_lo = h->smallVnodeIndex;
440     dh->largeVnodeIndex_lo = h->largeVnodeIndex;
441     dh->linkTable_lo = h->linkTable;
442 #endif
443 }
444
445 /* DiskToVolumeHeader
446  * Reads volume header file from disk, convering 64 bit inodes
447  * if required. Makes the assumption that AFS has *always* 
448  * zero'd the volume header file so that high parts of inode
449  * numbers are 0 in older (SGI EFS) volume header files.
450  */
451 void DiskToVolumeHeader(VolumeHeader_t *h, VolumeDiskHeader_t *dh)
452 {
453     memset((char*)h, 0, sizeof(VolumeHeader_t));
454     h->stamp = dh->stamp;
455     h->id = dh->id;
456     h->parent = dh->parent;
457
458 #ifdef AFS_64BIT_IOPS_ENV
459     h->volumeInfo = dh->volumeInfo_lo | ((Inode)dh->volumeInfo_hi << 32);
460     
461     h->smallVnodeIndex = dh->smallVnodeIndex_lo |
462         ((Inode)dh->smallVnodeIndex_hi << 32);
463
464     h->largeVnodeIndex = dh->largeVnodeIndex_lo |
465         ((Inode)dh->largeVnodeIndex_hi << 32);
466     h->linkTable = dh->linkTable_lo |
467         ((Inode)dh->linkTable_hi << 32);
468 #else
469     h->volumeInfo = dh->volumeInfo_lo;
470     h->smallVnodeIndex = dh->smallVnodeIndex_lo;
471     h->largeVnodeIndex = dh->largeVnodeIndex_lo;
472     h->linkTable = dh->linkTable_lo;
473 #endif
474 }
475
476
477 void WriteVolumeHeader_r(ec, vp)
478     Error *ec;
479     Volume *vp;
480 {
481     IHandle_t *h = V_diskDataHandle(vp);
482     FdHandle_t *fdP;
483
484     *ec = 0;
485
486     fdP = IH_OPEN(h);
487     if (fdP == NULL) {
488         *ec = VSALVAGE;
489         return;
490     }
491     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
492         *ec = VSALVAGE;
493         FDH_REALLYCLOSE(fdP);
494         return;
495     }
496     if (FDH_WRITE(fdP, (char*)&V_disk(vp), sizeof(V_disk(vp)))
497         != sizeof(V_disk(vp))) {
498         *ec = VSALVAGE;
499         FDH_REALLYCLOSE(fdP);
500         return;
501     }
502     FDH_CLOSE(fdP);
503 }
504
505 /* Attach an existing volume, given its pathname, and return a
506    pointer to the volume header information.  The volume also
507    normally goes online at this time.  An offline volume
508    must be reattached to make it go online */
509 Volume *
510 VAttachVolumeByName(ec, partition, name, mode)
511     Error *ec;
512     char *partition;
513     char *name;
514     int mode;
515 {
516     Volume *retVal;
517     VATTACH_LOCK
518     VOL_LOCK
519     retVal = VAttachVolumeByName_r(ec, partition, name, mode);
520     VOL_UNLOCK
521     VATTACH_UNLOCK
522     return retVal;
523 }
524
525 Volume *
526 VAttachVolumeByName_r(ec, partition, name, mode)
527     Error *ec;
528     char *partition;
529     char *name;
530     int mode;
531 {
532     register Volume *vp;
533     int fd,n;
534     struct stat status;
535     struct VolumeDiskHeader diskHeader;
536     struct VolumeHeader iheader;
537     struct DiskPartition *partp;
538     char path[64];
539     int isbusy = 0;
540     *ec = 0;
541     if (programType == volumeUtility) {
542         assert(VInit == 3);
543         VLockPartition_r(partition);
544     }
545     if (programType == fileServer) {
546         vp = VGetVolume_r(ec, VolumeNumber(name));
547         if (vp) {
548             if (V_inUse(vp))
549                 return vp;
550             if (vp->specialStatus == VBUSY)
551                 isbusy = 1;
552             VDetachVolume_r(ec, vp);
553             if ( *ec ) {
554                 Log("VAttachVolume: Error detaching volume (%s)\n", name);
555             }
556         }
557     }
558
559     if (!(partp = VGetPartition_r(partition, 0))) {
560         *ec = VNOVOL;
561         Log("VAttachVolume: Error getting partition (%s)\n", partition);
562         goto done;
563     }
564
565     *ec = 0;
566     strcpy(path, VPartitionPath(partp));
567     strcat(path, "/");
568     strcat(path, name);
569     VOL_UNLOCK
570     if ((fd = open(path, O_RDONLY)) == -1 || fstat(fd,&status) == -1) {
571         close(fd);
572         VOL_LOCK
573         *ec = VNOVOL;
574         goto done;
575     }
576     n = read(fd, &diskHeader, sizeof (diskHeader));
577     close(fd);
578     VOL_LOCK
579     if (n != sizeof (diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
580         Log("VAttachVolume: Error reading volume header %s\n", path);
581         *ec = VSALVAGE;
582         goto done;
583     }
584     if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
585         Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n",path);
586         *ec = VSALVAGE;
587         goto done;
588     }
589     
590     DiskToVolumeHeader(&iheader, &diskHeader);
591     if (programType == volumeUtility && mode != V_SECRETLY) {
592         if (FSYNC_askfs(iheader.id, partition, FSYNC_NEEDVOLUME, mode)
593             == FSYNC_DENIED) {
594             Log("VAttachVolume: attach of volume %u apparently denied by file server\n",
595                 iheader.id);
596             *ec = VNOVOL; /* XXXX */
597             goto done;
598         }
599     }
600
601     vp = attach2(ec, path, &iheader, partp, isbusy);
602     if (programType == volumeUtility && vp) {
603         /* duplicate computation in fssync.c about whether the server
604          * takes the volume offline or not.  If the volume isn't
605          * offline, we must not return it when we detach the volume,
606          * or the server will abort */
607         if (mode == V_READONLY || (!VolumeWriteable(vp) && (mode==V_CLONE || mode==V_DUMP)))
608             vp->needsPutBack = 0;
609         else
610             vp->needsPutBack = 1;
611     }
612     /* OK, there's a problem here, but one that I don't know how to
613      * fix right now, and that I don't think should arise often.
614      * Basically, we should only put back this volume to the server if
615      * it was given to us by the server, but since we don't have a vp,
616      * we can't run the VolumeWriteable function to find out as we do
617      * above when computing vp->needsPutBack.  So we send it back, but
618      * there's a path in VAttachVolume on the server which may abort
619      * if this volume doesn't have a header.  Should be pretty rare
620      * for all of that to happen, but if it does, probably the right
621      * fix is for the server to allow the return of readonly volumes
622      * that it doesn't think are really checked out. */
623     if (programType == volumeUtility && vp == NULL && mode != V_SECRETLY) {
624         FSYNC_askfs(iheader.id, partition, FSYNC_ON, 0);
625     }   
626     else if (programType == fileServer && vp) {
627             V_needsCallback(vp) = 0;
628 #ifdef  notdef
629             if (VInit >= 2 && V_BreakVolumeCallbacks) {
630                 Log("VAttachVolume: Volume %u was changed externally; breaking callbacks\n", V_id(vp));
631                 (*V_BreakVolumeCallbacks)(V_id(vp));
632             }
633 #endif
634         VUpdateVolume_r(ec,vp);
635         if (*ec) {
636             Log("VAttachVolume: Error updating volume\n");
637             if (vp)
638                 VPutVolume_r(vp);
639             goto done;
640         }
641         if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
642             /* This is a hack: by temporarily settint the incore
643              * dontSalvage flag ON, the volume will be put back on the
644              * Update list (with dontSalvage OFF again).  It will then
645              * come back in N minutes with DONT_SALVAGE eventually
646              * set.  This is the way that volumes that have never had
647              * it set get it set; or that volumes that have been
648              * offline without DONT SALVAGE having been set also
649              * eventually get it set */
650             V_dontSalvage(vp) = DONT_SALVAGE;
651             VAddToVolumeUpdateList_r(ec,vp);
652             if (*ec) {
653                 Log("VAttachVolume: Error adding volume to update list\n");
654                 if (vp)
655                     VPutVolume_r(vp);
656                 goto done;
657             }
658         }
659         if (LogLevel)
660             Log("VOnline:  volume %u (%s) attached and online\n",
661                 V_id(vp), V_name(vp));
662     }
663 done:
664     if (programType == volumeUtility) {
665         VUnlockPartition_r(partition);
666     }
667     if (*ec)
668         return NULL;
669     else
670         return vp;
671 }
672
673 private Volume *attach2(ec, path, header, partp, isbusy)
674     Error *ec;
675     char *path;
676     register struct VolumeHeader *header;
677     struct DiskPartition *partp;
678     int isbusy;
679 {
680     register Volume *vp;
681
682     VOL_UNLOCK
683     vp = (Volume *) calloc(1, sizeof(Volume));
684     assert(vp != NULL);
685     vp->specialStatus = (isbusy ? VBUSY : 0);
686     vp->device = partp->device;
687     vp->partition = partp;
688     IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header->parent,
689                    header->largeVnodeIndex);
690     IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header->parent,
691                    header->smallVnodeIndex);
692     IH_INIT(vp->diskDataHandle, partp->device, header->parent,
693                    header->volumeInfo);
694     IH_INIT(vp->linkHandle, partp->device, header->parent,
695                    header->linkTable);
696     vp->cacheCheck = ++VolumeCacheCheck;
697     vp->shuttingDown = 0;
698     vp->goingOffline = 0;
699     vp->nUsers = 1;
700     VOL_LOCK
701     GetVolumeHeader(vp);
702     VOL_UNLOCK
703     (void) ReadHeader(ec, V_diskDataHandle(vp),
704                       (char *)&V_disk(vp), sizeof(V_disk(vp)), 
705                       VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
706     VOL_LOCK
707     if (*ec) {
708       Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%d\n",
709         path, *ec);
710     }
711     if (!*ec) {
712         struct IndexFileHeader iHead;
713
714 #if TRANSARC_VOL_STATS
715         /*
716          * We just read in the diskstuff part of the header.  If the detailed
717          * volume stats area has not yet been initialized, we should bzero the
718          * area and mark it as initialized.
719          */
720         if (! (V_stat_initialized(vp))) {
721             memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
722             V_stat_initialized(vp) = 1;
723         }
724 #endif /* TRANSARC_VOL_STATS */
725         VOL_UNLOCK
726         (void) ReadHeader(ec, vp->vnodeIndex[vSmall].handle, 
727                           (char *)&iHead, sizeof(iHead), 
728                           SMALLINDEXMAGIC, SMALLINDEXVERSION);
729         VOL_LOCK
730         if (*ec) {
731             Log("VAttachVolume: Error reading smallVnode vol header %s; error=%d\n",
732                 path, *ec);
733         }
734     }
735     if (!*ec) {
736         struct IndexFileHeader iHead;
737         VOL_UNLOCK
738         (void) ReadHeader(ec, vp->vnodeIndex[vLarge].handle,
739                           (char *)&iHead, sizeof(iHead),
740                           LARGEINDEXMAGIC, LARGEINDEXVERSION);
741         VOL_LOCK
742         if (*ec) {
743             Log("VAttachVolume: Error reading largeVnode vol header %s; error=%d\n",
744                 path, *ec);
745         }
746     }
747 #ifdef AFS_NAMEI_ENV
748     if (!*ec) {
749         struct versionStamp stamp;
750         VOL_UNLOCK
751         (void) ReadHeader(ec, V_linkHandle(vp),
752                           (char *)&stamp, sizeof(stamp),
753                           LINKTABLEMAGIC, LINKTABLEVERSION);
754         VOL_LOCK
755         if (*ec) {
756             Log("VAttachVolume: Error reading namei vol header %s; error=%d\n",
757                 path, *ec);
758         }
759     }
760 #endif
761     if (*ec) {
762         Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%d\n",
763             path, *ec);
764         FreeVolume(vp);
765         return NULL;
766     }
767     if (V_needsSalvaged(vp)) {
768         if (vp->specialStatus) vp->specialStatus = 0;
769         Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
770         *ec = VSALVAGE;
771         return NULL;
772     }
773     if (programType == fileServer) {
774 #ifndef FAST_RESTART
775         if (V_inUse(vp) && VolumeWriteable(vp)) {
776             if (!V_needsSalvaged(vp)) {
777                 V_needsSalvaged(vp) = 1;
778                 VUpdateVolume_r(ec,vp);
779             }
780             FreeVolume(vp);
781             Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
782             *ec = VSALVAGE;
783             return NULL;
784         }
785 #endif /* FAST_RESTART */
786         if (V_destroyMe(vp) == DESTROY_ME) {
787             FreeVolume(vp);
788             Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
789             *ec = VNOVOL;
790             return NULL;
791         }
792     }
793
794     AddVolumeToHashTable(vp, V_id(vp));
795     vp->nextVnodeUnique = V_uniquifier(vp);
796     vp->vnodeIndex[vSmall].bitmap = vp->vnodeIndex[vLarge].bitmap = NULL;
797 #ifndef BITMAP_LATER
798     if (programType == fileServer && VolumeWriteable(vp)) {
799         int i;
800         for (i = 0; i<nVNODECLASSES; i++) {
801             VOL_UNLOCK
802             GetBitmap(ec,vp,i);
803             VOL_LOCK
804             if (*ec) {
805                 FreeVolume(vp);
806                 Log("VAttachVolume: error getting bitmap for volume (%s)\n", path);
807                 return NULL;
808             }
809         }
810     }
811 #endif /* BITMAP_LATER */
812
813     if (programType == fileServer) {
814         if (vp->specialStatus) vp->specialStatus = 0;
815         if (V_blessed(vp) && V_inService(vp) && !V_needsSalvaged(vp)) {
816             V_inUse(vp) = 1;
817             V_offlineMessage(vp)[0] = '\0';
818         }
819     }
820
821     return vp;
822 }
823
824 /* Attach an existing volume.
825    The volume also normally goes online at this time.
826    An offline volume must be reattached to make it go online.
827  */
828
829 Volume *
830 VAttachVolume(ec,volumeId, mode)
831     Error *ec;
832     VolumeId volumeId;
833     int mode;
834 {
835     Volume *retVal;
836     VATTACH_LOCK
837     VOL_LOCK
838     retVal = VAttachVolume_r(ec, volumeId, mode);
839     VOL_UNLOCK
840     VATTACH_UNLOCK
841     return retVal;
842 }
843
844 Volume *
845 VAttachVolume_r(ec,volumeId, mode)
846     Error *ec;
847     VolumeId volumeId;
848     int mode;
849 {
850     char *part, *name;
851     GetVolumePath(ec,volumeId, &part, &name);
852     if (*ec) {
853         register Volume *vp;
854         Error error;
855         vp = VGetVolume_r(&error, volumeId);
856         if (vp) {
857             assert(V_inUse(vp) == 0);
858             VDetachVolume_r(ec, vp);
859         }
860         return NULL;
861     }
862     return VAttachVolumeByName_r(ec, part, name, mode);
863 }
864
865 /* Increment a reference count to a volume, sans context swaps.  Requires
866  * possibly reading the volume header in from the disk, since there's
867  * an invariant in the volume package that nUsers>0 ==> vp->header is valid.
868  *
869  * N.B. This call can fail if we can't read in the header!!  In this case
870  * we still guarantee we won't context swap, but the ref count won't be
871  * incremented (otherwise we'd violate the invariant).
872  */
873 static int VHold_r(register Volume *vp)
874 {
875     Error error;
876
877     if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
878         VolumeReplacements++;
879         ReadHeader(&error, V_diskDataHandle(vp),
880                    (char *)&V_disk(vp), sizeof(V_disk(vp)),
881                    VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
882         if (error) return error;
883     }
884     vp->nUsers++;
885     return 0;
886 }
887
888 static int VHold(register Volume *vp)
889 {
890     int retVal;
891     VOL_LOCK
892     retVal = VHold_r(vp);
893     VOL_UNLOCK
894     return retVal;
895 }
896
897 void VTakeOffline_r(register Volume *vp)
898 {
899     assert(vp->nUsers > 0);
900     assert(programType == fileServer);
901     vp->goingOffline = 1;
902     V_needsSalvaged(vp) = 1;
903 }
904
905 void VTakeOffline(register Volume *vp)
906 {
907     VOL_LOCK
908     VTakeOffline_r(vp);
909     VOL_UNLOCK
910 }
911
912 void VPutVolume_r(register Volume *vp)
913 {
914     assert(--vp->nUsers >= 0);
915     if (vp->nUsers == 0) {
916         ReleaseVolumeHeader(vp->header);
917         if (vp->goingOffline) {
918             Error error;
919             assert(programType == fileServer);
920             vp->goingOffline = 0;
921             V_inUse(vp) = 0;
922             VUpdateVolume_r(&error, vp);
923             VCloseVolumeHandles_r(vp);
924             if (LogLevel) {
925                 Log("VOffline: Volume %u (%s) is now offline",
926                     V_id(vp), V_name(vp));
927                 if (V_offlineMessage(vp)[0])
928                     Log(" (%s)", V_offlineMessage(vp));
929                 Log("\n");
930             }
931 #ifdef AFS_PTHREAD_ENV
932             assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
933 #else /* AFS_PTHREAD_ENV */
934             LWP_NoYieldSignal(VPutVolume);
935 #endif /* AFS_PTHREAD_ENV */
936         }
937         if (vp->shuttingDown) {
938             VReleaseVolumeHandles_r(vp);
939             FreeVolume(vp);
940             if (programType == fileServer)
941 #ifdef AFS_PTHREAD_ENV
942                 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
943 #else /* AFS_PTHREAD_ENV */
944                 LWP_NoYieldSignal(VPutVolume);
945 #endif /* AFS_PTHREAD_ENV */
946         }
947     }
948 }
949
950 void VPutVolume(register Volume *vp)
951 {
952     VOL_LOCK
953     VPutVolume_r(vp);
954     VOL_UNLOCK
955 }
956
957 /* Get a pointer to an attached volume.  The pointer is returned regardless
958    of whether or not the volume is in service or on/off line.  An error
959    code, however, is returned with an indication of the volume's status */
960 Volume *VGetVolume(ec,volumeId)
961     Error *ec;
962     VolId volumeId;
963 {
964     Volume *retVal;
965     VOL_LOCK
966     retVal = VGetVolume_r(ec,volumeId);
967     VOL_UNLOCK
968     return retVal;
969 }
970
971 Volume *VGetVolume_r(ec,volumeId)
972     Error *ec;
973     VolId volumeId;
974 {
975     Volume *vp;
976     unsigned short V0=0, V1=0, V2=0, V3=0, V4=0, V5=0, V6=0, V7=0, V8=0, V9=0;
977     unsigned short V10=0, V11=0, V12=0, V13=0, V14=0, V15=0;
978
979     for(;;) {
980         *ec = 0;
981         V0++;
982         for (vp = VolumeHashTable[VOLUME_HASH(volumeId)];
983              vp && vp->hashid != volumeId; vp = vp->hashNext)
984             Vlooks++;
985
986         if (!vp) {
987           V1++;
988           if (VInit < 2) {
989             V2++;
990             /* Until we have reached an initialization level of 2
991                we don't know whether this volume exists or not.
992                We can't sleep and retry later because before a volume
993                is attached, the caller tries to get it first.  Just
994                return VOFFLINE and the caller can choose whether to
995                retry the command or not.*/
996             *ec = VOFFLINE;
997             break;
998           }
999
1000           *ec = VNOVOL;
1001           break;
1002         }
1003
1004         V3++;
1005         VolumeGets++;
1006         if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
1007           V5++;
1008             VolumeReplacements++;
1009             ReadHeader(ec, V_diskDataHandle(vp),
1010                 (char *)&V_disk(vp), sizeof(V_disk(vp)), VOLUMEINFOMAGIC,
1011                           VOLUMEINFOVERSION);
1012             if (*ec) {
1013               V6++;
1014                 /* Only log the error if it was a totally unexpected error.  Simply
1015                    a missing inode is likely to be caused by the volume being deleted */
1016                 if (errno != ENXIO || LogLevel)
1017                     Log("Volume %u: couldn't reread volume header\n", vp->hashid);
1018                 FreeVolume(vp);
1019                 vp = 0;
1020                 break;
1021             }
1022         }
1023         V7++;
1024         if (vp->shuttingDown) {
1025           V8++;
1026             *ec = VNOVOL;
1027             vp = 0;
1028             break;
1029         }
1030         if (programType == fileServer) {
1031           V9++;
1032             if (vp->goingOffline) {
1033               V10++;
1034 #ifdef AFS_PTHREAD_ENV
1035                 pthread_cond_wait(&vol_put_volume_cond, &vol_glock_mutex);
1036 #else /* AFS_PTHREAD_ENV */
1037                 LWP_WaitProcess(VPutVolume);
1038 #endif /* AFS_PTHREAD_ENV */
1039                 continue;
1040             }
1041             if (vp->specialStatus) {
1042               V11++;
1043                 *ec = vp->specialStatus;
1044               }
1045             else if (V_inService(vp)==0 || V_blessed(vp)==0) {
1046               V12++;
1047                 *ec = VNOVOL;
1048               }
1049             else if (V_inUse(vp)==0) {
1050               V13++;
1051                 *ec = VOFFLINE;
1052               }
1053           else {
1054               V14++;
1055           }
1056         }
1057         break;
1058     }
1059     V15++;
1060     /* if no error, bump nUsers */
1061     if (vp) vp->nUsers++;
1062
1063     assert (vp || *ec);
1064     return vp;
1065 }
1066
1067
1068 /* For both VForceOffline and VOffline, we close all relevant handles.
1069  * For VOffline, if we re-attach the volume, the files may possible be
1070  * different than before. 
1071  */
1072 static void VReleaseVolumeHandles_r(Volume *vp)
1073 {
1074     DFlushVolume(V_id(vp));
1075     VReleaseVnodeFiles_r(vp);
1076
1077     /* Too time consuming and unnecessary for the volserver */
1078     if (programType != volumeUtility) {
1079        IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1080        IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1081        IH_CONDSYNC(vp->diskDataHandle);
1082 #ifdef AFS_NT40_ENV
1083        IH_CONDSYNC(vp->linkHandle);
1084 #endif /* AFS_NT40_ENV */
1085     }
1086
1087     IH_RELEASE(vp->vnodeIndex[vLarge].handle);
1088     IH_RELEASE(vp->vnodeIndex[vSmall].handle);
1089     IH_RELEASE(vp->diskDataHandle);
1090     IH_RELEASE(vp->linkHandle);
1091 }
1092
1093 /* Force the volume offline, set the salvage flag.  No further references to
1094  * the volume through the volume package will be honored. */
1095 void VForceOffline_r(Volume *vp)
1096 {
1097     Error error;
1098     if (!V_inUse(vp))
1099        return;
1100     strcpy(V_offlineMessage(vp), "Forced offline due to internal error: volume needs to be salvaged");
1101     Log("Volume %u forced offline:  it needs salvaging!\n", V_id(vp));
1102     V_inUse(vp) = 0;
1103     vp->goingOffline = 0;    
1104     V_needsSalvaged(vp) = 1;
1105     VUpdateVolume_r(&error, vp);
1106 #ifdef AFS_PTHREAD_ENV
1107     assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1108 #else /* AFS_PTHREAD_ENV */
1109     LWP_NoYieldSignal(VPutVolume);
1110 #endif /* AFS_PTHREAD_ENV */
1111
1112     VReleaseVolumeHandles_r(vp);
1113
1114 }
1115
1116 void VForceOffline(Volume *vp)
1117 {
1118     VOL_LOCK
1119     VForceOffline_r(vp);
1120     VOL_UNLOCK
1121 }
1122
1123 /* The opposite of VAttachVolume.  The volume header is written to disk, with
1124    the inUse bit turned off.  A copy of the header is maintained in memory,
1125    however (which is why this is VOffline, not VDetach).
1126  */   
1127 void VOffline_r(Volume *vp, char *message)
1128 {
1129     Error error;
1130     VolumeId vid = V_id(vp);
1131     assert(programType != volumeUtility);
1132     if (!V_inUse(vp)) {
1133         VPutVolume_r(vp);
1134         return;
1135     }
1136     if (V_offlineMessage(vp)[0] == '\0')
1137         strncpy(V_offlineMessage(vp),message,
1138                 sizeof(V_offlineMessage(vp)));
1139     V_offlineMessage(vp)[sizeof(V_offlineMessage(vp))-1] = '\0';
1140     vp->goingOffline = 1;    
1141     VPutVolume_r(vp);
1142     vp = VGetVolume_r(&error, vid);     /* Wait for it to go offline */
1143     if (vp)  /* In case it was reattached... */
1144         VPutVolume_r(vp);
1145 }
1146
1147 void VOffline(Volume *vp, char *message)
1148 {
1149     VOL_LOCK
1150     VOffline_r(vp, message);
1151     VOL_UNLOCK
1152 }
1153
1154 /* For VDetachVolume, we close all cached file descriptors, but keep
1155  * the Inode handles in case we need to read from a busy volume.
1156  */
1157 static void VCloseVolumeHandles_r(Volume *vp)
1158 {
1159     DFlushVolume(V_id(vp));
1160     VCloseVnodeFiles_r(vp);
1161
1162     /* Too time consuming and unnecessary for the volserver */
1163     if (programType != volumeUtility) {
1164        IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1165        IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1166        IH_CONDSYNC(vp->diskDataHandle);
1167 #ifdef AFS_NT40_ENV
1168        IH_CONDSYNC(vp->linkHandle);
1169 #endif /* AFS_NT40_ENV */
1170     }
1171
1172     IH_REALLYCLOSE(vp->vnodeIndex[vLarge].handle);
1173     IH_REALLYCLOSE(vp->vnodeIndex[vSmall].handle);
1174     IH_REALLYCLOSE(vp->diskDataHandle);
1175     IH_REALLYCLOSE(vp->linkHandle);
1176 }
1177
1178 /* This gets used for the most part by utility routines that don't want
1179  * to keep all the volume headers around.  Generally, the file server won't
1180  * call this routine, because then the offline message in the volume header
1181  * (or other information) will still be available to clients. For NAMEI, also
1182  * close the file handles.
1183  */
1184 void VDetachVolume_r(Error *ec, Volume *vp)
1185 {
1186     VolumeId volume;
1187     struct DiskPartition *tpartp;
1188     int notifyServer, useDone;
1189
1190     *ec = 0;    /* always "succeeds" */
1191     if (programType == volumeUtility) {
1192         notifyServer = vp->needsPutBack;
1193         useDone = (V_destroyMe(vp) == DESTROY_ME);
1194     }
1195     tpartp = vp->partition;
1196     volume = V_id(vp);
1197     DeleteVolumeFromHashTable(vp);
1198     vp->shuttingDown = 1;
1199     VPutVolume_r(vp);
1200     /* Will be detached sometime in the future--this is OK since volume is offline */
1201
1202     if (programType == volumeUtility && notifyServer) {
1203         /* Note:  The server is not notified in the case of a bogus volume explicitly to
1204            make it possible to create a volume, do a partial restore, then abort the
1205            operation without ever putting the volume online.  This is essential in the
1206            case of a volume move operation between two partitions on the same server.  In
1207            that case, there would be two instances of the same volume, one of them bogus,
1208            which the file server would attempt to put on line */
1209         if (useDone)
1210             FSYNC_askfs(volume, tpartp->name, FSYNC_DONE, 0);   /* don't put online */
1211         else {
1212             FSYNC_askfs(volume, tpartp->name, FSYNC_ON, 0);     /* fs can use it again */
1213             /* Dettaching it so break all callbacks on it*/
1214             if (V_BreakVolumeCallbacks) {
1215                 Log("volume %u detached; breaking all call backs\n", volume);
1216                 (*V_BreakVolumeCallbacks)(volume);
1217             }
1218         }
1219     }
1220 }
1221
1222 void VDetachVolume(Error *ec, Volume *vp)
1223 {
1224     VOL_LOCK
1225     VDetachVolume_r(ec, vp);
1226     VOL_UNLOCK
1227 }
1228
1229
1230 int VAllocBitmapEntry_r(ec,vp,index)
1231     Error *ec;
1232     Volume *vp;
1233     register struct vnodeIndex *index;
1234 {
1235     register byte *bp,*ep;
1236     *ec = 0;
1237     /* This test is probably redundant */
1238     if (!VolumeWriteable(vp)) {
1239         *ec = VREADONLY;
1240         return 0;
1241     }
1242 #ifdef BITMAP_LATER
1243     if ((programType == fileServer) && !index->bitmap) {
1244         int i;
1245         int wasVBUSY = 0;
1246         if (vp->specialStatus == VBUSY) {
1247             if (vp->goingOffline) { /* vos dump waiting for the volume to
1248                                        go offline. We probably come here
1249                                        from AddNewReadableResidency */
1250                 wasVBUSY = 1;
1251             } else {
1252                 VOL_UNLOCK
1253                 while (vp->specialStatus == VBUSY)
1254 #ifdef AFS_PTHREAD_ENV
1255                     sleep(2);
1256 #else /* AFS_PTHREAD_ENV */
1257                     IOMGR_Sleep(2);
1258 #endif /* AFS_PTHREAD_ENV */
1259                 VOL_LOCK
1260             }
1261         }
1262         if (!index->bitmap) {
1263             vp->specialStatus = VBUSY; /* Stop anyone else from using it.*/
1264             for (i = 0; i<nVNODECLASSES; i++) {
1265                 VOL_UNLOCK
1266                 GetBitmap(ec,vp,i);
1267                 VOL_LOCK
1268                 if (*ec) {
1269                     vp->specialStatus = 0;
1270                     vp->shuttingDown = 1; /* Let who has it free it. */
1271                     return NULL;
1272                 }
1273             }
1274             if (!wasVBUSY)
1275                 vp->specialStatus = 0; /* Allow others to have access. */
1276         }
1277     }
1278 #endif /* BITMAP_LATER */
1279     bp = index->bitmap + index->bitmapOffset;
1280     ep = index->bitmap + index->bitmapSize;
1281     while (bp < ep) {
1282         if ((*(bit32 *)bp) != 0xffffffff) {
1283             int o;
1284             index->bitmapOffset = bp - index->bitmap;
1285             while (*bp == 0xff)
1286                 bp++;       
1287             o = ffs(~*bp)-1;  /* ffs is documented in BSTRING(3) */
1288             *bp |= (1 << o);
1289             return (bp - index->bitmap)*8 + o;
1290         }
1291         bp += sizeof(bit32) /* i.e. 4 */;
1292     }
1293     /* No bit map entry--must grow bitmap */
1294     bp = (byte *)
1295         realloc(index->bitmap, index->bitmapSize+VOLUME_BITMAP_GROWSIZE);
1296     assert(bp != NULL);
1297     index->bitmap = bp;
1298     bp += index->bitmapSize;
1299     memset(bp, 0, VOLUME_BITMAP_GROWSIZE);
1300     index->bitmapOffset = index->bitmapSize;
1301     index->bitmapSize += VOLUME_BITMAP_GROWSIZE;
1302     *bp = 1;
1303     return index->bitmapOffset*8;
1304 }
1305
1306 int VAllocBitmapEntry(ec,vp,index)
1307     Error *ec;
1308     Volume *vp;
1309     register struct vnodeIndex *index;
1310 {
1311     int retVal;
1312     VOL_LOCK
1313     retVal = VAllocBitmapEntry_r(ec,vp,index);
1314     VOL_UNLOCK
1315     return retVal;
1316 }
1317
1318 void VFreeBitMapEntry_r(Error *ec, register struct vnodeIndex *index,
1319                       int bitNumber)
1320 {
1321     unsigned int offset;
1322      *ec = 0;
1323 #ifdef BITMAP_LATER
1324      if (!index->bitmap) return;
1325 #endif /* BITMAP_LATER */
1326      offset = bitNumber>>3;
1327      if (offset >= index->bitmapSize) {
1328         *ec = VNOVNODE;
1329         return;
1330      }
1331      if (offset < index->bitmapOffset)
1332         index->bitmapOffset = offset&~3;        /* Truncate to nearest bit32 */
1333      *(index->bitmap + offset) &= ~(1 << (bitNumber & 0x7));
1334 }
1335
1336 void VFreeBitMapEntry(Error *ec, register struct vnodeIndex *index,
1337                       int bitNumber)
1338 {
1339     VOL_LOCK
1340     VFreeBitMapEntry_r(ec, index, bitNumber);
1341     VOL_UNLOCK
1342 }
1343
1344 void VUpdateVolume_r(Error *ec,Volume *vp)
1345 {
1346     *ec = 0;
1347     if (programType == fileServer) 
1348         V_uniquifier(vp) = (V_inUse(vp)? V_nextVnodeUnique(vp) + 200: V_nextVnodeUnique(vp));
1349     /*printf("Writing volume header for '%s'\n", V_name(vp));*/
1350     WriteVolumeHeader_r(ec, vp);
1351     if (*ec) {
1352         Log(
1353           "VUpdateVolume: error updating volume header, volume %u (%s)\n",
1354             V_id(vp), V_name(vp));
1355         VForceOffline_r(vp);
1356     }
1357 }
1358
1359 void VUpdateVolume(Error *ec, Volume *vp)
1360 {
1361     VOL_LOCK
1362     VUpdateVolume_r(ec, vp);
1363     VOL_UNLOCK
1364 }
1365
1366 void VSyncVolume_r(Error *ec, Volume *vp)
1367 {
1368     FdHandle_t *fdP;
1369     VUpdateVolume_r(ec, vp);
1370     if (!ec) {
1371         int code;
1372         fdP = IH_OPEN(V_diskDataHandle(vp));
1373         assert(fdP != NULL);
1374         code = FDH_SYNC(fdP);
1375         assert(code == 0);
1376         FDH_CLOSE(fdP);
1377     }
1378 }
1379
1380 void VSyncVolume(Error *ec, Volume *vp)
1381 {
1382     VOL_LOCK
1383     VSyncVolume_r(ec, vp);
1384     VOL_UNLOCK
1385 }
1386
1387 static void FreeVolume(vp)
1388     Volume *vp;
1389 {
1390     int i;
1391     if (!vp)
1392         return;
1393     for (i = 0; i<nVNODECLASSES; i++)
1394         if (vp->vnodeIndex[i].bitmap)
1395             free(vp->vnodeIndex[i].bitmap);
1396     FreeVolumeHeader(vp);
1397     DeleteVolumeFromHashTable(vp);
1398     free(vp);
1399 }
1400
1401 static void GetBitmap(Error *ec, Volume *vp, VnodeClass class)
1402 {
1403     StreamHandle_t *file;
1404     int nVnodes;
1405     int size;
1406     int counter = 0;
1407     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1408     struct vnodeIndex *vip = &vp->vnodeIndex[class];
1409     struct VnodeDiskObject *vnode;
1410     unsigned int unique = 0;
1411     FdHandle_t *fdP;
1412 #ifdef BITMAP_LATER
1413     byte *BitMap = 0;
1414 #endif /* BITMAP_LATER */
1415
1416     *ec = 0;
1417
1418     fdP = IH_OPEN(vip->handle);
1419     assert (fdP != NULL);
1420     file = FDH_FDOPEN(fdP, "r");
1421     assert (file != NULL);
1422     vnode = (VnodeDiskObject *) malloc(vcp->diskSize);
1423     assert(vnode != NULL);
1424     size = OS_SIZE(fdP->fd_fd);
1425     assert(size != -1);
1426     nVnodes = (size <= vcp->diskSize? 0: size-vcp->diskSize)
1427                 >> vcp->logSize;
1428     vip->bitmapSize = ((nVnodes/8)+10)/4*4; /* The 10 is a little extra so
1429                                 a few files can be created in this volume,
1430                                 the whole thing is rounded up to nearest 4
1431                                 bytes, because the bit map allocator likes
1432                                 it that way */
1433 #ifdef BITMAP_LATER
1434     BitMap = (byte *) calloc(1, vip->bitmapSize);
1435     assert(BitMap != NULL);
1436 #else /* BITMAP_LATER */
1437     vip->bitmap = (byte *) calloc(1, vip->bitmapSize);
1438     assert(vip->bitmap != NULL);
1439     vip->bitmapOffset = 0;
1440 #endif /* BITMAP_LATER */
1441     if (STREAM_SEEK(file,vcp->diskSize,0) != -1) {
1442       int bitNumber = 0;
1443       for (bitNumber = 0; bitNumber < nVnodes+100; bitNumber++) {
1444         if (STREAM_READ(vnode, vcp->diskSize, 1, file) != 1) 
1445           break;
1446         if (vnode->type != vNull) {
1447           if (vnode->vnodeMagic != vcp->magic) {
1448             Log("GetBitmap: addled vnode index in volume %s; volume needs salvage\n",
1449                 V_name(vp));
1450             *ec = VSALVAGE;
1451             break;
1452           }
1453 #ifdef BITMAP_LATER
1454           *(BitMap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1455 #else /* BITMAP_LATER */
1456           *(vip->bitmap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1457 #endif /* BITMAP_LATER */
1458           if (unique <= vnode->uniquifier)
1459             unique = vnode->uniquifier + 1; 
1460         }
1461 #ifndef AFS_PTHREAD_ENV
1462         if ((bitNumber & 0x00ff) == 0x0ff) { /* every 256 iterations */
1463           IOMGR_Poll();
1464         }
1465 #endif /* !AFS_PTHREAD_ENV */
1466       }
1467     }
1468     if (vp->nextVnodeUnique < unique) {
1469         Log("GetBitmap: bad volume uniquifier for volume %s; volume needs salvage\n", V_name(vp));
1470         *ec = VSALVAGE;
1471     }
1472     /* Paranoia, partly justified--I think fclose after fdopen
1473      * doesn't seem to close fd.  In any event, the documentation
1474      * doesn't specify, so it's safer to close it twice.
1475      */
1476     STREAM_CLOSE(file);
1477     FDH_CLOSE(fdP);
1478     free(vnode);
1479 #ifdef BITMAP_LATER
1480     /* There may have been a racing condition with some other thread, both
1481      * creating the bitmaps for this volume. If the other thread was faster
1482      * the pointer to bitmap should already be filled and we can free ours.
1483      */
1484     if (vip->bitmap == NULL) {
1485         vip->bitmap = BitMap;
1486         vip->bitmapOffset = 0;
1487     } else 
1488         free((byte *)BitMap);
1489 #endif /* BITMAP_LATER */
1490 }
1491
1492 static void GetVolumePath(Error *ec, VolId volumeId, char **partitionp,
1493                      char **namep)
1494 {
1495     static char partition[VMAXPATHLEN], name[VMAXPATHLEN];
1496     char path[VMAXPATHLEN];
1497     int found = 0;
1498     struct DiskPartition *dp;
1499
1500     *ec = 0;
1501     name[0] = '/';
1502     sprintf(&name[1],VFORMAT,volumeId);
1503     for (dp = DiskPartitionList; dp; dp = dp->next) {
1504         struct stat status;
1505         strcpy(path, VPartitionPath(dp));
1506         strcat(path, name);
1507         if (stat(path,&status) == 0) {
1508             strcpy(partition, dp->name);
1509             found = 1;
1510             break;
1511         }
1512     }
1513     if (!found) {
1514         *ec = VNOVOL;
1515         *partitionp = *namep = NULL;
1516     }
1517     else {
1518         *partitionp = partition;
1519         *namep = name;
1520     }
1521 }       
1522
1523 VolumeNumber(name)
1524     char *name;
1525 {
1526     if (*name == '/')
1527         name++;
1528     return atoi(name+1);
1529 }
1530
1531 char *VolumeExternalName(volumeId)
1532     VolumeId volumeId;
1533 {
1534     static char name[15];
1535     sprintf(name,VFORMAT,volumeId);
1536     return name;
1537 }
1538
1539 #if TRANSARC_VOL_STATS
1540 #define OneDay  (86400)                 /* 24 hours' worth of seconds */
1541 #else
1542 #define OneDay  (24*60*60)              /* 24 hours */
1543 #endif /* TRANSARC_VOL_STATS */
1544
1545 #define Midnight(date) ((date-TimeZoneCorrection)/OneDay*OneDay+TimeZoneCorrection)
1546
1547 /*------------------------------------------------------------------------
1548  * [export] VAdjustVolumeStatistics
1549  *
1550  * Description:
1551  *      If we've passed midnight, we need to update all the day use
1552  *      statistics as well as zeroing the detailed volume statistics
1553  *      (if we are implementing them).
1554  *
1555  * Arguments:
1556  *      vp : Pointer to the volume structure describing the lucky
1557  *              volume being considered for update.
1558  *
1559  * Returns:
1560  *      0 (always!)
1561  *
1562  * Environment:
1563  *      Nothing interesting.
1564  *
1565  * Side Effects:
1566  *      As described.
1567  *------------------------------------------------------------------------*/
1568
1569 VAdjustVolumeStatistics_r(vp)
1570     register Volume *vp;
1571
1572 { /*VAdjustVolumeStatistics*/
1573
1574     unsigned int now = FT_ApproxTime();
1575
1576     if (now - V_dayUseDate(vp) > OneDay) {
1577         register ndays, i;
1578
1579         ndays = (now - V_dayUseDate(vp)) / OneDay;
1580         for (i = 6; i>ndays-1; i--)
1581             V_weekUse(vp)[i] = V_weekUse(vp)[i-ndays];
1582         for (i = 0; i<ndays-1 && i<7; i++)
1583             V_weekUse(vp)[i] = 0;
1584         if (ndays <= 7)
1585             V_weekUse(vp)[ndays-1] = V_dayUse(vp);
1586         V_dayUse(vp) = 0;
1587         V_dayUseDate(vp) = Midnight(now);
1588
1589 #if TRANSARC_VOL_STATS
1590         /*
1591          * All we need to do is bzero the entire VOL_STATS_BYTES of
1592          * the detailed volume statistics area.
1593          */
1594         memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
1595 #endif /* TRANSARC_VOL_STATS */
1596     } /*It's been more than a day of collection*/
1597
1598 #if TRANSARC_VOL_STATS
1599     /*
1600      * Always return happily.
1601      */
1602     return(0);
1603 #endif /* TRANSARC_VOL_STATS */
1604
1605 } /*VAdjustVolumeStatistics*/
1606
1607 VAdjustVolumeStatistics(vp)
1608     register Volume *vp;
1609 {
1610     int retVal;
1611     VOL_LOCK
1612     VAdjustVolumeStatistics_r(vp);
1613     VOL_UNLOCK
1614     return retVal;
1615 }
1616
1617 void VBumpVolumeUsage_r(register Volume *vp)
1618 {
1619     unsigned int now = FT_ApproxTime();
1620     if (now - V_dayUseDate(vp) > OneDay)
1621         VAdjustVolumeStatistics_r(vp);
1622     /*
1623      * Save the volume header image to disk after every 128 bumps to dayUse.
1624      */
1625     if ((V_dayUse(vp)++ & 127) == 0) {
1626         Error error;
1627         VUpdateVolume_r(&error, vp);
1628     }
1629 }
1630
1631 void VBumpVolumeUsage(register Volume *vp)
1632 {
1633     VOL_LOCK
1634     VBumpVolumeUsage_r(vp);
1635     VOL_UNLOCK
1636 }
1637
1638 void VSetDiskUsage_r(void)
1639 {
1640     static int FifteenMinuteCounter = 0;
1641     
1642     while (VInit < 2) {
1643       /* NOTE: Don't attempt to access the partitions list until the
1644          initialization level indicates that all volumes are attached,
1645          which implies that all partitions are initialized. */
1646 #ifdef AFS_PTHREAD_ENV
1647       sleep(10);
1648 #else /* AFS_PTHREAD_ENV */
1649       IOMGR_Sleep(10);
1650 #endif /* AFS_PTHREAD_ENV */
1651     }
1652
1653     VResetDiskUsage_r();
1654     if (++FifteenMinuteCounter == 3) {
1655         FifteenMinuteCounter = 0;
1656         VScanUpdateList();
1657     }
1658 }
1659
1660 void VSetDiskUsage(void)
1661 {
1662     VOL_LOCK
1663     VSetDiskUsage_r();
1664     VOL_UNLOCK
1665 }
1666
1667 /* The number of minutes that a volume hasn't been updated before the
1668  * "Dont salvage" flag in the volume header will be turned on */
1669 #define SALVAGE_INTERVAL        (10*60)
1670
1671 static VolumeId *UpdateList;    /* Pointer to array of Volume ID's */
1672 static int nUpdatedVolumes;     /* Updated with entry in UpdateList, salvage after crash flag on */
1673 static int updateSize;          /* number of entries possible */
1674 #define UPDATE_LIST_SIZE 100    /* size increment */
1675
1676 void VAddToVolumeUpdateList_r(Error *ec, Volume *vp)
1677 {
1678     *ec = 0;
1679     vp->updateTime = FT_ApproxTime();
1680     if (V_dontSalvage(vp) == 0)
1681         return;
1682     V_dontSalvage(vp) = 0;
1683     VSyncVolume_r(ec, vp);
1684     if (*ec)
1685         return;
1686     if (!UpdateList) {
1687         updateSize = UPDATE_LIST_SIZE;
1688         UpdateList = (VolumeId *) malloc(sizeof (VolumeId) * updateSize);
1689     } else {
1690         if (nUpdatedVolumes == updateSize) {
1691             updateSize += UPDATE_LIST_SIZE;
1692             UpdateList = (VolumeId *) realloc(UpdateList, sizeof (VolumeId) * updateSize);
1693         }
1694     }
1695     UpdateList[nUpdatedVolumes++] = V_id(vp);
1696 }
1697
1698 static void VScanUpdateList() {
1699     register int i, gap;
1700     register Volume *vp;
1701     Error error;
1702     afs_int32 now = FT_ApproxTime();
1703     /* Be careful with this code, since it works with interleaved calls to AddToVolumeUpdateList */
1704     for (i = gap = 0; i<nUpdatedVolumes; i++) {
1705         vp = VGetVolume_r(&error, UpdateList[i-gap] = UpdateList[i]);
1706         if (error) {
1707             gap++;
1708         } else if (vp->nUsers == 1 && now - vp->updateTime > SALVAGE_INTERVAL) {
1709             V_dontSalvage(vp) = DONT_SALVAGE;
1710             VUpdateVolume_r(&error, vp); /* No need to fsync--not critical */
1711             gap++;
1712         }
1713         if (vp)
1714             VPutVolume_r(vp);
1715 #ifndef AFS_PTHREAD_ENV
1716         IOMGR_Poll();
1717 #endif /* !AFS_PTHREAD_ENV */
1718     }
1719     nUpdatedVolumes -= gap;
1720 }
1721
1722 /***************************************************/
1723 /* Add on routines to manage a volume header cache */
1724 /***************************************************/
1725
1726 static struct volHeader *volumeLRU;
1727
1728 /* Allocate a bunch of headers; string them together */
1729 static void InitLRU(howMany)
1730 int howMany;
1731 {
1732     register struct volHeader *hp;
1733     if (programType != fileServer)
1734         return;
1735     hp = (struct volHeader *)(calloc(howMany, sizeof(struct volHeader)));
1736     while (howMany--)
1737         ReleaseVolumeHeader(hp++);
1738 }
1739
1740 /* Get a volume header from the LRU list; update the old one if necessary */
1741 /* Returns 1 if there was already a header, which is removed from the LRU list */
1742 static int GetVolumeHeader(vp)
1743 register Volume *vp;
1744 {
1745     Error error;
1746     register struct volHeader *hd;
1747     int old;
1748     static int everLogged = 0;
1749
1750     old = (vp->header != 0);    /* old == volume already has a header */
1751     if (programType != fileServer) {
1752         if (!vp->header) {
1753             hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1754             assert(hd != 0);
1755             vp->header = hd;
1756             hd->back = vp;
1757         }
1758     }
1759     else {
1760         if (old) {
1761             hd = vp->header;
1762             if (volumeLRU == hd)
1763                 volumeLRU = hd->next;
1764             assert(hd->back == vp);
1765         }
1766         else {
1767             if (volumeLRU)
1768                 hd = volumeLRU->prev; /* not currently in use and least recently used */
1769             else {
1770                 hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1771                 hd->prev = hd->next = hd;       /* make it look like single elt LRU */
1772                 if (!everLogged) {
1773                     Log("****Allocated more volume headers, probably leak****\n");
1774                     everLogged=1;
1775                 }
1776             }
1777             if (hd->back) {
1778                 if (hd->diskstuff.inUse) {
1779                     WriteVolumeHeader_r(&error, hd->back);
1780                     /* Ignore errors; catch them later */
1781                 }
1782                 hd->back->header = 0;
1783             }
1784             hd->back = vp;
1785             vp->header = hd;
1786         }
1787         if (hd->next) { /* hd->next != 0 --> in LRU chain (we zero it later) */
1788             hd->prev->next = hd->next;  /* pull hd out of LRU list */
1789             hd->next->prev = hd->prev;  /* if hd only element, this is noop */
1790         }
1791         hd->next = hd->prev = 0;
1792         /* if not in LRU chain, next test won't be true */
1793         if (hd == volumeLRU)    /* last header item, turn into empty list */
1794             volumeLRU = NULL;
1795     }
1796     return old;
1797 }
1798
1799 /* Put it at the top of the LRU chain */
1800 static void ReleaseVolumeHeader(hd)
1801     register struct volHeader *hd;
1802 {
1803     if (programType != fileServer)
1804         return;
1805     if (!hd || hd->next) /* no header, or header already released */
1806         return;
1807     if (!volumeLRU) {
1808         hd->next = hd->prev = hd;
1809     } else {
1810         hd->prev = volumeLRU->prev;
1811         hd->next = volumeLRU;
1812         hd->prev->next = hd->next->prev = hd;
1813     }
1814     volumeLRU = hd;
1815 }
1816
1817 static void FreeVolumeHeader(vp)
1818 register Volume *vp;
1819 {
1820     register struct volHeader *hd = vp->header;
1821     if (!hd)
1822         return;
1823     if (programType == fileServer) {
1824         ReleaseVolumeHeader(hd);
1825         hd->back = 0;
1826     }
1827     else {
1828         free(hd);
1829     }
1830     vp->header = 0;
1831 }
1832
1833
1834 /***************************************************/
1835 /* Routines to add volume to hash chain, delete it */
1836 /***************************************************/
1837
1838 static void AddVolumeToHashTable(vp, hashid)
1839 register Volume *vp;
1840 {
1841     int hash = VOLUME_HASH(hashid);
1842     vp->hashid = hashid;
1843     vp->hashNext = VolumeHashTable[hash];
1844     VolumeHashTable[hash] = vp;
1845     vp->vnodeHashOffset = VolumeHashOffset_r();
1846 }    
1847
1848 static void DeleteVolumeFromHashTable(vp)
1849 register Volume *vp;
1850 {
1851     int hash = VOLUME_HASH(vp->hashid);
1852     if (VolumeHashTable[hash] == vp)
1853         VolumeHashTable[hash] = vp->hashNext;
1854     else {
1855         Volume *tvp = VolumeHashTable[hash];
1856         if (tvp == NULL)
1857             return;
1858         while (tvp->hashNext && tvp->hashNext != vp)
1859             tvp = tvp->hashNext;
1860         if (tvp->hashNext == NULL)
1861             return;
1862         tvp->hashNext = vp->hashNext;
1863     }
1864     vp->hashid = 0;
1865 }
1866
1867 void VPrintCacheStats_r(void)
1868 {
1869     register struct VnodeClassInfo *vcp;
1870     vcp = &VnodeClassInfo[vLarge];
1871     Log("Large vnode cache, %d entries, %d allocs, %d gets (%d reads), %d writes\n",
1872         vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1873     vcp = &VnodeClassInfo[vSmall];
1874     Log("Small vnode cache,%d entries, %d allocs, %d gets (%d reads), %d writes\n",
1875         vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1876     Log("Volume header cache, %d entries, %d gets, %d replacements\n",
1877         VolumeCacheSize, VolumeGets, VolumeReplacements);
1878 }
1879
1880 void VPrintCacheStats(void)
1881 {
1882     VOL_LOCK
1883     VPrintCacheStats_r();
1884     VOL_UNLOCK
1885 }
1886