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