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