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