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