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