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