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