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