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