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