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