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