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