2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* 1/1/89: NB: this stuff is all going to be replaced. Don't take it too seriously */
15 Institution: The Information Technology Center, Carnegie-Mellon University
19 #include <afsconfig.h>
20 #include <afs/param.h>
25 #include <afs/afsint.h>
28 #include <sys/param.h>
29 #if !defined(AFS_SGI_ENV)
32 #else /* AFS_OSF_ENV */
33 #ifdef AFS_VFSINCL_ENV
36 #include <sys/fs/ufs_fs.h>
38 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
39 #include <ufs/ufs/dinode.h>
40 #include <ufs/ffs/fs.h>
45 #else /* AFS_VFSINCL_ENV */
46 #if !defined(AFS_AIX_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV)
49 #endif /* AFS_VFSINCL_ENV */
50 #endif /* AFS_OSF_ENV */
51 #endif /* AFS_SGI_ENV */
52 #endif /* AFS_NT40_ENV */
70 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
72 #include <sys/mnttab.h>
73 #include <sys/mntent.h>
79 #if defined(AFS_SGI_ENV)
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 */
90 #ifndef AFS_LINUX20_ENV
91 #include <fstab.h> /* Need to find in libc 5, present in libc 6 */
94 #endif /* AFS_SGI_ENV */
96 #endif /* AFS_HPUX_ENV */
100 #include <netinet/in.h>
101 #include <sys/wait.h>
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)
114 #include <afs/errors.h>
117 #include <afs/afssyscalls.h>
120 #include <afs/afsutil.h>
125 #include "partition.h"
126 #ifdef AFS_PTHREAD_ENV
128 #else /* AFS_PTHREAD_ENV */
129 #include "afs/assert.h"
130 #endif /* AFS_PTHREAD_ENV */
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 */
145 extern void *calloc(), *realloc();
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,
163 static void VReleaseVolumeHandles_r(Volume *vp);
164 static void VCloseVolumeHandles_r(Volume *vp);
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 */
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];
178 /* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
181 afs_int32 ffs_tmp = x; \
182 if (ffs_tmp == 0) return(-1); \
184 for (ffs_i = 1;; ffs_i++) { \
185 if (ffs_tmp & 1) return(ffs_i); \
186 else ffs_tmp >>= 1; \
189 #endif /* !AFS_HAVE_FFS */
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 */
193 extern struct Lock FSYNC_handler_lock;
195 Volume *VAttachVolumeByName();
196 Volume *VAttachVolumeByName_r();
198 static int TimeZoneCorrection; /* Number of seconds west of GMT */
200 /* Common message used when the volume goes off line */
201 char *VSalvageMessage =
202 "Files in this volume are currently unavailable; call operations";
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. */
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 */
216 int VolumeCacheSize = 200, VolumeGets=0, VolumeReplacements=0, Vlooks = 0;
219 int VInitVolumePackage(ProgramType pt, int nLargeVnodes, int nSmallVnodes,
220 int connect, int volcache)
222 int errors = 0; /* Number of errors while finding vice partitions. */
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 */
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;
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.
248 if (programType == fileServer) {
249 /* File server or "stand" */
253 if (volcache > VolumeCacheSize)
254 VolumeCacheSize = volcache;
255 InitLRU(VolumeCacheSize);
257 VInitVnodes(vLarge, nLargeVnodes);
258 VInitVnodes(vSmall, nSmallVnodes);
261 errors = VAttachPartitions();
265 if (programType == fileServer) {
268 struct DiskPartition *diskP;
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));
276 while (dp = readdir(dirp)) {
278 p = strrchr(dp->d_name, '.');
279 if (p != NULL && strcmp(p, VHDREXT) == 0) {
282 vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
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);
293 Log("Partition %s: attached %d volumes; %d volumes not attached\n",
294 diskP->name, nAttached, nUnattached);
299 VInit = 2; /* Initialized, and all volumes have been attached */
300 if (programType == volumeUtility && connect) {
302 Log("Unable to connect to file server; aborted\n");
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 */
317 retVal = VConnectFS_r();
322 int VConnectFS_r(void)
325 assert(VInit == 2 && programType == volumeUtility);
326 rc = FSYNC_clientInit();
332 void VDisconnectFS_r(void) {
333 assert(programType == volumeUtility);
338 void VDisconnectFS(void) {
344 void VShutdown_r(void)
347 register Volume *vp, *np;
348 register afs_int32 code;
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) {
355 if (code == 0) break; /* got it */
356 /* otherwise we go around again, trying another volume */
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).
364 for(np=vp->hashNext; np; np=np->hashNext) {
366 if (code == 0) break; /* got it */
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 */
373 Log("VShutdown: complete.\n");
384 static void ReadHeader(Error *ec, IHandle_t *h, char *to, int size,
385 int magic, int version)
387 struct versionStamp *vsn;
402 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
404 FDH_REALLYCLOSE(fdP);
407 vsn = (struct versionStamp *) to;
408 if (FDH_READ(fdP, to, size) != size || vsn->magic != magic) {
410 FDH_REALLYCLOSE(fdP);
415 /* Check is conditional, in case caller wants to inspect version himself */
416 if (version && vsn->version != version) {
421 /* VolumeHeaderToDisk
422 * Allows for storing 64 bit inode numbers in on-disk volume header
425 void VolumeHeaderToDisk(VolumeDiskHeader_t *dh, VolumeHeader_t *h)
428 memset((char*)dh, 0, sizeof(VolumeDiskHeader_t));
429 dh->stamp = h->stamp;
431 dh->parent = h->parent;
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;
443 dh->volumeInfo_lo = h->volumeInfo;
444 dh->smallVnodeIndex_lo = h->smallVnodeIndex;
445 dh->largeVnodeIndex_lo = h->largeVnodeIndex;
446 dh->linkTable_lo = h->linkTable;
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.
456 void DiskToVolumeHeader(VolumeHeader_t *h, VolumeDiskHeader_t *dh)
458 memset((char*)h, 0, sizeof(VolumeHeader_t));
459 h->stamp = dh->stamp;
461 h->parent = dh->parent;
463 #ifdef AFS_64BIT_IOPS_ENV
464 h->volumeInfo = dh->volumeInfo_lo | ((Inode)dh->volumeInfo_hi << 32);
466 h->smallVnodeIndex = dh->smallVnodeIndex_lo |
467 ((Inode)dh->smallVnodeIndex_hi << 32);
469 h->largeVnodeIndex = dh->largeVnodeIndex_lo |
470 ((Inode)dh->largeVnodeIndex_hi << 32);
471 h->linkTable = dh->linkTable_lo |
472 ((Inode)dh->linkTable_hi << 32);
474 h->volumeInfo = dh->volumeInfo_lo;
475 h->smallVnodeIndex = dh->smallVnodeIndex_lo;
476 h->largeVnodeIndex = dh->largeVnodeIndex_lo;
477 h->linkTable = dh->linkTable_lo;
482 void WriteVolumeHeader_r(ec, vp)
486 IHandle_t *h = V_diskDataHandle(vp);
496 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
498 FDH_REALLYCLOSE(fdP);
501 if (FDH_WRITE(fdP, (char*)&V_disk(vp), sizeof(V_disk(vp)))
502 != sizeof(V_disk(vp))) {
504 FDH_REALLYCLOSE(fdP);
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 */
515 VAttachVolumeByName(Error *ec, char *partition, char *name, int mode)
520 retVal = VAttachVolumeByName_r(ec, partition, name, mode);
527 VAttachVolumeByName_r(Error *ec, char *partition, char *name, int mode)
531 #ifdef AFS_LARGEFILE_ENV
532 struct stat64 status;
533 #else /* !AFS_LARGEFILE_ENV */
535 #endif /* !AFS_LARGEFILE_ENV */
536 struct VolumeDiskHeader diskHeader;
537 struct VolumeHeader iheader;
538 struct DiskPartition *partp;
542 if (programType == volumeUtility) {
544 VLockPartition_r(partition);
546 if (programType == fileServer) {
547 vp = VGetVolume_r(ec, VolumeNumber(name));
551 if (vp->specialStatus == VBUSY)
553 VDetachVolume_r(ec, vp);
555 Log("VAttachVolume: Error detaching volume (%s)\n", name);
560 if (!(partp = VGetPartition_r(partition, 0))) {
562 Log("VAttachVolume: Error getting partition (%s)\n", partition);
567 strcpy(path, VPartitionPath(partp));
571 if ((fd = open(path, O_RDONLY)) == -1
572 #ifdef AFS_LARGEFILE_ENV
573 || fstat64(fd,&status) == -1
574 #else /* !AFS_LARGEFILE_ENV */
575 || fstat(fd,&status) == -1
576 #endif /* !AFS_LARGEFILE_ENV */
583 n = read(fd, &diskHeader, sizeof (diskHeader));
586 if (n != sizeof (diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
587 Log("VAttachVolume: Error reading volume header %s\n", path);
591 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
592 Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n",path);
597 DiskToVolumeHeader(&iheader, &diskHeader);
598 if (programType == volumeUtility && mode != V_SECRETLY) {
599 if (FSYNC_askfs(iheader.id, partition, FSYNC_NEEDVOLUME, mode)
601 Log("VAttachVolume: attach of volume %u apparently denied by file server\n",
603 *ec = VNOVOL; /* XXXX */
608 vp = attach2(ec, path, &iheader, partp, isbusy);
609 if (programType == volumeUtility && vp) {
610 /* duplicate computation in fssync.c about whether the server
611 * takes the volume offline or not. If the volume isn't
612 * offline, we must not return it when we detach the volume,
613 * or the server will abort */
614 if (mode == V_READONLY || (!VolumeWriteable(vp) && (mode==V_CLONE || mode==V_DUMP)))
615 vp->needsPutBack = 0;
617 vp->needsPutBack = 1;
619 /* OK, there's a problem here, but one that I don't know how to
620 * fix right now, and that I don't think should arise often.
621 * Basically, we should only put back this volume to the server if
622 * it was given to us by the server, but since we don't have a vp,
623 * we can't run the VolumeWriteable function to find out as we do
624 * above when computing vp->needsPutBack. So we send it back, but
625 * there's a path in VAttachVolume on the server which may abort
626 * if this volume doesn't have a header. Should be pretty rare
627 * for all of that to happen, but if it does, probably the right
628 * fix is for the server to allow the return of readonly volumes
629 * that it doesn't think are really checked out. */
630 if (programType == volumeUtility && vp == NULL && mode != V_SECRETLY) {
631 FSYNC_askfs(iheader.id, partition, FSYNC_ON, 0);
633 else if (programType == fileServer && vp) {
634 V_needsCallback(vp) = 0;
636 if (VInit >= 2 && V_BreakVolumeCallbacks) {
637 Log("VAttachVolume: Volume %u was changed externally; breaking callbacks\n", V_id(vp));
638 (*V_BreakVolumeCallbacks)(V_id(vp));
641 VUpdateVolume_r(ec,vp);
643 Log("VAttachVolume: Error updating volume\n");
648 if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
649 /* This is a hack: by temporarily settint the incore
650 * dontSalvage flag ON, the volume will be put back on the
651 * Update list (with dontSalvage OFF again). It will then
652 * come back in N minutes with DONT_SALVAGE eventually
653 * set. This is the way that volumes that have never had
654 * it set get it set; or that volumes that have been
655 * offline without DONT SALVAGE having been set also
656 * eventually get it set */
657 V_dontSalvage(vp) = DONT_SALVAGE;
658 VAddToVolumeUpdateList_r(ec,vp);
660 Log("VAttachVolume: Error adding volume to update list\n");
667 Log("VOnline: volume %u (%s) attached and online\n",
668 V_id(vp), V_name(vp));
671 if (programType == volumeUtility) {
672 VUnlockPartition_r(partition);
680 private Volume *attach2(Error *ec, char *path, register struct VolumeHeader
681 *header, struct DiskPartition *partp, int isbusy)
686 vp = (Volume *) calloc(1, sizeof(Volume));
688 vp->specialStatus = (isbusy ? VBUSY : 0);
689 vp->device = partp->device;
690 vp->partition = partp;
691 IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header->parent,
692 header->largeVnodeIndex);
693 IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header->parent,
694 header->smallVnodeIndex);
695 IH_INIT(vp->diskDataHandle, partp->device, header->parent,
697 IH_INIT(vp->linkHandle, partp->device, header->parent,
699 vp->cacheCheck = ++VolumeCacheCheck;
700 /* just in case this ever rolls over */
702 vp->cacheCheck = ++VolumeCacheCheck;
703 vp->shuttingDown = 0;
704 vp->goingOffline = 0;
709 (void) ReadHeader(ec, V_diskDataHandle(vp),
710 (char *)&V_disk(vp), sizeof(V_disk(vp)),
711 VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
714 Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%d\n",
718 struct IndexFileHeader iHead;
720 #if OPENAFS_VOL_STATS
722 * We just read in the diskstuff part of the header. If the detailed
723 * volume stats area has not yet been initialized, we should bzero the
724 * area and mark it as initialized.
726 if (! (V_stat_initialized(vp))) {
727 memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
728 V_stat_initialized(vp) = 1;
730 #endif /* OPENAFS_VOL_STATS */
732 (void) ReadHeader(ec, vp->vnodeIndex[vSmall].handle,
733 (char *)&iHead, sizeof(iHead),
734 SMALLINDEXMAGIC, SMALLINDEXVERSION);
737 Log("VAttachVolume: Error reading smallVnode vol header %s; error=%d\n",
742 struct IndexFileHeader iHead;
744 (void) ReadHeader(ec, vp->vnodeIndex[vLarge].handle,
745 (char *)&iHead, sizeof(iHead),
746 LARGEINDEXMAGIC, LARGEINDEXVERSION);
749 Log("VAttachVolume: Error reading largeVnode vol header %s; error=%d\n",
755 struct versionStamp stamp;
757 (void) ReadHeader(ec, V_linkHandle(vp),
758 (char *)&stamp, sizeof(stamp),
759 LINKTABLEMAGIC, LINKTABLEVERSION);
762 Log("VAttachVolume: Error reading namei vol header %s; error=%d\n",
768 Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%d\n",
773 if (V_needsSalvaged(vp)) {
774 if (vp->specialStatus) vp->specialStatus = 0;
775 Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
779 if (programType == fileServer) {
781 if (V_inUse(vp) && VolumeWriteable(vp)) {
782 if (!V_needsSalvaged(vp)) {
783 V_needsSalvaged(vp) = 1;
784 VUpdateVolume_r(ec,vp);
787 Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
791 #endif /* FAST_RESTART */
792 if (V_destroyMe(vp) == DESTROY_ME) {
794 Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
800 AddVolumeToHashTable(vp, V_id(vp));
801 vp->nextVnodeUnique = V_uniquifier(vp);
802 vp->vnodeIndex[vSmall].bitmap = vp->vnodeIndex[vLarge].bitmap = NULL;
804 if (programType == fileServer && VolumeWriteable(vp)) {
806 for (i = 0; i<nVNODECLASSES; i++) {
812 Log("VAttachVolume: error getting bitmap for volume (%s)\n", path);
817 #endif /* BITMAP_LATER */
819 if (programType == fileServer) {
820 if (vp->specialStatus) vp->specialStatus = 0;
821 if (V_blessed(vp) && V_inService(vp) && !V_needsSalvaged(vp)) {
823 V_offlineMessage(vp)[0] = '\0';
830 /* Attach an existing volume.
831 The volume also normally goes online at this time.
832 An offline volume must be reattached to make it go online.
836 VAttachVolume(Error *ec, VolumeId volumeId, int mode)
841 retVal = VAttachVolume_r(ec, volumeId, mode);
848 VAttachVolume_r(Error *ec, VolumeId volumeId, int mode)
851 GetVolumePath(ec,volumeId, &part, &name);
855 vp = VGetVolume_r(&error, volumeId);
857 assert(V_inUse(vp) == 0);
858 VDetachVolume_r(ec, vp);
862 return VAttachVolumeByName_r(ec, part, name, mode);
865 /* Increment a reference count to a volume, sans context swaps. Requires
866 * possibly reading the volume header in from the disk, since there's
867 * an invariant in the volume package that nUsers>0 ==> vp->header is valid.
869 * N.B. This call can fail if we can't read in the header!! In this case
870 * we still guarantee we won't context swap, but the ref count won't be
871 * incremented (otherwise we'd violate the invariant).
873 static int VHold_r(register Volume *vp)
877 if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
878 VolumeReplacements++;
879 ReadHeader(&error, V_diskDataHandle(vp),
880 (char *)&V_disk(vp), sizeof(V_disk(vp)),
881 VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
882 if (error) return error;
888 static int VHold(register Volume *vp)
892 retVal = VHold_r(vp);
897 void VTakeOffline_r(register Volume *vp)
899 assert(vp->nUsers > 0);
900 assert(programType == fileServer);
901 vp->goingOffline = 1;
902 V_needsSalvaged(vp) = 1;
905 void VTakeOffline(register Volume *vp)
912 void VPutVolume_r(register Volume *vp)
914 assert(--vp->nUsers >= 0);
915 if (vp->nUsers == 0) {
916 ReleaseVolumeHeader(vp->header);
917 if (vp->goingOffline) {
919 assert(programType == fileServer);
920 vp->goingOffline = 0;
922 VUpdateVolume_r(&error, vp);
923 VCloseVolumeHandles_r(vp);
925 Log("VOffline: Volume %u (%s) is now offline",
926 V_id(vp), V_name(vp));
927 if (V_offlineMessage(vp)[0])
928 Log(" (%s)", V_offlineMessage(vp));
931 #ifdef AFS_PTHREAD_ENV
932 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
933 #else /* AFS_PTHREAD_ENV */
934 LWP_NoYieldSignal(VPutVolume);
935 #endif /* AFS_PTHREAD_ENV */
937 if (vp->shuttingDown) {
938 VReleaseVolumeHandles_r(vp);
940 if (programType == fileServer)
941 #ifdef AFS_PTHREAD_ENV
942 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
943 #else /* AFS_PTHREAD_ENV */
944 LWP_NoYieldSignal(VPutVolume);
945 #endif /* AFS_PTHREAD_ENV */
950 void VPutVolume(register Volume *vp)
957 /* Get a pointer to an attached volume. The pointer is returned regardless
958 of whether or not the volume is in service or on/off line. An error
959 code, however, is returned with an indication of the volume's status */
960 Volume *VGetVolume(Error *ec, VolId volumeId)
964 retVal = VGetVolume_r(ec,volumeId);
969 Volume *VGetVolume_r(Error *ec, VolId volumeId)
972 unsigned short V0=0, V1=0, V2=0, V3=0, V4=0, V5=0, V6=0, V7=0, V8=0, V9=0;
973 unsigned short V10=0, V11=0, V12=0, V13=0, V14=0, V15=0;
978 for (vp = VolumeHashTable[VOLUME_HASH(volumeId)];
979 vp && vp->hashid != volumeId; vp = vp->hashNext)
986 /* Until we have reached an initialization level of 2
987 we don't know whether this volume exists or not.
988 We can't sleep and retry later because before a volume
989 is attached, the caller tries to get it first. Just
990 return VOFFLINE and the caller can choose whether to
991 retry the command or not.*/
1002 if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
1004 VolumeReplacements++;
1005 ReadHeader(ec, V_diskDataHandle(vp),
1006 (char *)&V_disk(vp), sizeof(V_disk(vp)), VOLUMEINFOMAGIC,
1010 /* Only log the error if it was a totally unexpected error. Simply
1011 a missing inode is likely to be caused by the volume being deleted */
1012 if (errno != ENXIO || LogLevel)
1013 Log("Volume %u: couldn't reread volume header\n", vp->hashid);
1020 if (vp->shuttingDown) {
1026 if (programType == fileServer) {
1028 if (vp->goingOffline) {
1030 #ifdef AFS_PTHREAD_ENV
1031 pthread_cond_wait(&vol_put_volume_cond, &vol_glock_mutex);
1032 #else /* AFS_PTHREAD_ENV */
1033 LWP_WaitProcess(VPutVolume);
1034 #endif /* AFS_PTHREAD_ENV */
1037 if (vp->specialStatus) {
1039 *ec = vp->specialStatus;
1041 else if (V_inService(vp)==0 || V_blessed(vp)==0) {
1045 else if (V_inUse(vp)==0) {
1056 /* if no error, bump nUsers */
1057 if (vp) vp->nUsers++;
1064 /* For both VForceOffline and VOffline, we close all relevant handles.
1065 * For VOffline, if we re-attach the volume, the files may possible be
1066 * different than before.
1068 static void VReleaseVolumeHandles_r(Volume *vp)
1070 DFlushVolume(V_id(vp));
1071 VReleaseVnodeFiles_r(vp);
1073 /* Too time consuming and unnecessary for the volserver */
1074 if (programType != volumeUtility) {
1075 IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1076 IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1077 IH_CONDSYNC(vp->diskDataHandle);
1079 IH_CONDSYNC(vp->linkHandle);
1080 #endif /* AFS_NT40_ENV */
1083 IH_RELEASE(vp->vnodeIndex[vLarge].handle);
1084 IH_RELEASE(vp->vnodeIndex[vSmall].handle);
1085 IH_RELEASE(vp->diskDataHandle);
1086 IH_RELEASE(vp->linkHandle);
1089 /* Force the volume offline, set the salvage flag. No further references to
1090 * the volume through the volume package will be honored. */
1091 void VForceOffline_r(Volume *vp)
1096 strcpy(V_offlineMessage(vp), "Forced offline due to internal error: volume needs to be salvaged");
1097 Log("Volume %u forced offline: it needs salvaging!\n", V_id(vp));
1099 vp->goingOffline = 0;
1100 V_needsSalvaged(vp) = 1;
1101 VUpdateVolume_r(&error, vp);
1102 #ifdef AFS_PTHREAD_ENV
1103 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1104 #else /* AFS_PTHREAD_ENV */
1105 LWP_NoYieldSignal(VPutVolume);
1106 #endif /* AFS_PTHREAD_ENV */
1108 VReleaseVolumeHandles_r(vp);
1112 void VForceOffline(Volume *vp)
1115 VForceOffline_r(vp);
1119 /* The opposite of VAttachVolume. The volume header is written to disk, with
1120 the inUse bit turned off. A copy of the header is maintained in memory,
1121 however (which is why this is VOffline, not VDetach).
1123 void VOffline_r(Volume *vp, char *message)
1126 VolumeId vid = V_id(vp);
1127 assert(programType != volumeUtility);
1132 if (V_offlineMessage(vp)[0] == '\0')
1133 strncpy(V_offlineMessage(vp),message,
1134 sizeof(V_offlineMessage(vp)));
1135 V_offlineMessage(vp)[sizeof(V_offlineMessage(vp))-1] = '\0';
1136 vp->goingOffline = 1;
1138 vp = VGetVolume_r(&error, vid); /* Wait for it to go offline */
1139 if (vp) /* In case it was reattached... */
1143 void VOffline(Volume *vp, char *message)
1146 VOffline_r(vp, message);
1150 /* For VDetachVolume, we close all cached file descriptors, but keep
1151 * the Inode handles in case we need to read from a busy volume.
1153 static void VCloseVolumeHandles_r(Volume *vp)
1155 DFlushVolume(V_id(vp));
1156 VCloseVnodeFiles_r(vp);
1158 /* Too time consuming and unnecessary for the volserver */
1159 if (programType != volumeUtility) {
1160 IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1161 IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1162 IH_CONDSYNC(vp->diskDataHandle);
1164 IH_CONDSYNC(vp->linkHandle);
1165 #endif /* AFS_NT40_ENV */
1168 IH_REALLYCLOSE(vp->vnodeIndex[vLarge].handle);
1169 IH_REALLYCLOSE(vp->vnodeIndex[vSmall].handle);
1170 IH_REALLYCLOSE(vp->diskDataHandle);
1171 IH_REALLYCLOSE(vp->linkHandle);
1174 /* This gets used for the most part by utility routines that don't want
1175 * to keep all the volume headers around. Generally, the file server won't
1176 * call this routine, because then the offline message in the volume header
1177 * (or other information) will still be available to clients. For NAMEI, also
1178 * close the file handles.
1180 void VDetachVolume_r(Error *ec, Volume *vp)
1183 struct DiskPartition *tpartp;
1184 int notifyServer, useDone;
1186 *ec = 0; /* always "succeeds" */
1187 if (programType == volumeUtility) {
1188 notifyServer = vp->needsPutBack;
1189 useDone = (V_destroyMe(vp) == DESTROY_ME);
1191 tpartp = vp->partition;
1193 DeleteVolumeFromHashTable(vp);
1194 vp->shuttingDown = 1;
1196 /* Will be detached sometime in the future--this is OK since volume is offline */
1198 if (programType == volumeUtility && notifyServer) {
1200 * Note: The server is not notified in the case of a bogus volume
1201 * explicitly to make it possible to create a volume, do a partial
1202 * restore, then abort the operation without ever putting the volume
1203 * online. This is essential in the case of a volume move operation
1204 * between two partitions on the same server. In that case, there
1205 * would be two instances of the same volume, one of them bogus,
1206 * which the file server would attempt to put on line
1209 /* don't put online */
1210 FSYNC_askfs(volume, tpartp->name, FSYNC_DONE, 0);
1212 /* fs can use it again */
1213 FSYNC_askfs(volume, tpartp->name, FSYNC_ON, 0);
1214 /* Dettaching it so break all callbacks on it*/
1215 if (V_BreakVolumeCallbacks) {
1216 Log("volume %u detached; breaking all call backs\n", volume);
1217 (*V_BreakVolumeCallbacks)(volume);
1223 void VDetachVolume(Error *ec, Volume *vp)
1226 VDetachVolume_r(ec, vp);
1231 int VAllocBitmapEntry_r(Error *ec, Volume *vp, register struct vnodeIndex
1234 register byte *bp,*ep;
1236 /* This test is probably redundant */
1237 if (!VolumeWriteable(vp)) {
1242 if ((programType == fileServer) && !index->bitmap) {
1245 if (vp->specialStatus == VBUSY) {
1246 if (vp->goingOffline) { /* vos dump waiting for the volume to
1247 go offline. We probably come here
1248 from AddNewReadableResidency */
1252 while (vp->specialStatus == VBUSY)
1253 #ifdef AFS_PTHREAD_ENV
1255 #else /* AFS_PTHREAD_ENV */
1257 #endif /* AFS_PTHREAD_ENV */
1261 if (!index->bitmap) {
1262 vp->specialStatus = VBUSY; /* Stop anyone else from using it.*/
1263 for (i = 0; i<nVNODECLASSES; i++) {
1268 vp->specialStatus = 0;
1269 vp->shuttingDown = 1; /* Let who has it free it. */
1274 vp->specialStatus = 0; /* Allow others to have access. */
1277 #endif /* BITMAP_LATER */
1278 bp = index->bitmap + index->bitmapOffset;
1279 ep = index->bitmap + index->bitmapSize;
1281 if ((*(bit32 *)bp) != 0xffffffff) {
1283 index->bitmapOffset = bp - index->bitmap;
1286 o = ffs(~*bp)-1; /* ffs is documented in BSTRING(3) */
1288 return (bp - index->bitmap)*8 + o;
1290 bp += sizeof(bit32) /* i.e. 4 */;
1292 /* No bit map entry--must grow bitmap */
1294 realloc(index->bitmap, index->bitmapSize+VOLUME_BITMAP_GROWSIZE);
1297 bp += index->bitmapSize;
1298 memset(bp, 0, VOLUME_BITMAP_GROWSIZE);
1299 index->bitmapOffset = index->bitmapSize;
1300 index->bitmapSize += VOLUME_BITMAP_GROWSIZE;
1302 return index->bitmapOffset*8;
1305 int VAllocBitmapEntry(Error *ec, Volume *vp, register struct vnodeIndex *index)
1309 retVal = VAllocBitmapEntry_r(ec,vp,index);
1314 void VFreeBitMapEntry_r(Error *ec, register struct vnodeIndex *index,
1317 unsigned int offset;
1320 if (!index->bitmap) return;
1321 #endif /* BITMAP_LATER */
1322 offset = bitNumber>>3;
1323 if (offset >= index->bitmapSize) {
1327 if (offset < index->bitmapOffset)
1328 index->bitmapOffset = offset&~3; /* Truncate to nearest bit32 */
1329 *(index->bitmap + offset) &= ~(1 << (bitNumber & 0x7));
1332 void VFreeBitMapEntry(Error *ec, register struct vnodeIndex *index,
1336 VFreeBitMapEntry_r(ec, index, bitNumber);
1340 void VUpdateVolume_r(Error *ec,Volume *vp)
1343 if (programType == fileServer)
1344 V_uniquifier(vp) = (V_inUse(vp)? V_nextVnodeUnique(vp) + 200: V_nextVnodeUnique(vp));
1345 /*printf("Writing volume header for '%s'\n", V_name(vp));*/
1346 WriteVolumeHeader_r(ec, vp);
1349 "VUpdateVolume: error updating volume header, volume %u (%s)\n",
1350 V_id(vp), V_name(vp));
1351 VForceOffline_r(vp);
1355 void VUpdateVolume(Error *ec, Volume *vp)
1358 VUpdateVolume_r(ec, vp);
1362 void VSyncVolume_r(Error *ec, Volume *vp)
1365 VUpdateVolume_r(ec, vp);
1368 fdP = IH_OPEN(V_diskDataHandle(vp));
1369 assert(fdP != NULL);
1370 code = FDH_SYNC(fdP);
1376 void VSyncVolume(Error *ec, Volume *vp)
1379 VSyncVolume_r(ec, vp);
1383 static void FreeVolume(Volume *vp)
1388 for (i = 0; i<nVNODECLASSES; i++)
1389 if (vp->vnodeIndex[i].bitmap)
1390 free(vp->vnodeIndex[i].bitmap);
1391 FreeVolumeHeader(vp);
1392 DeleteVolumeFromHashTable(vp);
1396 static void GetBitmap(Error *ec, Volume *vp, VnodeClass class)
1398 StreamHandle_t *file;
1402 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1403 struct vnodeIndex *vip = &vp->vnodeIndex[class];
1404 struct VnodeDiskObject *vnode;
1405 unsigned int unique = 0;
1409 #endif /* BITMAP_LATER */
1413 fdP = IH_OPEN(vip->handle);
1414 assert (fdP != NULL);
1415 file = FDH_FDOPEN(fdP, "r");
1416 assert (file != NULL);
1417 vnode = (VnodeDiskObject *) malloc(vcp->diskSize);
1418 assert(vnode != NULL);
1419 size = OS_SIZE(fdP->fd_fd);
1421 nVnodes = (size <= vcp->diskSize? 0: size-vcp->diskSize)
1423 vip->bitmapSize = ((nVnodes/8)+10)/4*4; /* The 10 is a little extra so
1424 a few files can be created in this volume,
1425 the whole thing is rounded up to nearest 4
1426 bytes, because the bit map allocator likes
1429 BitMap = (byte *) calloc(1, vip->bitmapSize);
1430 assert(BitMap != NULL);
1431 #else /* BITMAP_LATER */
1432 vip->bitmap = (byte *) calloc(1, vip->bitmapSize);
1433 assert(vip->bitmap != NULL);
1434 vip->bitmapOffset = 0;
1435 #endif /* BITMAP_LATER */
1436 if (STREAM_SEEK(file,vcp->diskSize,0) != -1) {
1438 for (bitNumber = 0; bitNumber < nVnodes+100; bitNumber++) {
1439 if (STREAM_READ(vnode, vcp->diskSize, 1, file) != 1)
1441 if (vnode->type != vNull) {
1442 if (vnode->vnodeMagic != vcp->magic) {
1443 Log("GetBitmap: addled vnode index in volume %s; volume needs salvage\n",
1449 *(BitMap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1450 #else /* BITMAP_LATER */
1451 *(vip->bitmap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1452 #endif /* BITMAP_LATER */
1453 if (unique <= vnode->uniquifier)
1454 unique = vnode->uniquifier + 1;
1456 #ifndef AFS_PTHREAD_ENV
1457 if ((bitNumber & 0x00ff) == 0x0ff) { /* every 256 iterations */
1460 #endif /* !AFS_PTHREAD_ENV */
1463 if (vp->nextVnodeUnique < unique) {
1464 Log("GetBitmap: bad volume uniquifier for volume %s; volume needs salvage\n", V_name(vp));
1467 /* Paranoia, partly justified--I think fclose after fdopen
1468 * doesn't seem to close fd. In any event, the documentation
1469 * doesn't specify, so it's safer to close it twice.
1475 /* There may have been a racing condition with some other thread, both
1476 * creating the bitmaps for this volume. If the other thread was faster
1477 * the pointer to bitmap should already be filled and we can free ours.
1479 if (vip->bitmap == NULL) {
1480 vip->bitmap = BitMap;
1481 vip->bitmapOffset = 0;
1483 free((byte *)BitMap);
1484 #endif /* BITMAP_LATER */
1487 static void GetVolumePath(Error *ec, VolId volumeId, char **partitionp,
1490 static char partition[VMAXPATHLEN], name[VMAXPATHLEN];
1491 char path[VMAXPATHLEN];
1493 struct DiskPartition *dp;
1497 sprintf(&name[1],VFORMAT,volumeId);
1498 for (dp = DiskPartitionList; dp; dp = dp->next) {
1499 #ifdef AFS_LARGEFILE_ENV
1500 struct stat64 status;
1501 #else /* !AFS_LARGEFILE_ENV */
1504 strcpy(path, VPartitionPath(dp));
1506 #ifdef AFS_LARGEFILE_ENV
1507 if (stat64(path,&status) == 0)
1508 #else /* !AFS_LARGEFILE_ENV */
1509 if (stat(path,&status) == 0)
1510 #endif /* !AFS_LARGEFILE_ENV */
1512 strcpy(partition, dp->name);
1519 *partitionp = *namep = NULL;
1522 *partitionp = partition;
1527 int VolumeNumber(char *name)
1531 return atoi(name+1);
1534 char *VolumeExternalName(VolumeId volumeId)
1536 static char name[15];
1537 sprintf(name,VFORMAT,volumeId);
1541 #if OPENAFS_VOL_STATS
1542 #define OneDay (86400) /* 24 hours' worth of seconds */
1544 #define OneDay (24*60*60) /* 24 hours */
1545 #endif /* OPENAFS_VOL_STATS */
1547 #define Midnight(date) ((date-TimeZoneCorrection)/OneDay*OneDay+TimeZoneCorrection)
1549 /*------------------------------------------------------------------------
1550 * [export] VAdjustVolumeStatistics
1553 * If we've passed midnight, we need to update all the day use
1554 * statistics as well as zeroing the detailed volume statistics
1555 * (if we are implementing them).
1558 * vp : Pointer to the volume structure describing the lucky
1559 * volume being considered for update.
1565 * Nothing interesting.
1569 *------------------------------------------------------------------------*/
1571 int VAdjustVolumeStatistics_r(register Volume *vp)
1573 unsigned int now = FT_ApproxTime();
1575 if (now - V_dayUseDate(vp) > OneDay) {
1578 ndays = (now - V_dayUseDate(vp)) / OneDay;
1579 for (i = 6; i>ndays-1; i--)
1580 V_weekUse(vp)[i] = V_weekUse(vp)[i-ndays];
1581 for (i = 0; i<ndays-1 && i<7; i++)
1582 V_weekUse(vp)[i] = 0;
1584 V_weekUse(vp)[ndays-1] = V_dayUse(vp);
1586 V_dayUseDate(vp) = Midnight(now);
1588 #if OPENAFS_VOL_STATS
1590 * All we need to do is bzero the entire VOL_STATS_BYTES of
1591 * the detailed volume statistics area.
1593 memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
1594 #endif /* OPENAFS_VOL_STATS */
1595 } /*It's been more than a day of collection*/
1598 * Always return happily.
1601 } /*VAdjustVolumeStatistics*/
1603 int VAdjustVolumeStatistics(register Volume *vp)
1607 retVal = VAdjustVolumeStatistics_r(vp);
1612 void VBumpVolumeUsage_r(register Volume *vp)
1614 unsigned int now = FT_ApproxTime();
1615 if (now - V_dayUseDate(vp) > OneDay)
1616 VAdjustVolumeStatistics_r(vp);
1618 * Save the volume header image to disk after every 128 bumps to dayUse.
1620 if ((V_dayUse(vp)++ & 127) == 0) {
1622 VUpdateVolume_r(&error, vp);
1626 void VBumpVolumeUsage(register Volume *vp)
1629 VBumpVolumeUsage_r(vp);
1633 void VSetDiskUsage_r(void)
1635 static int FifteenMinuteCounter = 0;
1638 /* NOTE: Don't attempt to access the partitions list until the
1639 initialization level indicates that all volumes are attached,
1640 which implies that all partitions are initialized. */
1641 #ifdef AFS_PTHREAD_ENV
1643 #else /* AFS_PTHREAD_ENV */
1645 #endif /* AFS_PTHREAD_ENV */
1648 VResetDiskUsage_r();
1649 if (++FifteenMinuteCounter == 3) {
1650 FifteenMinuteCounter = 0;
1655 void VSetDiskUsage(void)
1662 /* The number of minutes that a volume hasn't been updated before the
1663 * "Dont salvage" flag in the volume header will be turned on */
1664 #define SALVAGE_INTERVAL (10*60)
1666 static VolumeId *UpdateList; /* Pointer to array of Volume ID's */
1667 static int nUpdatedVolumes; /* Updated with entry in UpdateList, salvage after crash flag on */
1668 static int updateSize; /* number of entries possible */
1669 #define UPDATE_LIST_SIZE 100 /* size increment */
1671 void VAddToVolumeUpdateList_r(Error *ec, Volume *vp)
1674 vp->updateTime = FT_ApproxTime();
1675 if (V_dontSalvage(vp) == 0)
1677 V_dontSalvage(vp) = 0;
1678 VSyncVolume_r(ec, vp);
1682 updateSize = UPDATE_LIST_SIZE;
1683 UpdateList = (VolumeId *) malloc(sizeof (VolumeId) * updateSize);
1685 if (nUpdatedVolumes == updateSize) {
1686 updateSize += UPDATE_LIST_SIZE;
1687 UpdateList = (VolumeId *) realloc(UpdateList, sizeof (VolumeId) * updateSize);
1690 assert(UpdateList != NULL);
1691 UpdateList[nUpdatedVolumes++] = V_id(vp);
1694 static void VScanUpdateList() {
1695 register int i, gap;
1696 register Volume *vp;
1698 afs_int32 now = FT_ApproxTime();
1699 /* Be careful with this code, since it works with interleaved calls to AddToVolumeUpdateList */
1700 for (i = gap = 0; i<nUpdatedVolumes; i++) {
1701 vp = VGetVolume_r(&error, UpdateList[i-gap] = UpdateList[i]);
1704 } else if (vp->nUsers == 1 && now - vp->updateTime > SALVAGE_INTERVAL) {
1705 V_dontSalvage(vp) = DONT_SALVAGE;
1706 VUpdateVolume_r(&error, vp); /* No need to fsync--not critical */
1711 #ifndef AFS_PTHREAD_ENV
1713 #endif /* !AFS_PTHREAD_ENV */
1715 nUpdatedVolumes -= gap;
1718 /***************************************************/
1719 /* Add on routines to manage a volume header cache */
1720 /***************************************************/
1722 static struct volHeader *volumeLRU;
1724 /* Allocate a bunch of headers; string them together */
1725 static void InitLRU(int howMany)
1727 register struct volHeader *hp;
1728 if (programType != fileServer)
1730 hp = (struct volHeader *)(calloc(howMany, sizeof(struct volHeader)));
1732 ReleaseVolumeHeader(hp++);
1735 /* Get a volume header from the LRU list; update the old one if necessary */
1736 /* Returns 1 if there was already a header, which is removed from the LRU list */
1737 static int GetVolumeHeader(register Volume *vp)
1740 register struct volHeader *hd;
1742 static int everLogged = 0;
1744 old = (vp->header != 0); /* old == volume already has a header */
1745 if (programType != fileServer) {
1747 hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1756 if (volumeLRU == hd)
1757 volumeLRU = hd->next;
1758 assert(hd->back == vp);
1762 /* not currently in use and least recently used */
1763 hd = volumeLRU->prev;
1765 hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1766 /* make it look like single elt LRU */
1767 hd->prev = hd->next = hd;
1769 Log("****Allocated more volume headers, probably leak****\n");
1774 if (hd->diskstuff.inUse) {
1775 WriteVolumeHeader_r(&error, hd->back);
1776 /* Ignore errors; catch them later */
1778 hd->back->header = 0;
1783 if (hd->next) { /* hd->next != 0 --> in LRU chain (we zero it later) */
1784 hd->prev->next = hd->next; /* pull hd out of LRU list */
1785 hd->next->prev = hd->prev; /* if hd only element, this is noop */
1787 hd->next = hd->prev = 0;
1788 /* if not in LRU chain, next test won't be true */
1789 if (hd == volumeLRU) /* last header item, turn into empty list */
1795 /* Put it at the top of the LRU chain */
1796 static void ReleaseVolumeHeader(register struct volHeader *hd)
1798 if (programType != fileServer)
1800 if (!hd || hd->next) /* no header, or header already released */
1803 hd->next = hd->prev = hd;
1805 hd->prev = volumeLRU->prev;
1806 hd->next = volumeLRU;
1807 hd->prev->next = hd->next->prev = hd;
1812 static void FreeVolumeHeader(register Volume *vp)
1814 register struct volHeader *hd = vp->header;
1817 if (programType == fileServer) {
1818 ReleaseVolumeHeader(hd);
1828 /***************************************************/
1829 /* Routines to add volume to hash chain, delete it */
1830 /***************************************************/
1832 static void AddVolumeToHashTable(register Volume *vp, int hashid)
1834 int hash = VOLUME_HASH(hashid);
1835 vp->hashid = hashid;
1836 vp->hashNext = VolumeHashTable[hash];
1837 VolumeHashTable[hash] = vp;
1838 vp->vnodeHashOffset = VolumeHashOffset_r();
1841 static void DeleteVolumeFromHashTable(register Volume *vp)
1843 int hash = VOLUME_HASH(vp->hashid);
1844 if (VolumeHashTable[hash] == vp)
1845 VolumeHashTable[hash] = vp->hashNext;
1847 Volume *tvp = VolumeHashTable[hash];
1850 while (tvp->hashNext && tvp->hashNext != vp)
1851 tvp = tvp->hashNext;
1852 if (tvp->hashNext == NULL)
1854 tvp->hashNext = vp->hashNext;
1859 void VPrintCacheStats_r(void)
1861 register struct VnodeClassInfo *vcp;
1862 vcp = &VnodeClassInfo[vLarge];
1863 Log("Large vnode cache, %d entries, %d allocs, %d gets (%d reads), %d writes\n",
1864 vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1865 vcp = &VnodeClassInfo[vSmall];
1866 Log("Small vnode cache,%d entries, %d allocs, %d gets (%d reads), %d writes\n",
1867 vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1868 Log("Volume header cache, %d entries, %d gets, %d replacements\n",
1869 VolumeCacheSize, VolumeGets, VolumeReplacements);
1872 void VPrintCacheStats(void)
1875 VPrintCacheStats_r();