vol-prototyping-20030309
[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     if (h == NULL) {
392         *ec = VSALVAGE;
393         return;
394     }
395
396     fdP = IH_OPEN(h);
397     if (fdP == NULL) {
398         *ec = VSALVAGE;
399         return;
400     }
401
402     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
403         *ec = VSALVAGE;
404         FDH_REALLYCLOSE(fdP);
405         return;
406     }
407     vsn = (struct versionStamp *) to;
408     if (FDH_READ(fdP, to, size) != size || vsn->magic != magic) {
409         *ec = VSALVAGE;
410         FDH_REALLYCLOSE(fdP);
411         return;
412     }
413     FDH_CLOSE(fdP);
414
415     /* Check is conditional, in case caller wants to inspect version himself */
416     if (version && vsn->version != version) {
417         *ec = VSALVAGE;
418     }
419 }
420
421 /* VolumeHeaderToDisk
422  * Allows for storing 64 bit inode numbers in on-disk volume header
423  * file.
424  */
425 void VolumeHeaderToDisk(VolumeDiskHeader_t *dh, VolumeHeader_t *h)
426 {
427
428     memset((char*)dh, 0, sizeof(VolumeDiskHeader_t));
429     dh->stamp = h->stamp;
430     dh->id = h->id;
431     dh->parent = h->parent;
432
433 #ifdef AFS_64BIT_IOPS_ENV
434     dh->volumeInfo_lo = (afs_int32) h->volumeInfo & 0xffffffff;
435     dh->volumeInfo_hi = (afs_int32) (h->volumeInfo >> 32) & 0xffffffff;
436     dh->smallVnodeIndex_lo = (afs_int32) h->smallVnodeIndex & 0xffffffff;
437     dh->smallVnodeIndex_hi = (afs_int32) (h->smallVnodeIndex >> 32) & 0xffffffff;
438     dh->largeVnodeIndex_lo = (afs_int32) h->largeVnodeIndex & 0xffffffff;
439     dh->largeVnodeIndex_hi = (afs_int32) (h->largeVnodeIndex >> 32) & 0xffffffff;
440     dh->linkTable_lo = (afs_int32) h->linkTable & 0xffffffff;
441     dh->linkTable_hi = (afs_int32) (h->linkTable >> 32) & 0xffffffff;
442 #else
443     dh->volumeInfo_lo = h->volumeInfo;
444     dh->smallVnodeIndex_lo = h->smallVnodeIndex;
445     dh->largeVnodeIndex_lo = h->largeVnodeIndex;
446     dh->linkTable_lo = h->linkTable;
447 #endif
448 }
449
450 /* DiskToVolumeHeader
451  * Reads volume header file from disk, convering 64 bit inodes
452  * if required. Makes the assumption that AFS has *always* 
453  * zero'd the volume header file so that high parts of inode
454  * numbers are 0 in older (SGI EFS) volume header files.
455  */
456 void DiskToVolumeHeader(VolumeHeader_t *h, VolumeDiskHeader_t *dh)
457 {
458     memset((char*)h, 0, sizeof(VolumeHeader_t));
459     h->stamp = dh->stamp;
460     h->id = dh->id;
461     h->parent = dh->parent;
462
463 #ifdef AFS_64BIT_IOPS_ENV
464     h->volumeInfo = dh->volumeInfo_lo | ((Inode)dh->volumeInfo_hi << 32);
465     
466     h->smallVnodeIndex = dh->smallVnodeIndex_lo |
467         ((Inode)dh->smallVnodeIndex_hi << 32);
468
469     h->largeVnodeIndex = dh->largeVnodeIndex_lo |
470         ((Inode)dh->largeVnodeIndex_hi << 32);
471     h->linkTable = dh->linkTable_lo |
472         ((Inode)dh->linkTable_hi << 32);
473 #else
474     h->volumeInfo = dh->volumeInfo_lo;
475     h->smallVnodeIndex = dh->smallVnodeIndex_lo;
476     h->largeVnodeIndex = dh->largeVnodeIndex_lo;
477     h->linkTable = dh->linkTable_lo;
478 #endif
479 }
480
481
482 void WriteVolumeHeader_r(ec, vp)
483     Error *ec;
484     Volume *vp;
485 {
486     IHandle_t *h = V_diskDataHandle(vp);
487     FdHandle_t *fdP;
488
489     *ec = 0;
490
491     fdP = IH_OPEN(h);
492     if (fdP == NULL) {
493         *ec = VSALVAGE;
494         return;
495     }
496     if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
497         *ec = VSALVAGE;
498         FDH_REALLYCLOSE(fdP);
499         return;
500     }
501     if (FDH_WRITE(fdP, (char*)&V_disk(vp), sizeof(V_disk(vp)))
502         != sizeof(V_disk(vp))) {
503         *ec = VSALVAGE;
504         FDH_REALLYCLOSE(fdP);
505         return;
506     }
507     FDH_CLOSE(fdP);
508 }
509
510 /* Attach an existing volume, given its pathname, and return a
511    pointer to the volume header information.  The volume also
512    normally goes online at this time.  An offline volume
513    must be reattached to make it go online */
514 Volume *
515 VAttachVolumeByName(Error *ec, char *partition, char *name, 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(Error *ec, char *partition, char *name, int mode)
528 {
529     register Volume *vp;
530     int fd,n;
531 #ifdef AFS_LARGEFILE_ENV
532     struct stat64 status;
533 #else /* !AFS_LARGEFILE_ENV */
534     struct stat status;
535 #endif /* !AFS_LARGEFILE_ENV */
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
572 #ifdef AFS_LARGEFILE_ENV
573         || fstat64(fd,&status) == -1
574 #else /* !AFS_LARGEFILE_ENV */
575         || fstat(fd,&status) == -1
576 #endif /* !AFS_LARGEFILE_ENV */
577         ) {
578         close(fd);
579         VOL_LOCK
580         *ec = VNOVOL;
581         goto done;
582     }
583     n = read(fd, &diskHeader, sizeof (diskHeader));
584     close(fd);
585     VOL_LOCK
586     if (n != sizeof (diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
587         Log("VAttachVolume: Error reading volume header %s\n", path);
588         *ec = VSALVAGE;
589         goto done;
590     }
591     if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
592         Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n",path);
593         *ec = VSALVAGE;
594         goto done;
595     }
596     
597     DiskToVolumeHeader(&iheader, &diskHeader);
598     if (programType == volumeUtility && mode != V_SECRETLY) {
599         if (FSYNC_askfs(iheader.id, partition, FSYNC_NEEDVOLUME, mode)
600             == FSYNC_DENIED) {
601             Log("VAttachVolume: attach of volume %u apparently denied by file server\n",
602                 iheader.id);
603             *ec = VNOVOL; /* XXXX */
604             goto done;
605         }
606     }
607
608     vp = attach2(ec, path, &iheader, partp, isbusy);
609     if (programType == volumeUtility && vp) {
610         /* duplicate computation in fssync.c about whether the server
611          * takes the volume offline or not.  If the volume isn't
612          * offline, we must not return it when we detach the volume,
613          * or the server will abort */
614         if (mode == V_READONLY || (!VolumeWriteable(vp) && (mode==V_CLONE || mode==V_DUMP)))
615             vp->needsPutBack = 0;
616         else
617             vp->needsPutBack = 1;
618     }
619     /* OK, there's a problem here, but one that I don't know how to
620      * fix right now, and that I don't think should arise often.
621      * Basically, we should only put back this volume to the server if
622      * it was given to us by the server, but since we don't have a vp,
623      * we can't run the VolumeWriteable function to find out as we do
624      * above when computing vp->needsPutBack.  So we send it back, but
625      * there's a path in VAttachVolume on the server which may abort
626      * if this volume doesn't have a header.  Should be pretty rare
627      * for all of that to happen, but if it does, probably the right
628      * fix is for the server to allow the return of readonly volumes
629      * that it doesn't think are really checked out. */
630     if (programType == volumeUtility && vp == NULL && mode != V_SECRETLY) {
631         FSYNC_askfs(iheader.id, partition, FSYNC_ON, 0);
632     }   
633     else if (programType == fileServer && vp) {
634             V_needsCallback(vp) = 0;
635 #ifdef  notdef
636             if (VInit >= 2 && V_BreakVolumeCallbacks) {
637                 Log("VAttachVolume: Volume %u was changed externally; breaking callbacks\n", V_id(vp));
638                 (*V_BreakVolumeCallbacks)(V_id(vp));
639             }
640 #endif
641         VUpdateVolume_r(ec,vp);
642         if (*ec) {
643             Log("VAttachVolume: Error updating volume\n");
644             if (vp)
645                 VPutVolume_r(vp);
646             goto done;
647         }
648         if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
649             /* This is a hack: by temporarily settint the incore
650              * dontSalvage flag ON, the volume will be put back on the
651              * Update list (with dontSalvage OFF again).  It will then
652              * come back in N minutes with DONT_SALVAGE eventually
653              * set.  This is the way that volumes that have never had
654              * it set get it set; or that volumes that have been
655              * offline without DONT SALVAGE having been set also
656              * eventually get it set */
657             V_dontSalvage(vp) = DONT_SALVAGE;
658             VAddToVolumeUpdateList_r(ec,vp);
659             if (*ec) {
660                 Log("VAttachVolume: Error adding volume to update list\n");
661                 if (vp)
662                     VPutVolume_r(vp);
663                 goto done;
664             }
665         }
666         if (LogLevel)
667             Log("VOnline:  volume %u (%s) attached and online\n",
668                 V_id(vp), V_name(vp));
669     }
670 done:
671     if (programType == volumeUtility) {
672         VUnlockPartition_r(partition);
673     }
674     if (*ec)
675         return NULL;
676     else
677         return vp;
678 }
679
680 private Volume *attach2(Error *ec, char *path, register struct VolumeHeader 
681                         *header, struct DiskPartition *partp, int isbusy)
682 {
683     register Volume *vp;
684
685     VOL_UNLOCK
686     vp = (Volume *) calloc(1, sizeof(Volume));
687     assert(vp != NULL);
688     vp->specialStatus = (isbusy ? VBUSY : 0);
689     vp->device = partp->device;
690     vp->partition = partp;
691     IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header->parent,
692                    header->largeVnodeIndex);
693     IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header->parent,
694                    header->smallVnodeIndex);
695     IH_INIT(vp->diskDataHandle, partp->device, header->parent,
696                    header->volumeInfo);
697     IH_INIT(vp->linkHandle, partp->device, header->parent,
698                    header->linkTable);
699     vp->cacheCheck = ++VolumeCacheCheck;
700     /* just in case this ever rolls over */
701     if (!vp->cacheCheck) 
702         vp->cacheCheck = ++VolumeCacheCheck;
703     vp->shuttingDown = 0;
704     vp->goingOffline = 0;
705     vp->nUsers = 1;
706     VOL_LOCK
707     GetVolumeHeader(vp);
708     VOL_UNLOCK
709     (void) ReadHeader(ec, V_diskDataHandle(vp),
710                       (char *)&V_disk(vp), sizeof(V_disk(vp)), 
711                       VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
712     VOL_LOCK
713     if (*ec) {
714       Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%d\n",
715         path, *ec);
716     }
717     if (!*ec) {
718         struct IndexFileHeader iHead;
719
720 #if OPENAFS_VOL_STATS
721         /*
722          * We just read in the diskstuff part of the header.  If the detailed
723          * volume stats area has not yet been initialized, we should bzero the
724          * area and mark it as initialized.
725          */
726         if (! (V_stat_initialized(vp))) {
727             memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
728             V_stat_initialized(vp) = 1;
729         }
730 #endif /* OPENAFS_VOL_STATS */
731         VOL_UNLOCK
732         (void) ReadHeader(ec, vp->vnodeIndex[vSmall].handle, 
733                           (char *)&iHead, sizeof(iHead), 
734                           SMALLINDEXMAGIC, SMALLINDEXVERSION);
735         VOL_LOCK
736         if (*ec) {
737             Log("VAttachVolume: Error reading smallVnode vol header %s; error=%d\n",
738                 path, *ec);
739         }
740     }
741     if (!*ec) {
742         struct IndexFileHeader iHead;
743         VOL_UNLOCK
744         (void) ReadHeader(ec, vp->vnodeIndex[vLarge].handle,
745                           (char *)&iHead, sizeof(iHead),
746                           LARGEINDEXMAGIC, LARGEINDEXVERSION);
747         VOL_LOCK
748         if (*ec) {
749             Log("VAttachVolume: Error reading largeVnode vol header %s; error=%d\n",
750                 path, *ec);
751         }
752     }
753 #ifdef AFS_NAMEI_ENV
754     if (!*ec) {
755         struct versionStamp stamp;
756         VOL_UNLOCK
757         (void) ReadHeader(ec, V_linkHandle(vp),
758                           (char *)&stamp, sizeof(stamp),
759                           LINKTABLEMAGIC, LINKTABLEVERSION);
760         VOL_LOCK
761         if (*ec) {
762             Log("VAttachVolume: Error reading namei vol header %s; error=%d\n",
763                 path, *ec);
764         }
765     }
766 #endif
767     if (*ec) {
768         Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%d\n",
769             path, *ec);
770         FreeVolume(vp);
771         return NULL;
772     }
773     if (V_needsSalvaged(vp)) {
774         if (vp->specialStatus) vp->specialStatus = 0;
775         Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
776         *ec = VSALVAGE;
777         return NULL;
778     }
779     if (programType == fileServer) {
780 #ifndef FAST_RESTART
781         if (V_inUse(vp) && VolumeWriteable(vp)) {
782             if (!V_needsSalvaged(vp)) {
783                 V_needsSalvaged(vp) = 1;
784                 VUpdateVolume_r(ec,vp);
785             }
786             FreeVolume(vp);
787             Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
788             *ec = VSALVAGE;
789             return NULL;
790         }
791 #endif /* FAST_RESTART */
792         if (V_destroyMe(vp) == DESTROY_ME) {
793             FreeVolume(vp);
794             Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
795             *ec = VNOVOL;
796             return NULL;
797         }
798     }
799
800     AddVolumeToHashTable(vp, V_id(vp));
801     vp->nextVnodeUnique = V_uniquifier(vp);
802     vp->vnodeIndex[vSmall].bitmap = vp->vnodeIndex[vLarge].bitmap = NULL;
803 #ifndef BITMAP_LATER
804     if (programType == fileServer && VolumeWriteable(vp)) {
805         int i;
806         for (i = 0; i<nVNODECLASSES; i++) {
807             VOL_UNLOCK
808             GetBitmap(ec,vp,i);
809             VOL_LOCK
810             if (*ec) {
811                 FreeVolume(vp);
812                 Log("VAttachVolume: error getting bitmap for volume (%s)\n", path);
813                 return NULL;
814             }
815         }
816     }
817 #endif /* BITMAP_LATER */
818
819     if (programType == fileServer) {
820         if (vp->specialStatus) vp->specialStatus = 0;
821         if (V_blessed(vp) && V_inService(vp) && !V_needsSalvaged(vp)) {
822             V_inUse(vp) = 1;
823             V_offlineMessage(vp)[0] = '\0';
824         }
825     }
826
827     return vp;
828 }
829
830 /* Attach an existing volume.
831    The volume also normally goes online at this time.
832    An offline volume must be reattached to make it go online.
833  */
834
835 Volume *
836 VAttachVolume(Error *ec, VolumeId volumeId, int mode)
837 {
838     Volume *retVal;
839     VATTACH_LOCK
840     VOL_LOCK
841     retVal = VAttachVolume_r(ec, volumeId, mode);
842     VOL_UNLOCK
843     VATTACH_UNLOCK
844     return retVal;
845 }
846
847 Volume *
848 VAttachVolume_r(Error *ec, VolumeId volumeId, 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(Error *ec, VolId volumeId)
961 {
962     Volume *retVal;
963     VOL_LOCK
964     retVal = VGetVolume_r(ec,volumeId);
965     VOL_UNLOCK
966     return retVal;
967 }
968
969 Volume *VGetVolume_r(Error *ec, VolId volumeId)
970 {
971     Volume *vp;
972     unsigned short V0=0, V1=0, V2=0, V3=0, V4=0, V5=0, V6=0, V7=0, V8=0, V9=0;
973     unsigned short V10=0, V11=0, V12=0, V13=0, V14=0, V15=0;
974
975     for(;;) {
976         *ec = 0;
977         V0++;
978         for (vp = VolumeHashTable[VOLUME_HASH(volumeId)];
979              vp && vp->hashid != volumeId; vp = vp->hashNext)
980             Vlooks++;
981
982         if (!vp) {
983           V1++;
984           if (VInit < 2) {
985             V2++;
986             /* Until we have reached an initialization level of 2
987                we don't know whether this volume exists or not.
988                We can't sleep and retry later because before a volume
989                is attached, the caller tries to get it first.  Just
990                return VOFFLINE and the caller can choose whether to
991                retry the command or not.*/
992             *ec = VOFFLINE;
993             break;
994           }
995
996           *ec = VNOVOL;
997           break;
998         }
999
1000         V3++;
1001         VolumeGets++;
1002         if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
1003           V5++;
1004             VolumeReplacements++;
1005             ReadHeader(ec, V_diskDataHandle(vp),
1006                 (char *)&V_disk(vp), sizeof(V_disk(vp)), VOLUMEINFOMAGIC,
1007                           VOLUMEINFOVERSION);
1008             if (*ec) {
1009               V6++;
1010                 /* Only log the error if it was a totally unexpected error.  Simply
1011                    a missing inode is likely to be caused by the volume being deleted */
1012                 if (errno != ENXIO || LogLevel)
1013                     Log("Volume %u: couldn't reread volume header\n", vp->hashid);
1014                 FreeVolume(vp);
1015                 vp = 0;
1016                 break;
1017             }
1018         }
1019         V7++;
1020         if (vp->shuttingDown) {
1021           V8++;
1022             *ec = VNOVOL;
1023             vp = 0;
1024             break;
1025         }
1026         if (programType == fileServer) {
1027           V9++;
1028             if (vp->goingOffline) {
1029               V10++;
1030 #ifdef AFS_PTHREAD_ENV
1031                 pthread_cond_wait(&vol_put_volume_cond, &vol_glock_mutex);
1032 #else /* AFS_PTHREAD_ENV */
1033                 LWP_WaitProcess(VPutVolume);
1034 #endif /* AFS_PTHREAD_ENV */
1035                 continue;
1036             }
1037             if (vp->specialStatus) {
1038               V11++;
1039                 *ec = vp->specialStatus;
1040               }
1041             else if (V_inService(vp)==0 || V_blessed(vp)==0) {
1042               V12++;
1043                 *ec = VNOVOL;
1044               }
1045             else if (V_inUse(vp)==0) {
1046               V13++;
1047                 *ec = VOFFLINE;
1048               }
1049           else {
1050               V14++;
1051           }
1052         }
1053         break;
1054     }
1055     V15++;
1056     /* if no error, bump nUsers */
1057     if (vp) vp->nUsers++;
1058
1059     assert (vp || *ec);
1060     return vp;
1061 }
1062
1063
1064 /* For both VForceOffline and VOffline, we close all relevant handles.
1065  * For VOffline, if we re-attach the volume, the files may possible be
1066  * different than before. 
1067  */
1068 static void VReleaseVolumeHandles_r(Volume *vp)
1069 {
1070     DFlushVolume(V_id(vp));
1071     VReleaseVnodeFiles_r(vp);
1072
1073     /* Too time consuming and unnecessary for the volserver */
1074     if (programType != volumeUtility) {
1075        IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1076        IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1077        IH_CONDSYNC(vp->diskDataHandle);
1078 #ifdef AFS_NT40_ENV
1079        IH_CONDSYNC(vp->linkHandle);
1080 #endif /* AFS_NT40_ENV */
1081     }
1082
1083     IH_RELEASE(vp->vnodeIndex[vLarge].handle);
1084     IH_RELEASE(vp->vnodeIndex[vSmall].handle);
1085     IH_RELEASE(vp->diskDataHandle);
1086     IH_RELEASE(vp->linkHandle);
1087 }
1088
1089 /* Force the volume offline, set the salvage flag.  No further references to
1090  * the volume through the volume package will be honored. */
1091 void VForceOffline_r(Volume *vp)
1092 {
1093     Error error;
1094     if (!V_inUse(vp))
1095        return;
1096     strcpy(V_offlineMessage(vp), "Forced offline due to internal error: volume needs to be salvaged");
1097     Log("Volume %u forced offline:  it needs salvaging!\n", V_id(vp));
1098     V_inUse(vp) = 0;
1099     vp->goingOffline = 0;    
1100     V_needsSalvaged(vp) = 1;
1101     VUpdateVolume_r(&error, vp);
1102 #ifdef AFS_PTHREAD_ENV
1103     assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1104 #else /* AFS_PTHREAD_ENV */
1105     LWP_NoYieldSignal(VPutVolume);
1106 #endif /* AFS_PTHREAD_ENV */
1107
1108     VReleaseVolumeHandles_r(vp);
1109
1110 }
1111
1112 void VForceOffline(Volume *vp)
1113 {
1114     VOL_LOCK
1115     VForceOffline_r(vp);
1116     VOL_UNLOCK
1117 }
1118
1119 /* The opposite of VAttachVolume.  The volume header is written to disk, with
1120    the inUse bit turned off.  A copy of the header is maintained in memory,
1121    however (which is why this is VOffline, not VDetach).
1122  */   
1123 void VOffline_r(Volume *vp, char *message)
1124 {
1125     Error error;
1126     VolumeId vid = V_id(vp);
1127     assert(programType != volumeUtility);
1128     if (!V_inUse(vp)) {
1129         VPutVolume_r(vp);
1130         return;
1131     }
1132     if (V_offlineMessage(vp)[0] == '\0')
1133         strncpy(V_offlineMessage(vp),message,
1134                 sizeof(V_offlineMessage(vp)));
1135     V_offlineMessage(vp)[sizeof(V_offlineMessage(vp))-1] = '\0';
1136     vp->goingOffline = 1;    
1137     VPutVolume_r(vp);
1138     vp = VGetVolume_r(&error, vid);     /* Wait for it to go offline */
1139     if (vp)  /* In case it was reattached... */
1140         VPutVolume_r(vp);
1141 }
1142
1143 void VOffline(Volume *vp, char *message)
1144 {
1145     VOL_LOCK
1146     VOffline_r(vp, message);
1147     VOL_UNLOCK
1148 }
1149
1150 /* For VDetachVolume, we close all cached file descriptors, but keep
1151  * the Inode handles in case we need to read from a busy volume.
1152  */
1153 static void VCloseVolumeHandles_r(Volume *vp)
1154 {
1155     DFlushVolume(V_id(vp));
1156     VCloseVnodeFiles_r(vp);
1157
1158     /* Too time consuming and unnecessary for the volserver */
1159     if (programType != volumeUtility) {
1160        IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1161        IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1162        IH_CONDSYNC(vp->diskDataHandle);
1163 #ifdef AFS_NT40_ENV
1164        IH_CONDSYNC(vp->linkHandle);
1165 #endif /* AFS_NT40_ENV */
1166     }
1167
1168     IH_REALLYCLOSE(vp->vnodeIndex[vLarge].handle);
1169     IH_REALLYCLOSE(vp->vnodeIndex[vSmall].handle);
1170     IH_REALLYCLOSE(vp->diskDataHandle);
1171     IH_REALLYCLOSE(vp->linkHandle);
1172 }
1173
1174 /* This gets used for the most part by utility routines that don't want
1175  * to keep all the volume headers around.  Generally, the file server won't
1176  * call this routine, because then the offline message in the volume header
1177  * (or other information) will still be available to clients. For NAMEI, also
1178  * close the file handles.
1179  */
1180 void VDetachVolume_r(Error *ec, Volume *vp)
1181 {
1182     VolumeId volume;
1183     struct DiskPartition *tpartp;
1184     int notifyServer, useDone;
1185
1186     *ec = 0;    /* always "succeeds" */
1187     if (programType == volumeUtility) {
1188         notifyServer = vp->needsPutBack;
1189         useDone = (V_destroyMe(vp) == DESTROY_ME);
1190     }
1191     tpartp = vp->partition;
1192     volume = V_id(vp);
1193     DeleteVolumeFromHashTable(vp);
1194     vp->shuttingDown = 1;
1195     VPutVolume_r(vp);
1196     /* Will be detached sometime in the future--this is OK since volume is offline */
1197
1198     if (programType == volumeUtility && notifyServer) {
1199         /* 
1200          * Note:  The server is not notified in the case of a bogus volume 
1201          * explicitly to make it possible to create a volume, do a partial 
1202          * restore, then abort the operation without ever putting the volume 
1203          * online.  This is essential in the case of a volume move operation 
1204          * between two partitions on the same server.  In that case, there 
1205          * would be two instances of the same volume, one of them bogus, 
1206          * which the file server would attempt to put on line 
1207          */
1208         if (useDone)
1209             /* don't put online */
1210             FSYNC_askfs(volume, tpartp->name, FSYNC_DONE, 0);   
1211         else {
1212             /* fs can use it again */
1213             FSYNC_askfs(volume, tpartp->name, FSYNC_ON, 0);     
1214             /* Dettaching it so break all callbacks on it*/
1215             if (V_BreakVolumeCallbacks) {
1216                 Log("volume %u detached; breaking all call backs\n", volume);
1217                 (*V_BreakVolumeCallbacks)(volume);
1218             }
1219         }
1220     }
1221 }
1222
1223 void VDetachVolume(Error *ec, Volume *vp)
1224 {
1225     VOL_LOCK
1226     VDetachVolume_r(ec, vp);
1227     VOL_UNLOCK
1228 }
1229
1230
1231 int VAllocBitmapEntry_r(Error *ec, Volume *vp, register struct vnodeIndex
1232                         *index)
1233 {
1234     register byte *bp,*ep;
1235     *ec = 0;
1236     /* This test is probably redundant */
1237     if (!VolumeWriteable(vp)) {
1238         *ec = VREADONLY;
1239         return 0;
1240     }
1241 #ifdef BITMAP_LATER
1242     if ((programType == fileServer) && !index->bitmap) {
1243         int i;
1244         int wasVBUSY = 0;
1245         if (vp->specialStatus == VBUSY) {
1246             if (vp->goingOffline) { /* vos dump waiting for the volume to
1247                                        go offline. We probably come here
1248                                        from AddNewReadableResidency */
1249                 wasVBUSY = 1;
1250             } else {
1251                 VOL_UNLOCK
1252                 while (vp->specialStatus == VBUSY)
1253 #ifdef AFS_PTHREAD_ENV
1254                     sleep(2);
1255 #else /* AFS_PTHREAD_ENV */
1256                     IOMGR_Sleep(2);
1257 #endif /* AFS_PTHREAD_ENV */
1258                 VOL_LOCK
1259             }
1260         }
1261         if (!index->bitmap) {
1262             vp->specialStatus = VBUSY; /* Stop anyone else from using it.*/
1263             for (i = 0; i<nVNODECLASSES; i++) {
1264                 VOL_UNLOCK
1265                 GetBitmap(ec,vp,i);
1266                 VOL_LOCK
1267                 if (*ec) {
1268                     vp->specialStatus = 0;
1269                     vp->shuttingDown = 1; /* Let who has it free it. */
1270                     return NULL;
1271                 }
1272             }
1273             if (!wasVBUSY)
1274                 vp->specialStatus = 0; /* Allow others to have access. */
1275         }
1276     }
1277 #endif /* BITMAP_LATER */
1278     bp = index->bitmap + index->bitmapOffset;
1279     ep = index->bitmap + index->bitmapSize;
1280     while (bp < ep) {
1281         if ((*(bit32 *)bp) != 0xffffffff) {
1282             int o;
1283             index->bitmapOffset = bp - index->bitmap;
1284             while (*bp == 0xff)
1285                 bp++;       
1286             o = ffs(~*bp)-1;  /* ffs is documented in BSTRING(3) */
1287             *bp |= (1 << o);
1288             return (bp - index->bitmap)*8 + o;
1289         }
1290         bp += sizeof(bit32) /* i.e. 4 */;
1291     }
1292     /* No bit map entry--must grow bitmap */
1293     bp = (byte *)
1294         realloc(index->bitmap, index->bitmapSize+VOLUME_BITMAP_GROWSIZE);
1295     assert(bp != NULL);
1296     index->bitmap = bp;
1297     bp += index->bitmapSize;
1298     memset(bp, 0, VOLUME_BITMAP_GROWSIZE);
1299     index->bitmapOffset = index->bitmapSize;
1300     index->bitmapSize += VOLUME_BITMAP_GROWSIZE;
1301     *bp = 1;
1302     return index->bitmapOffset*8;
1303 }
1304
1305 int VAllocBitmapEntry(Error *ec, Volume *vp, register struct vnodeIndex *index)
1306 {
1307     int retVal;
1308     VOL_LOCK
1309     retVal = VAllocBitmapEntry_r(ec,vp,index);
1310     VOL_UNLOCK
1311     return retVal;
1312 }
1313
1314 void VFreeBitMapEntry_r(Error *ec, register struct vnodeIndex *index,
1315                       int bitNumber)
1316 {
1317     unsigned int offset;
1318      *ec = 0;
1319 #ifdef BITMAP_LATER
1320      if (!index->bitmap) return;
1321 #endif /* BITMAP_LATER */
1322      offset = bitNumber>>3;
1323      if (offset >= index->bitmapSize) {
1324         *ec = VNOVNODE;
1325         return;
1326      }
1327      if (offset < index->bitmapOffset)
1328         index->bitmapOffset = offset&~3;        /* Truncate to nearest bit32 */
1329      *(index->bitmap + offset) &= ~(1 << (bitNumber & 0x7));
1330 }
1331
1332 void VFreeBitMapEntry(Error *ec, register struct vnodeIndex *index,
1333                       int bitNumber)
1334 {
1335     VOL_LOCK
1336     VFreeBitMapEntry_r(ec, index, bitNumber);
1337     VOL_UNLOCK
1338 }
1339
1340 void VUpdateVolume_r(Error *ec,Volume *vp)
1341 {
1342     *ec = 0;
1343     if (programType == fileServer) 
1344         V_uniquifier(vp) = (V_inUse(vp)? V_nextVnodeUnique(vp) + 200: V_nextVnodeUnique(vp));
1345     /*printf("Writing volume header for '%s'\n", V_name(vp));*/
1346     WriteVolumeHeader_r(ec, vp);
1347     if (*ec) {
1348         Log(
1349           "VUpdateVolume: error updating volume header, volume %u (%s)\n",
1350             V_id(vp), V_name(vp));
1351         VForceOffline_r(vp);
1352     }
1353 }
1354
1355 void VUpdateVolume(Error *ec, Volume *vp)
1356 {
1357     VOL_LOCK
1358     VUpdateVolume_r(ec, vp);
1359     VOL_UNLOCK
1360 }
1361
1362 void VSyncVolume_r(Error *ec, Volume *vp)
1363 {
1364     FdHandle_t *fdP;
1365     VUpdateVolume_r(ec, vp);
1366     if (!ec) {
1367         int code;
1368         fdP = IH_OPEN(V_diskDataHandle(vp));
1369         assert(fdP != NULL);
1370         code = FDH_SYNC(fdP);
1371         assert(code == 0);
1372         FDH_CLOSE(fdP);
1373     }
1374 }
1375
1376 void VSyncVolume(Error *ec, Volume *vp)
1377 {
1378     VOL_LOCK
1379     VSyncVolume_r(ec, vp);
1380     VOL_UNLOCK
1381 }
1382
1383 static void FreeVolume(Volume *vp)
1384 {
1385     int i;
1386     if (!vp)
1387         return;
1388     for (i = 0; i<nVNODECLASSES; i++)
1389         if (vp->vnodeIndex[i].bitmap)
1390             free(vp->vnodeIndex[i].bitmap);
1391     FreeVolumeHeader(vp);
1392     DeleteVolumeFromHashTable(vp);
1393     free(vp);
1394 }
1395
1396 static void GetBitmap(Error *ec, Volume *vp, VnodeClass class)
1397 {
1398     StreamHandle_t *file;
1399     int nVnodes;
1400     int size;
1401     int counter = 0;
1402     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1403     struct vnodeIndex *vip = &vp->vnodeIndex[class];
1404     struct VnodeDiskObject *vnode;
1405     unsigned int unique = 0;
1406     FdHandle_t *fdP;
1407 #ifdef BITMAP_LATER
1408     byte *BitMap = 0;
1409 #endif /* BITMAP_LATER */
1410
1411     *ec = 0;
1412
1413     fdP = IH_OPEN(vip->handle);
1414     assert (fdP != NULL);
1415     file = FDH_FDOPEN(fdP, "r");
1416     assert (file != NULL);
1417     vnode = (VnodeDiskObject *) malloc(vcp->diskSize);
1418     assert(vnode != NULL);
1419     size = OS_SIZE(fdP->fd_fd);
1420     assert(size != -1);
1421     nVnodes = (size <= vcp->diskSize? 0: size-vcp->diskSize)
1422                 >> vcp->logSize;
1423     vip->bitmapSize = ((nVnodes/8)+10)/4*4; /* The 10 is a little extra so
1424                                 a few files can be created in this volume,
1425                                 the whole thing is rounded up to nearest 4
1426                                 bytes, because the bit map allocator likes
1427                                 it that way */
1428 #ifdef BITMAP_LATER
1429     BitMap = (byte *) calloc(1, vip->bitmapSize);
1430     assert(BitMap != NULL);
1431 #else /* BITMAP_LATER */
1432     vip->bitmap = (byte *) calloc(1, vip->bitmapSize);
1433     assert(vip->bitmap != NULL);
1434     vip->bitmapOffset = 0;
1435 #endif /* BITMAP_LATER */
1436     if (STREAM_SEEK(file,vcp->diskSize,0) != -1) {
1437       int bitNumber = 0;
1438       for (bitNumber = 0; bitNumber < nVnodes+100; bitNumber++) {
1439         if (STREAM_READ(vnode, vcp->diskSize, 1, file) != 1) 
1440           break;
1441         if (vnode->type != vNull) {
1442           if (vnode->vnodeMagic != vcp->magic) {
1443             Log("GetBitmap: addled vnode index in volume %s; volume needs salvage\n",
1444                 V_name(vp));
1445             *ec = VSALVAGE;
1446             break;
1447           }
1448 #ifdef BITMAP_LATER
1449           *(BitMap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1450 #else /* BITMAP_LATER */
1451           *(vip->bitmap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1452 #endif /* BITMAP_LATER */
1453           if (unique <= vnode->uniquifier)
1454             unique = vnode->uniquifier + 1; 
1455         }
1456 #ifndef AFS_PTHREAD_ENV
1457         if ((bitNumber & 0x00ff) == 0x0ff) { /* every 256 iterations */
1458           IOMGR_Poll();
1459         }
1460 #endif /* !AFS_PTHREAD_ENV */
1461       }
1462     }
1463     if (vp->nextVnodeUnique < unique) {
1464         Log("GetBitmap: bad volume uniquifier for volume %s; volume needs salvage\n", V_name(vp));
1465         *ec = VSALVAGE;
1466     }
1467     /* Paranoia, partly justified--I think fclose after fdopen
1468      * doesn't seem to close fd.  In any event, the documentation
1469      * doesn't specify, so it's safer to close it twice.
1470      */
1471     STREAM_CLOSE(file);
1472     FDH_CLOSE(fdP);
1473     free(vnode);
1474 #ifdef BITMAP_LATER
1475     /* There may have been a racing condition with some other thread, both
1476      * creating the bitmaps for this volume. If the other thread was faster
1477      * the pointer to bitmap should already be filled and we can free ours.
1478      */
1479     if (vip->bitmap == NULL) {
1480         vip->bitmap = BitMap;
1481         vip->bitmapOffset = 0;
1482     } else 
1483         free((byte *)BitMap);
1484 #endif /* BITMAP_LATER */
1485 }
1486
1487 static void GetVolumePath(Error *ec, VolId volumeId, char **partitionp,
1488                      char **namep)
1489 {
1490     static char partition[VMAXPATHLEN], name[VMAXPATHLEN];
1491     char path[VMAXPATHLEN];
1492     int found = 0;
1493     struct DiskPartition *dp;
1494
1495     *ec = 0;
1496     name[0] = '/';
1497     sprintf(&name[1],VFORMAT,volumeId);
1498     for (dp = DiskPartitionList; dp; dp = dp->next) {
1499 #ifdef AFS_LARGEFILE_ENV
1500         struct stat64 status;
1501 #else /* !AFS_LARGEFILE_ENV */
1502         struct stat status;
1503 #endif
1504         strcpy(path, VPartitionPath(dp));
1505         strcat(path, name);
1506 #ifdef AFS_LARGEFILE_ENV
1507         if (stat64(path,&status) == 0)
1508 #else /* !AFS_LARGEFILE_ENV */
1509         if (stat(path,&status) == 0)
1510 #endif /* !AFS_LARGEFILE_ENV */
1511         {
1512             strcpy(partition, dp->name);
1513             found = 1;
1514             break;
1515         }
1516     }
1517     if (!found) {
1518         *ec = VNOVOL;
1519         *partitionp = *namep = NULL;
1520     }
1521     else {
1522         *partitionp = partition;
1523         *namep = name;
1524     }
1525 }       
1526
1527 int VolumeNumber(char *name)
1528 {
1529     if (*name == '/')
1530         name++;
1531     return atoi(name+1);
1532 }
1533
1534 char *VolumeExternalName(VolumeId volumeId)
1535 {
1536     static char name[15];
1537     sprintf(name,VFORMAT,volumeId);
1538     return name;
1539 }
1540
1541 #if OPENAFS_VOL_STATS
1542 #define OneDay  (86400)                 /* 24 hours' worth of seconds */
1543 #else
1544 #define OneDay  (24*60*60)              /* 24 hours */
1545 #endif /* OPENAFS_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 int VAdjustVolumeStatistics_r(register Volume *vp)
1572 {
1573     unsigned int now = FT_ApproxTime();
1574
1575     if (now - V_dayUseDate(vp) > OneDay) {
1576         register ndays, i;
1577
1578         ndays = (now - V_dayUseDate(vp)) / OneDay;
1579         for (i = 6; i>ndays-1; i--)
1580             V_weekUse(vp)[i] = V_weekUse(vp)[i-ndays];
1581         for (i = 0; i<ndays-1 && i<7; i++)
1582             V_weekUse(vp)[i] = 0;
1583         if (ndays <= 7)
1584             V_weekUse(vp)[ndays-1] = V_dayUse(vp);
1585         V_dayUse(vp) = 0;
1586         V_dayUseDate(vp) = Midnight(now);
1587
1588 #if OPENAFS_VOL_STATS
1589         /*
1590          * All we need to do is bzero the entire VOL_STATS_BYTES of
1591          * the detailed volume statistics area.
1592          */
1593         memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
1594 #endif /* OPENAFS_VOL_STATS */
1595     } /*It's been more than a day of collection*/
1596
1597     /*
1598      * Always return happily.
1599      */
1600     return(0);
1601 } /*VAdjustVolumeStatistics*/
1602
1603 int VAdjustVolumeStatistics(register Volume *vp)
1604 {
1605     int retVal;
1606     VOL_LOCK
1607     retVal = VAdjustVolumeStatistics_r(vp);
1608     VOL_UNLOCK
1609     return retVal;
1610 }
1611
1612 void VBumpVolumeUsage_r(register Volume *vp)
1613 {
1614     unsigned int now = FT_ApproxTime();
1615     if (now - V_dayUseDate(vp) > OneDay)
1616         VAdjustVolumeStatistics_r(vp);
1617     /*
1618      * Save the volume header image to disk after every 128 bumps to dayUse.
1619      */
1620     if ((V_dayUse(vp)++ & 127) == 0) {
1621         Error error;
1622         VUpdateVolume_r(&error, vp);
1623     }
1624 }
1625
1626 void VBumpVolumeUsage(register Volume *vp)
1627 {
1628     VOL_LOCK
1629     VBumpVolumeUsage_r(vp);
1630     VOL_UNLOCK
1631 }
1632
1633 void VSetDiskUsage_r(void)
1634 {
1635     static int FifteenMinuteCounter = 0;
1636     
1637     while (VInit < 2) {
1638       /* NOTE: Don't attempt to access the partitions list until the
1639          initialization level indicates that all volumes are attached,
1640          which implies that all partitions are initialized. */
1641 #ifdef AFS_PTHREAD_ENV
1642       sleep(10);
1643 #else /* AFS_PTHREAD_ENV */
1644       IOMGR_Sleep(10);
1645 #endif /* AFS_PTHREAD_ENV */
1646     }
1647
1648     VResetDiskUsage_r();
1649     if (++FifteenMinuteCounter == 3) {
1650         FifteenMinuteCounter = 0;
1651         VScanUpdateList();
1652     }
1653 }
1654
1655 void VSetDiskUsage(void)
1656 {
1657     VOL_LOCK
1658     VSetDiskUsage_r();
1659     VOL_UNLOCK
1660 }
1661
1662 /* The number of minutes that a volume hasn't been updated before the
1663  * "Dont salvage" flag in the volume header will be turned on */
1664 #define SALVAGE_INTERVAL        (10*60)
1665
1666 static VolumeId *UpdateList;    /* Pointer to array of Volume ID's */
1667 static int nUpdatedVolumes;     /* Updated with entry in UpdateList, salvage after crash flag on */
1668 static int updateSize;          /* number of entries possible */
1669 #define UPDATE_LIST_SIZE 100    /* size increment */
1670
1671 void VAddToVolumeUpdateList_r(Error *ec, Volume *vp)
1672 {
1673     *ec = 0;
1674     vp->updateTime = FT_ApproxTime();
1675     if (V_dontSalvage(vp) == 0)
1676         return;
1677     V_dontSalvage(vp) = 0;
1678     VSyncVolume_r(ec, vp);
1679     if (*ec)
1680         return;
1681     if (!UpdateList) {
1682         updateSize = UPDATE_LIST_SIZE;
1683         UpdateList = (VolumeId *) malloc(sizeof (VolumeId) * updateSize);
1684     } else {
1685         if (nUpdatedVolumes == updateSize) {
1686             updateSize += UPDATE_LIST_SIZE;
1687             UpdateList = (VolumeId *) realloc(UpdateList, sizeof (VolumeId) * updateSize);
1688         }
1689     }
1690     assert(UpdateList != NULL);
1691     UpdateList[nUpdatedVolumes++] = V_id(vp);
1692 }
1693
1694 static void VScanUpdateList() {
1695     register int i, gap;
1696     register Volume *vp;
1697     Error error;
1698     afs_int32 now = FT_ApproxTime();
1699     /* Be careful with this code, since it works with interleaved calls to AddToVolumeUpdateList */
1700     for (i = gap = 0; i<nUpdatedVolumes; i++) {
1701         vp = VGetVolume_r(&error, UpdateList[i-gap] = UpdateList[i]);
1702         if (error) {
1703             gap++;
1704         } else if (vp->nUsers == 1 && now - vp->updateTime > SALVAGE_INTERVAL) {
1705             V_dontSalvage(vp) = DONT_SALVAGE;
1706             VUpdateVolume_r(&error, vp); /* No need to fsync--not critical */
1707             gap++;
1708         }
1709         if (vp)
1710             VPutVolume_r(vp);
1711 #ifndef AFS_PTHREAD_ENV
1712         IOMGR_Poll();
1713 #endif /* !AFS_PTHREAD_ENV */
1714     }
1715     nUpdatedVolumes -= gap;
1716 }
1717
1718 /***************************************************/
1719 /* Add on routines to manage a volume header cache */
1720 /***************************************************/
1721
1722 static struct volHeader *volumeLRU;
1723
1724 /* Allocate a bunch of headers; string them together */
1725 static void InitLRU(int howMany)
1726 {
1727     register struct volHeader *hp;
1728     if (programType != fileServer)
1729         return;
1730     hp = (struct volHeader *)(calloc(howMany, sizeof(struct volHeader)));
1731     while (howMany--)
1732         ReleaseVolumeHeader(hp++);
1733 }
1734
1735 /* Get a volume header from the LRU list; update the old one if necessary */
1736 /* Returns 1 if there was already a header, which is removed from the LRU list */
1737 static int GetVolumeHeader(register Volume *vp)
1738 {
1739     Error error;
1740     register struct volHeader *hd;
1741     int old;
1742     static int everLogged = 0;
1743
1744     old = (vp->header != 0);    /* old == volume already has a header */
1745     if (programType != fileServer) {
1746         if (!vp->header) {
1747             hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1748             assert(hd != 0);
1749             vp->header = hd;
1750             hd->back = vp;
1751         }
1752     }
1753     else {
1754         if (old) {
1755             hd = vp->header;
1756             if (volumeLRU == hd)
1757                 volumeLRU = hd->next;
1758             assert(hd->back == vp);
1759         }
1760         else {
1761             if (volumeLRU)
1762                 /* not currently in use and least recently used */
1763                 hd = volumeLRU->prev; 
1764             else {
1765                 hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1766                 /* make it look like single elt LRU */
1767                 hd->prev = hd->next = hd;       
1768                 if (!everLogged) {
1769                     Log("****Allocated more volume headers, probably leak****\n");
1770                     everLogged=1;
1771                 }
1772             }
1773             if (hd->back) {
1774                 if (hd->diskstuff.inUse) {
1775                     WriteVolumeHeader_r(&error, hd->back);
1776                     /* Ignore errors; catch them later */
1777                 }
1778                 hd->back->header = 0;
1779             }
1780             hd->back = vp;
1781             vp->header = hd;
1782         }
1783         if (hd->next) { /* hd->next != 0 --> in LRU chain (we zero it later) */
1784             hd->prev->next = hd->next;  /* pull hd out of LRU list */
1785             hd->next->prev = hd->prev;  /* if hd only element, this is noop */
1786         }
1787         hd->next = hd->prev = 0;
1788         /* if not in LRU chain, next test won't be true */
1789         if (hd == volumeLRU)    /* last header item, turn into empty list */
1790             volumeLRU = NULL;
1791     }
1792     return old;
1793 }
1794
1795 /* Put it at the top of the LRU chain */
1796 static void ReleaseVolumeHeader(register struct volHeader *hd)
1797 {
1798     if (programType != fileServer)
1799         return;
1800     if (!hd || hd->next) /* no header, or header already released */
1801         return;
1802     if (!volumeLRU) {
1803         hd->next = hd->prev = hd;
1804     } else {
1805         hd->prev = volumeLRU->prev;
1806         hd->next = volumeLRU;
1807         hd->prev->next = hd->next->prev = hd;
1808     }
1809     volumeLRU = hd;
1810 }
1811
1812 static void FreeVolumeHeader(register Volume *vp)
1813 {
1814     register struct volHeader *hd = vp->header;
1815     if (!hd)
1816         return;
1817     if (programType == fileServer) {
1818         ReleaseVolumeHeader(hd);
1819         hd->back = 0;
1820     }
1821     else {
1822         free(hd);
1823     }
1824     vp->header = 0;
1825 }
1826
1827
1828 /***************************************************/
1829 /* Routines to add volume to hash chain, delete it */
1830 /***************************************************/
1831
1832 static void AddVolumeToHashTable(register Volume *vp, int hashid)
1833 {
1834     int hash = VOLUME_HASH(hashid);
1835     vp->hashid = hashid;
1836     vp->hashNext = VolumeHashTable[hash];
1837     VolumeHashTable[hash] = vp;
1838     vp->vnodeHashOffset = VolumeHashOffset_r();
1839 }    
1840
1841 static void DeleteVolumeFromHashTable(register Volume *vp)
1842 {
1843     int hash = VOLUME_HASH(vp->hashid);
1844     if (VolumeHashTable[hash] == vp)
1845         VolumeHashTable[hash] = vp->hashNext;
1846     else {
1847         Volume *tvp = VolumeHashTable[hash];
1848         if (tvp == NULL)
1849             return;
1850         while (tvp->hashNext && tvp->hashNext != vp)
1851             tvp = tvp->hashNext;
1852         if (tvp->hashNext == NULL)
1853             return;
1854         tvp->hashNext = vp->hashNext;
1855     }
1856     vp->hashid = 0;
1857 }
1858
1859 void VPrintCacheStats_r(void)
1860 {
1861     register struct VnodeClassInfo *vcp;
1862     vcp = &VnodeClassInfo[vLarge];
1863     Log("Large vnode cache, %d entries, %d allocs, %d gets (%d reads), %d writes\n",
1864         vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1865     vcp = &VnodeClassInfo[vSmall];
1866     Log("Small vnode cache,%d entries, %d allocs, %d gets (%d reads), %d writes\n",
1867         vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1868     Log("Volume header cache, %d entries, %d gets, %d replacements\n",
1869         VolumeCacheSize, VolumeGets, VolumeReplacements);
1870 }
1871
1872 void VPrintCacheStats(void)
1873 {
1874     VOL_LOCK
1875     VPrintCacheStats_r();
1876     VOL_UNLOCK
1877 }
1878