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 <afs/param.h>
20 #include <afsconfig.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_FBSD_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_FBSD_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 */
133 #if !defined(AFS_NT40_ENV) && !defined(AFS_NAMEI_ENV)
134 #include <afs/osi_inode.h>
140 #ifdef AFS_PTHREAD_ENV
141 pthread_mutex_t vol_glock_mutex;
142 pthread_mutex_t vol_attach_mutex;
143 pthread_cond_t vol_put_volume_cond;
144 pthread_cond_t vol_sleep_cond;
145 #endif /* AFS_PTHREAD_ENV */
148 extern void *calloc(), *realloc();
151 /* Forward declarations */
152 static Volume *attach2();
153 static void FreeVolume();
154 static void VScanUpdateList();
155 static void InitLRU();
156 static int GetVolumeHeader();
157 static void ReleaseVolumeHeader();
158 static void FreeVolumeHeader();
159 static void AddVolumeToHashTable();
160 static void DeleteVolumeFromHashTable();
161 static int VHold(Volume *vp);
162 static int VHold_r(Volume *vp);
163 static void GetBitmap(Error *ec, Volume *vp, VnodeClass class);
164 static void GetVolumePath(Error *ec, VolId volumeId, char **partitionp,
166 static void VReleaseVolumeHandles_r(Volume *vp);
167 static void VCloseVolumeHandles_r(Volume *vp);
169 int LogLevel; /* Vice loglevel--not defined as extern so that it will be
170 defined when not linked with vice, XXXX */
171 ProgramType programType; /* The type of program using the package */
174 #define VOLUME_BITMAP_GROWSIZE 16 /* bytes, => 128vnodes */
175 /* Must be a multiple of 4 (1 word) !!*/
176 #define VOLUME_HASH_TABLE_SIZE 128 /* Must be a power of 2!! */
177 #define VOLUME_HASH(volumeId) (volumeId&(VOLUME_HASH_TABLE_SIZE-1))
178 private Volume *VolumeHashTable[VOLUME_HASH_TABLE_SIZE];
181 /* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
184 afs_int32 ffs_tmp = x; \
185 if (ffs_tmp == 0) return(-1); \
187 for (ffs_i = 1;; ffs_i++) { \
188 if (ffs_tmp & 1) return(ffs_i); \
189 else ffs_tmp >>= 1; \
192 #endif /* !AFS_HAVE_FFS */
194 struct Lock vol_listLock; /* Lock obtained when listing volumes: prevents a volume from being missed if the volume is attached during a list volumes */
196 extern struct Lock FSYNC_handler_lock;
198 Volume *VAttachVolumeByName();
199 Volume *VAttachVolumeByName_r();
201 static int TimeZoneCorrection; /* Number of seconds west of GMT */
203 /* Common message used when the volume goes off line */
204 char *VSalvageMessage =
205 "Files in this volume are currently unavailable; call operations";
207 int VInit; /* 0 - uninitialized,
208 1 - initialized but not all volumes have been attached,
209 2 - initialized and all volumes have been attached,
210 3 - initialized, all volumes have been attached, and
211 VConnectFS() has completed. */
214 int VolumeCacheCheck; /* Incremented everytime a volume goes on line--
215 * used to stamp volume headers and in-core
216 * vnodes. When the volume goes on-line the
217 * vnode will be invalidated */
219 int VolumeCacheSize = 200, VolumeGets=0, VolumeReplacements=0, Vlooks = 0;
222 int VInitVolumePackage(ProgramType pt, int nLargeVnodes, int nSmallVnodes,
223 int connect, int volcache)
225 int errors = 0; /* Number of errors while finding vice partitions. */
231 #ifdef AFS_PTHREAD_ENV
232 assert(pthread_mutex_init(&vol_glock_mutex, NULL) == 0);
233 assert(pthread_mutex_init(&vol_attach_mutex, NULL) == 0);
234 assert(pthread_cond_init(&vol_put_volume_cond, NULL) == 0);
235 assert(pthread_cond_init(&vol_sleep_cond, NULL) == 0);
236 #else /* AFS_PTHREAD_ENV */
238 #endif /* AFS_PTHREAD_ENV */
239 Lock_Init(&vol_listLock);
240 Lock_Init(&FSYNC_handler_lock);
241 srandom(time(0)); /* For VGetVolumeInfo */
242 gettimeofday(&tv, &tz);
243 TimeZoneCorrection = tz.tz_minuteswest*60;
245 /* Ok, we have done enough initialization that fileserver can
246 * start accepting calls, even though the volumes may not be
247 * available just yet.
251 if (programType == fileServer) {
252 /* File server or "stand" */
256 if (volcache > VolumeCacheSize)
257 VolumeCacheSize = volcache;
258 InitLRU(VolumeCacheSize);
260 VInitVnodes(vLarge, nLargeVnodes);
261 VInitVnodes(vSmall, nSmallVnodes);
264 errors = VAttachPartitions();
268 if (programType == fileServer) {
271 struct DiskPartition *diskP;
274 /* Attach all the volumes in this partition */
275 for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
276 int nAttached = 0, nUnattached = 0;
277 dirp = opendir(VPartitionPath(diskP));
279 while (dp = readdir(dirp)) {
281 p = strrchr(dp->d_name, '.');
282 if (p != NULL && strcmp(p, VHDREXT) == 0) {
285 vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
287 (*(vp?&nAttached:&nUnattached))++;
288 if (error == VOFFLINE)
289 Log("Volume %u stays offline (/vice/offline/%s exists)\n",
290 VolumeNumber(dp->d_name), dp->d_name);
296 Log("Partition %s: attached %d volumes; %d volumes not attached\n",
297 diskP->name, nAttached, nUnattached);
302 VInit = 2; /* Initialized, and all volumes have been attached */
303 if (programType == volumeUtility && connect) {
305 Log("Unable to connect to file server; aborted\n");
312 /* This must be called by any volume utility which needs to run while the
313 file server is also running. This is separated from VInitVolumePackage so
314 that a utility can fork--and each of the children can independently
315 initialize communication with the file server */
320 retVal = VConnectFS_r();
325 int VConnectFS_r(void)
328 assert(VInit == 2 && programType == volumeUtility);
329 rc = FSYNC_clientInit();
335 void VDisconnectFS_r(void) {
336 assert(programType == volumeUtility);
341 void VDisconnectFS(void) {
347 void VShutdown_r(void)
350 register Volume *vp, *np;
351 register afs_int32 code;
353 Log("VShutdown: shutting down on-line volumes...\n");
354 for (i=0; i<VOLUME_HASH_TABLE_SIZE; i++) {
355 /* try to hold first volume in the hash table */
356 for(vp = VolumeHashTable[i]; vp; vp=vp->hashNext) {
358 if (code == 0) break; /* got it */
359 /* otherwise we go around again, trying another volume */
362 /* first compute np before releasing vp, in case vp disappears
363 * after releasing. Hold it, so it doesn't disapear. If we
364 * can't hold it, try the next one in the chain. Invariant
365 * at the top of this loop is that vp is held (has extra ref count).
367 for(np=vp->hashNext; np; np=np->hashNext) {
369 if (code == 0) break; /* got it */
371 /* next, take the volume offline (drops reference count) */
372 VOffline_r(vp, "File server was shut down");
373 vp = np; /* next guy to try */
376 Log("VShutdown: complete.\n");
387 static void ReadHeader(Error *ec, IHandle_t *h, char *to, int size,
388 int magic, int version)
390 struct versionStamp *vsn;
400 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
402 FDH_REALLYCLOSE(fdP);
405 vsn = (struct versionStamp *) to;
406 if (FDH_READ(fdP, to, size) != size || vsn->magic != magic) {
408 FDH_REALLYCLOSE(fdP);
413 /* Check is conditional, in case caller wants to inspect version himself */
414 if (version && vsn->version != version) {
419 /* VolumeHeaderToDisk
420 * Allows for storing 64 bit inode numbers in on-disk volume header
423 void VolumeHeaderToDisk(VolumeDiskHeader_t *dh, VolumeHeader_t *h)
426 bzero((char*)dh, sizeof(VolumeDiskHeader_t));
427 dh->stamp = h->stamp;
429 dh->parent = h->parent;
431 #ifdef AFS_64BIT_IOPS_ENV
432 dh->volumeInfo_lo = (afs_int32) h->volumeInfo & 0xffffffff;
433 dh->volumeInfo_hi = (afs_int32) (h->volumeInfo >> 32) & 0xffffffff;
434 dh->smallVnodeIndex_lo = (afs_int32) h->smallVnodeIndex & 0xffffffff;
435 dh->smallVnodeIndex_hi = (afs_int32) (h->smallVnodeIndex >> 32) & 0xffffffff;
436 dh->largeVnodeIndex_lo = (afs_int32) h->largeVnodeIndex & 0xffffffff;
437 dh->largeVnodeIndex_hi = (afs_int32) (h->largeVnodeIndex >> 32) & 0xffffffff;
438 dh->linkTable_lo = (afs_int32) h->linkTable & 0xffffffff;
439 dh->linkTable_hi = (afs_int32) (h->linkTable >> 32) & 0xffffffff;
441 dh->volumeInfo_lo = h->volumeInfo;
442 dh->smallVnodeIndex_lo = h->smallVnodeIndex;
443 dh->largeVnodeIndex_lo = h->largeVnodeIndex;
444 dh->linkTable_lo = h->linkTable;
448 /* DiskToVolumeHeader
449 * Reads volume header file from disk, convering 64 bit inodes
450 * if required. Makes the assumption that AFS has *always*
451 * zero'd the volume header file so that high parts of inode
452 * numbers are 0 in older (SGI EFS) volume header files.
454 void DiskToVolumeHeader(VolumeHeader_t *h, VolumeDiskHeader_t *dh)
456 bzero((char*)h, sizeof(VolumeHeader_t));
457 h->stamp = dh->stamp;
459 h->parent = dh->parent;
461 #ifdef AFS_64BIT_IOPS_ENV
462 h->volumeInfo = dh->volumeInfo_lo | ((Inode)dh->volumeInfo_hi << 32);
464 h->smallVnodeIndex = dh->smallVnodeIndex_lo |
465 ((Inode)dh->smallVnodeIndex_hi << 32);
467 h->largeVnodeIndex = dh->largeVnodeIndex_lo |
468 ((Inode)dh->largeVnodeIndex_hi << 32);
469 h->linkTable = dh->linkTable_lo |
470 ((Inode)dh->linkTable_hi << 32);
472 h->volumeInfo = dh->volumeInfo_lo;
473 h->smallVnodeIndex = dh->smallVnodeIndex_lo;
474 h->largeVnodeIndex = dh->largeVnodeIndex_lo;
475 h->linkTable = dh->linkTable_lo;
480 void WriteVolumeHeader_r(ec, vp)
484 IHandle_t *h = V_diskDataHandle(vp);
494 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
496 FDH_REALLYCLOSE(fdP);
499 if (FDH_WRITE(fdP, (char*)&V_disk(vp), sizeof(V_disk(vp)))
500 != sizeof(V_disk(vp))) {
502 FDH_REALLYCLOSE(fdP);
508 /* Attach an existing volume, given its pathname, and return a
509 pointer to the volume header information. The volume also
510 normally goes online at this time. An offline volume
511 must be reattached to make it go online */
513 VAttachVolumeByName(ec, partition, name, mode)
522 retVal = VAttachVolumeByName_r(ec, partition, name, mode);
529 VAttachVolumeByName_r(ec, partition, name, mode)
538 struct VolumeDiskHeader diskHeader;
539 struct VolumeHeader iheader;
540 struct DiskPartition *partp;
544 if (programType == volumeUtility) {
546 VLockPartition_r(partition);
548 if (programType == fileServer) {
549 vp = VGetVolume_r(ec, VolumeNumber(name));
553 if (vp->specialStatus == VBUSY)
555 VDetachVolume_r(ec, vp);
557 Log("VAttachVolume: Error detaching volume (%s)\n", name);
562 if (!(partp = VGetPartition_r(partition, 0))) {
564 Log("VAttachVolume: Error getting partition (%s)\n", partition);
569 strcpy(path, VPartitionPath(partp));
573 if ((fd = open(path, O_RDONLY)) == -1 || fstat(fd,&status) == -1) {
579 n = read(fd, &diskHeader, sizeof (diskHeader));
582 if (n != sizeof (diskHeader) || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
583 Log("VAttachVolume: Error reading volume header %s\n", path);
587 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
588 Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n",path);
593 DiskToVolumeHeader(&iheader, &diskHeader);
594 if (programType == volumeUtility && mode != V_SECRETLY) {
595 if (FSYNC_askfs(iheader.id, partition, FSYNC_NEEDVOLUME, mode)
597 Log("VAttachVolume: attach of volume %u apparently denied by file server\n",
599 *ec = VNOVOL; /* XXXX */
604 vp = attach2(ec, path, &iheader, partp, isbusy);
605 if (programType == volumeUtility && vp) {
606 /* duplicate computation in fssync.c about whether the server
607 * takes the volume offline or not. If the volume isn't
608 * offline, we must not return it when we detach the volume,
609 * or the server will abort */
610 if (mode == V_READONLY || (!VolumeWriteable(vp) && (mode==V_CLONE || mode==V_DUMP)))
611 vp->needsPutBack = 0;
613 vp->needsPutBack = 1;
615 /* OK, there's a problem here, but one that I don't know how to
616 * fix right now, and that I don't think should arise often.
617 * Basically, we should only put back this volume to the server if
618 * it was given to us by the server, but since we don't have a vp,
619 * we can't run the VolumeWriteable function to find out as we do
620 * above when computing vp->needsPutBack. So we send it back, but
621 * there's a path in VAttachVolume on the server which may abort
622 * if this volume doesn't have a header. Should be pretty rare
623 * for all of that to happen, but if it does, probably the right
624 * fix is for the server to allow the return of readonly volumes
625 * that it doesn't think are really checked out. */
626 if (programType == volumeUtility && vp == NULL && mode != V_SECRETLY) {
627 FSYNC_askfs(iheader.id, partition, FSYNC_ON, 0);
629 else if (programType == fileServer && vp) {
630 V_needsCallback(vp) = 0;
632 if (VInit >= 2 && V_BreakVolumeCallbacks) {
633 Log("VAttachVolume: Volume %u was changed externally; breaking callbacks\n", V_id(vp));
634 (*V_BreakVolumeCallbacks)(V_id(vp));
637 VUpdateVolume_r(ec,vp);
639 Log("VAttachVolume: Error updating volume\n");
644 if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
645 /* This is a hack: by temporarily settint the incore
646 * dontSalvage flag ON, the volume will be put back on the
647 * Update list (with dontSalvage OFF again). It will then
648 * come back in N minutes with DONT_SALVAGE eventually
649 * set. This is the way that volumes that have never had
650 * it set get it set; or that volumes that have been
651 * offline without DONT SALVAGE having been set also
652 * eventually get it set */
653 V_dontSalvage(vp) = DONT_SALVAGE;
654 VAddToVolumeUpdateList_r(ec,vp);
656 Log("VAttachVolume: Error adding volume to update list\n");
663 Log("VOnline: volume %u (%s) attached and online\n",
664 V_id(vp), V_name(vp));
667 if (programType == volumeUtility) {
668 VUnlockPartition_r(partition);
676 private Volume *attach2(ec, path, header, partp, isbusy)
679 register struct VolumeHeader *header;
680 struct DiskPartition *partp;
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 vp->shuttingDown = 0;
701 vp->goingOffline = 0;
706 (void) ReadHeader(ec, V_diskDataHandle(vp),
707 (char *)&V_disk(vp), sizeof(V_disk(vp)),
708 VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
711 Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%d\n",
715 struct IndexFileHeader iHead;
717 #if TRANSARC_VOL_STATS
719 * We just read in the diskstuff part of the header. If the detailed
720 * volume stats area has not yet been initialized, we should bzero the
721 * area and mark it as initialized.
723 if (! (V_stat_initialized(vp))) {
724 bzero((char *)(V_stat_area(vp)), VOL_STATS_BYTES);
725 V_stat_initialized(vp) = 1;
727 #endif /* TRANSARC_VOL_STATS */
729 (void) ReadHeader(ec, vp->vnodeIndex[vSmall].handle,
730 (char *)&iHead, sizeof(iHead),
731 SMALLINDEXMAGIC, SMALLINDEXVERSION);
734 Log("VAttachVolume: Error reading smallVnode vol header %s; error=%d\n",
739 struct IndexFileHeader iHead;
741 (void) ReadHeader(ec, vp->vnodeIndex[vLarge].handle,
742 (char *)&iHead, sizeof(iHead),
743 LARGEINDEXMAGIC, LARGEINDEXVERSION);
746 Log("VAttachVolume: Error reading largeVnode vol header %s; error=%d\n",
752 struct versionStamp stamp;
754 (void) ReadHeader(ec, V_linkHandle(vp),
755 (char *)&stamp, sizeof(stamp),
756 LINKTABLEMAGIC, LINKTABLEVERSION);
759 Log("VAttachVolume: Error reading namei vol header %s; error=%d\n",
765 Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%d\n",
770 if (V_needsSalvaged(vp)) {
771 if (vp->specialStatus) vp->specialStatus = 0;
772 Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
776 if (programType == fileServer) {
778 if (V_inUse(vp) && VolumeWriteable(vp)) {
779 if (!V_needsSalvaged(vp)) {
780 V_needsSalvaged(vp) = 1;
781 VUpdateVolume_r(ec,vp);
784 Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
788 #endif /* FAST_RESTART */
789 if (V_destroyMe(vp) == DESTROY_ME) {
791 Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
797 AddVolumeToHashTable(vp, V_id(vp));
798 vp->nextVnodeUnique = V_uniquifier(vp);
799 vp->vnodeIndex[vSmall].bitmap = vp->vnodeIndex[vLarge].bitmap = NULL;
801 if (programType == fileServer && VolumeWriteable(vp)) {
803 for (i = 0; i<nVNODECLASSES; i++) {
809 Log("VAttachVolume: error getting bitmap for volume (%s)\n", path);
814 #endif /* BITMAP_LATER */
816 if (programType == fileServer) {
817 if (vp->specialStatus) vp->specialStatus = 0;
818 if (V_blessed(vp) && V_inService(vp) && !V_needsSalvaged(vp)) {
820 V_offlineMessage(vp)[0] = '\0';
827 /* Attach an existing volume.
828 The volume also normally goes online at this time.
829 An offline volume must be reattached to make it go online.
833 VAttachVolume(ec,volumeId, mode)
841 retVal = VAttachVolume_r(ec, volumeId, mode);
848 VAttachVolume_r(ec,volumeId, mode)
854 GetVolumePath(ec,volumeId, &part, &name);
858 vp = VGetVolume_r(&error, volumeId);
860 assert(V_inUse(vp) == 0);
861 VDetachVolume_r(ec, vp);
865 return VAttachVolumeByName_r(ec, part, name, mode);
868 /* Increment a reference count to a volume, sans context swaps. Requires
869 * possibly reading the volume header in from the disk, since there's
870 * an invariant in the volume package that nUsers>0 ==> vp->header is valid.
872 * N.B. This call can fail if we can't read in the header!! In this case
873 * we still guarantee we won't context swap, but the ref count won't be
874 * incremented (otherwise we'd violate the invariant).
876 static int VHold_r(register Volume *vp)
880 if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
881 VolumeReplacements++;
882 ReadHeader(&error, V_diskDataHandle(vp),
883 (char *)&V_disk(vp), sizeof(V_disk(vp)),
884 VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
885 if (error) return error;
891 static int VHold(register Volume *vp)
895 retVal = VHold_r(vp);
900 void VTakeOffline_r(register Volume *vp)
902 assert(vp->nUsers > 0);
903 assert(programType == fileServer);
904 vp->goingOffline = 1;
905 V_needsSalvaged(vp) = 1;
908 void VTakeOffline(register Volume *vp)
915 void VPutVolume_r(register Volume *vp)
917 assert(--vp->nUsers >= 0);
918 if (vp->nUsers == 0) {
919 ReleaseVolumeHeader(vp->header);
920 if (vp->goingOffline) {
922 assert(programType == fileServer);
923 vp->goingOffline = 0;
925 VUpdateVolume_r(&error, vp);
926 VCloseVolumeHandles_r(vp);
928 Log("VOffline: Volume %u (%s) is now offline",
929 V_id(vp), V_name(vp));
930 if (V_offlineMessage(vp)[0])
931 Log(" (%s)", V_offlineMessage(vp));
934 #ifdef AFS_PTHREAD_ENV
935 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
936 #else /* AFS_PTHREAD_ENV */
937 LWP_NoYieldSignal(VPutVolume);
938 #endif /* AFS_PTHREAD_ENV */
940 if (vp->shuttingDown) {
941 VReleaseVolumeHandles_r(vp);
943 if (programType == fileServer)
944 #ifdef AFS_PTHREAD_ENV
945 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
946 #else /* AFS_PTHREAD_ENV */
947 LWP_NoYieldSignal(VPutVolume);
948 #endif /* AFS_PTHREAD_ENV */
953 void VPutVolume(register Volume *vp)
960 /* Get a pointer to an attached volume. The pointer is returned regardless
961 of whether or not the volume is in service or on/off line. An error
962 code, however, is returned with an indication of the volume's status */
963 Volume *VGetVolume(ec,volumeId)
969 retVal = VGetVolume_r(ec,volumeId);
974 Volume *VGetVolume_r(ec,volumeId)
979 unsigned short V0=0, V1=0, V2=0, V3=0, V4=0, V5=0, V6=0, V7=0, V8=0, V9=0;
980 unsigned short V10=0, V11=0, V12=0, V13=0, V14=0, V15=0;
985 for (vp = VolumeHashTable[VOLUME_HASH(volumeId)];
986 vp && vp->hashid != volumeId; vp = vp->hashNext)
993 /* Until we have reached an initialization level of 2
994 we don't know whether this volume exists or not.
995 We can't sleep and retry later because before a volume
996 is attached, the caller tries to get it first. Just
997 return VOFFLINE and the caller can choose whether to
998 retry the command or not.*/
1009 if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
1011 VolumeReplacements++;
1012 ReadHeader(ec, V_diskDataHandle(vp),
1013 (char *)&V_disk(vp), sizeof(V_disk(vp)), VOLUMEINFOMAGIC,
1017 /* Only log the error if it was a totally unexpected error. Simply
1018 a missing inode is likely to be caused by the volume being deleted */
1019 if (errno != ENXIO || LogLevel)
1020 Log("Volume %u: couldn't reread volume header\n", vp->hashid);
1027 if (vp->shuttingDown) {
1033 if (programType == fileServer) {
1035 if (vp->goingOffline) {
1037 #ifdef AFS_PTHREAD_ENV
1038 pthread_cond_wait(&vol_put_volume_cond, &vol_glock_mutex);
1039 #else /* AFS_PTHREAD_ENV */
1040 LWP_WaitProcess(VPutVolume);
1041 #endif /* AFS_PTHREAD_ENV */
1044 if (vp->specialStatus) {
1046 *ec = vp->specialStatus;
1048 else if (V_inService(vp)==0 || V_blessed(vp)==0) {
1052 else if (V_inUse(vp)==0) {
1063 /* if no error, bump nUsers */
1064 if (vp) vp->nUsers++;
1071 /* For both VForceOffline and VOffline, we close all relevant handles.
1072 * For VOffline, if we re-attach the volume, the files may possible be
1073 * different than before.
1075 static void VReleaseVolumeHandles_r(Volume *vp)
1077 DFlushVolume(V_id(vp));
1078 VReleaseVnodeFiles_r(vp);
1080 /* Too time consuming and unnecessary for the volserver */
1081 if (programType != volumeUtility) {
1082 IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1083 IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1084 IH_CONDSYNC(vp->diskDataHandle);
1086 IH_CONDSYNC(vp->linkHandle);
1087 #endif /* AFS_NT40_ENV */
1090 IH_RELEASE(vp->vnodeIndex[vLarge].handle);
1091 IH_RELEASE(vp->vnodeIndex[vSmall].handle);
1092 IH_RELEASE(vp->diskDataHandle);
1093 IH_RELEASE(vp->linkHandle);
1096 /* Force the volume offline, set the salvage flag. No further references to
1097 * the volume through the volume package will be honored. */
1098 void VForceOffline_r(Volume *vp)
1103 strcpy(V_offlineMessage(vp), "Forced offline due to internal error: volume needs to be salvaged");
1104 Log("Volume %u forced offline: it needs salvaging!\n", V_id(vp));
1106 vp->goingOffline = 0;
1107 V_needsSalvaged(vp) = 1;
1108 VUpdateVolume_r(&error, vp);
1109 #ifdef AFS_PTHREAD_ENV
1110 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1111 #else /* AFS_PTHREAD_ENV */
1112 LWP_NoYieldSignal(VPutVolume);
1113 #endif /* AFS_PTHREAD_ENV */
1115 VReleaseVolumeHandles_r(vp);
1119 void VForceOffline(Volume *vp)
1122 VForceOffline_r(vp);
1126 /* The opposite of VAttachVolume. The volume header is written to disk, with
1127 the inUse bit turned off. A copy of the header is maintained in memory,
1128 however (which is why this is VOffline, not VDetach).
1130 void VOffline_r(Volume *vp, char *message)
1133 VolumeId vid = V_id(vp);
1134 assert(programType != volumeUtility);
1139 if (V_offlineMessage(vp)[0] == '\0')
1140 strncpy(V_offlineMessage(vp),message,
1141 sizeof(V_offlineMessage(vp)));
1142 V_offlineMessage(vp)[sizeof(V_offlineMessage(vp))-1] = '\0';
1143 vp->goingOffline = 1;
1145 vp = VGetVolume_r(&error, vid); /* Wait for it to go offline */
1146 if (vp) /* In case it was reattached... */
1150 void VOffline(Volume *vp, char *message)
1153 VOffline_r(vp, message);
1157 /* For VDetachVolume, we close all cached file descriptors, but keep
1158 * the Inode handles in case we need to read from a busy volume.
1160 static void VCloseVolumeHandles_r(Volume *vp)
1162 DFlushVolume(V_id(vp));
1163 VCloseVnodeFiles_r(vp);
1165 /* Too time consuming and unnecessary for the volserver */
1166 if (programType != volumeUtility) {
1167 IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1168 IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1169 IH_CONDSYNC(vp->diskDataHandle);
1171 IH_CONDSYNC(vp->linkHandle);
1172 #endif /* AFS_NT40_ENV */
1175 IH_REALLYCLOSE(vp->vnodeIndex[vLarge].handle);
1176 IH_REALLYCLOSE(vp->vnodeIndex[vSmall].handle);
1177 IH_REALLYCLOSE(vp->diskDataHandle);
1178 IH_REALLYCLOSE(vp->linkHandle);
1181 /* This gets used for the most part by utility routines that don't want
1182 * to keep all the volume headers around. Generally, the file server won't
1183 * call this routine, because then the offline message in the volume header
1184 * (or other information) will still be available to clients. For NAMEI, also
1185 * close the file handles.
1187 void VDetachVolume_r(Error *ec, Volume *vp)
1190 struct DiskPartition *tpartp;
1191 int notifyServer, useDone;
1193 *ec = 0; /* always "succeeds" */
1194 if (programType == volumeUtility) {
1195 notifyServer = vp->needsPutBack;
1196 useDone = (V_destroyMe(vp) == DESTROY_ME);
1198 tpartp = vp->partition;
1200 DeleteVolumeFromHashTable(vp);
1201 vp->shuttingDown = 1;
1203 /* Will be detached sometime in the future--this is OK since volume is offline */
1205 if (programType == volumeUtility && notifyServer) {
1206 /* Note: The server is not notified in the case of a bogus volume explicitly to
1207 make it possible to create a volume, do a partial restore, then abort the
1208 operation without ever putting the volume online. This is essential in the
1209 case of a volume move operation between two partitions on the same server. In
1210 that case, there would be two instances of the same volume, one of them bogus,
1211 which the file server would attempt to put on line */
1213 FSYNC_askfs(volume, tpartp->name, FSYNC_DONE, 0); /* don't put online */
1215 FSYNC_askfs(volume, tpartp->name, FSYNC_ON, 0); /* fs can use it again */
1216 /* Dettaching it so break all callbacks on it*/
1217 if (V_BreakVolumeCallbacks) {
1218 Log("volume %u detached; breaking all call backs\n", volume);
1219 (*V_BreakVolumeCallbacks)(volume);
1225 void VDetachVolume(Error *ec, Volume *vp)
1228 VDetachVolume_r(ec, vp);
1233 int VAllocBitmapEntry_r(ec,vp,index)
1236 register struct vnodeIndex *index;
1238 register byte *bp,*ep;
1240 /* This test is probably redundant */
1241 if (!VolumeWriteable(vp)) {
1246 if ((programType == fileServer) && !index->bitmap) {
1249 if (vp->specialStatus == VBUSY) {
1250 if (vp->goingOffline) { /* vos dump waiting for the volume to
1251 go offline. We probably come here
1252 from AddNewReadableResidency */
1256 while (vp->specialStatus == VBUSY)
1257 #ifdef AFS_PTHREAD_ENV
1259 #else /* AFS_PTHREAD_ENV */
1261 #endif /* AFS_PTHREAD_ENV */
1265 if (!index->bitmap) {
1266 vp->specialStatus = VBUSY; /* Stop anyone else from using it.*/
1267 for (i = 0; i<nVNODECLASSES; i++) {
1272 vp->specialStatus = 0;
1273 vp->shuttingDown = 1; /* Let who has it free it. */
1278 vp->specialStatus = 0; /* Allow others to have access. */
1281 #endif /* BITMAP_LATER */
1282 bp = index->bitmap + index->bitmapOffset;
1283 ep = index->bitmap + index->bitmapSize;
1285 if ((*(bit32 *)bp) != 0xffffffff) {
1287 index->bitmapOffset = bp - index->bitmap;
1290 o = ffs(~*bp)-1; /* ffs is documented in BSTRING(3) */
1292 return (bp - index->bitmap)*8 + o;
1294 bp += sizeof(bit32) /* i.e. 4 */;
1296 /* No bit map entry--must grow bitmap */
1298 realloc(index->bitmap, index->bitmapSize+VOLUME_BITMAP_GROWSIZE);
1301 bp += index->bitmapSize;
1302 bzero(bp, VOLUME_BITMAP_GROWSIZE);
1303 index->bitmapOffset = index->bitmapSize;
1304 index->bitmapSize += VOLUME_BITMAP_GROWSIZE;
1306 return index->bitmapOffset*8;
1309 int VAllocBitmapEntry(ec,vp,index)
1312 register struct vnodeIndex *index;
1316 retVal = VAllocBitmapEntry_r(ec,vp,index);
1321 void VFreeBitMapEntry_r(Error *ec, register struct vnodeIndex *index,
1324 unsigned int offset;
1327 if (!index->bitmap) return;
1328 #endif /* BITMAP_LATER */
1329 offset = bitNumber>>3;
1330 if (offset >= index->bitmapSize) {
1334 if (offset < index->bitmapOffset)
1335 index->bitmapOffset = offset&~3; /* Truncate to nearest bit32 */
1336 *(index->bitmap + offset) &= ~(1 << (bitNumber & 0x7));
1339 void VFreeBitMapEntry(Error *ec, register struct vnodeIndex *index,
1343 VFreeBitMapEntry_r(ec, index, bitNumber);
1347 void VUpdateVolume_r(Error *ec,Volume *vp)
1350 if (programType == fileServer)
1351 V_uniquifier(vp) = (V_inUse(vp)? V_nextVnodeUnique(vp) + 200: V_nextVnodeUnique(vp));
1352 /*printf("Writing volume header for '%s'\n", V_name(vp));*/
1353 WriteVolumeHeader_r(ec, vp);
1356 "VUpdateVolume: error updating volume header, volume %u (%s)\n",
1357 V_id(vp), V_name(vp));
1358 VForceOffline_r(vp);
1362 void VUpdateVolume(Error *ec, Volume *vp)
1365 VUpdateVolume_r(ec, vp);
1369 void VSyncVolume_r(Error *ec, Volume *vp)
1372 VUpdateVolume_r(ec, vp);
1375 fdP = IH_OPEN(V_diskDataHandle(vp));
1376 assert(fdP != NULL);
1377 code = FDH_SYNC(fdP);
1383 void VSyncVolume(Error *ec, Volume *vp)
1386 VSyncVolume_r(ec, vp);
1390 static void FreeVolume(vp)
1396 for (i = 0; i<nVNODECLASSES; i++)
1397 if (vp->vnodeIndex[i].bitmap)
1398 free(vp->vnodeIndex[i].bitmap);
1399 FreeVolumeHeader(vp);
1400 DeleteVolumeFromHashTable(vp);
1404 static void GetBitmap(Error *ec, Volume *vp, VnodeClass class)
1406 StreamHandle_t *file;
1410 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1411 struct vnodeIndex *vip = &vp->vnodeIndex[class];
1412 struct VnodeDiskObject *vnode;
1413 unsigned int unique = 0;
1417 #endif /* BITMAP_LATER */
1421 fdP = IH_OPEN(vip->handle);
1422 assert (fdP != NULL);
1423 file = FDH_FDOPEN(fdP, "r");
1424 assert (file != NULL);
1425 vnode = (VnodeDiskObject *) malloc(vcp->diskSize);
1426 assert(vnode != NULL);
1427 size = OS_SIZE(fdP->fd_fd);
1429 nVnodes = (size <= vcp->diskSize? 0: size-vcp->diskSize)
1431 vip->bitmapSize = ((nVnodes/8)+10)/4*4; /* The 10 is a little extra so
1432 a few files can be created in this volume,
1433 the whole thing is rounded up to nearest 4
1434 bytes, because the bit map allocator likes
1437 BitMap = (byte *) calloc(1, vip->bitmapSize);
1438 assert(BitMap != NULL);
1439 #else /* BITMAP_LATER */
1440 vip->bitmap = (byte *) calloc(1, vip->bitmapSize);
1441 assert(vip->bitmap != NULL);
1442 vip->bitmapOffset = 0;
1443 #endif /* BITMAP_LATER */
1444 if (STREAM_SEEK(file,vcp->diskSize,0) != -1) {
1446 for (bitNumber = 0; bitNumber < nVnodes+100; bitNumber++) {
1447 if (STREAM_READ(vnode, vcp->diskSize, 1, file) != 1)
1449 if (vnode->type != vNull) {
1450 if (vnode->vnodeMagic != vcp->magic) {
1451 Log("GetBitmap: addled vnode index in volume %s; volume needs salvage\n",
1457 *(BitMap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1458 #else /* BITMAP_LATER */
1459 *(vip->bitmap + (bitNumber>>3)) |= (1 << (bitNumber & 0x7));
1460 #endif /* BITMAP_LATER */
1461 if (unique <= vnode->uniquifier)
1462 unique = vnode->uniquifier + 1;
1464 #ifndef AFS_PTHREAD_ENV
1465 if ((bitNumber & 0x00ff) == 0x0ff) { /* every 256 iterations */
1468 #endif /* !AFS_PTHREAD_ENV */
1471 if (vp->nextVnodeUnique < unique) {
1472 Log("GetBitmap: bad volume uniquifier for volume %s; volume needs salvage\n", V_name(vp));
1475 /* Paranoia, partly justified--I think fclose after fdopen
1476 * doesn't seem to close fd. In any event, the documentation
1477 * doesn't specify, so it's safer to close it twice.
1483 /* There may have been a racing condition with some other thread, both
1484 * creating the bitmaps for this volume. If the other thread was faster
1485 * the pointer to bitmap should already be filled and we can free ours.
1487 if (vip->bitmap == NULL) {
1488 vip->bitmap = BitMap;
1489 vip->bitmapOffset = 0;
1491 free((byte *)BitMap);
1492 #endif /* BITMAP_LATER */
1495 static void GetVolumePath(Error *ec, VolId volumeId, char **partitionp,
1498 static char partition[VMAXPATHLEN], name[VMAXPATHLEN];
1499 char path[VMAXPATHLEN];
1501 struct DiskPartition *dp;
1505 sprintf(&name[1],VFORMAT,volumeId);
1506 for (dp = DiskPartitionList; dp; dp = dp->next) {
1508 strcpy(path, VPartitionPath(dp));
1510 if (stat(path,&status) == 0) {
1511 strcpy(partition, dp->name);
1518 *partitionp = *namep = NULL;
1521 *partitionp = partition;
1531 return atoi(name+1);
1534 char *VolumeExternalName(volumeId)
1537 static char name[15];
1538 sprintf(name,VFORMAT,volumeId);
1542 #if TRANSARC_VOL_STATS
1543 #define OneDay (86400) /* 24 hours' worth of seconds */
1545 #define OneDay (24*60*60) /* 24 hours */
1546 #endif /* TRANSARC_VOL_STATS */
1548 #define Midnight(date) ((date-TimeZoneCorrection)/OneDay*OneDay+TimeZoneCorrection)
1550 /*------------------------------------------------------------------------
1551 * [export] VAdjustVolumeStatistics
1554 * If we've passed midnight, we need to update all the day use
1555 * statistics as well as zeroing the detailed volume statistics
1556 * (if we are implementing them).
1559 * vp : Pointer to the volume structure describing the lucky
1560 * volume being considered for update.
1566 * Nothing interesting.
1570 *------------------------------------------------------------------------*/
1572 VAdjustVolumeStatistics_r(vp)
1573 register Volume *vp;
1575 { /*VAdjustVolumeStatistics*/
1577 unsigned int now = FT_ApproxTime();
1579 if (now - V_dayUseDate(vp) > OneDay) {
1582 ndays = (now - V_dayUseDate(vp)) / OneDay;
1583 for (i = 6; i>ndays-1; i--)
1584 V_weekUse(vp)[i] = V_weekUse(vp)[i-ndays];
1585 for (i = 0; i<ndays-1 && i<7; i++)
1586 V_weekUse(vp)[i] = 0;
1588 V_weekUse(vp)[ndays-1] = V_dayUse(vp);
1590 V_dayUseDate(vp) = Midnight(now);
1592 #if TRANSARC_VOL_STATS
1594 * All we need to do is bzero the entire VOL_STATS_BYTES of
1595 * the detailed volume statistics area.
1597 bzero((char *)(V_stat_area(vp)), VOL_STATS_BYTES);
1598 #endif /* TRANSARC_VOL_STATS */
1599 } /*It's been more than a day of collection*/
1601 #if TRANSARC_VOL_STATS
1603 * Always return happily.
1606 #endif /* TRANSARC_VOL_STATS */
1608 } /*VAdjustVolumeStatistics*/
1610 VAdjustVolumeStatistics(vp)
1611 register Volume *vp;
1615 VAdjustVolumeStatistics_r(vp);
1620 void VBumpVolumeUsage_r(register Volume *vp)
1622 unsigned int now = FT_ApproxTime();
1623 if (now - V_dayUseDate(vp) > OneDay)
1624 VAdjustVolumeStatistics_r(vp);
1626 * Save the volume header image to disk after every 128 bumps to dayUse.
1628 if ((V_dayUse(vp)++ & 127) == 0) {
1630 VUpdateVolume_r(&error, vp);
1634 void VBumpVolumeUsage(register Volume *vp)
1637 VBumpVolumeUsage_r(vp);
1641 void VSetDiskUsage_r(void)
1643 static int FifteenMinuteCounter = 0;
1646 /* NOTE: Don't attempt to access the partitions list until the
1647 initialization level indicates that all volumes are attached,
1648 which implies that all partitions are initialized. */
1649 #ifdef AFS_PTHREAD_ENV
1651 #else /* AFS_PTHREAD_ENV */
1653 #endif /* AFS_PTHREAD_ENV */
1656 VResetDiskUsage_r();
1657 if (++FifteenMinuteCounter == 3) {
1658 FifteenMinuteCounter = 0;
1663 void VSetDiskUsage(void)
1670 /* The number of minutes that a volume hasn't been updated before the
1671 * "Dont salvage" flag in the volume header will be turned on */
1672 #define SALVAGE_INTERVAL (10*60)
1674 static VolumeId *UpdateList; /* Pointer to array of Volume ID's */
1675 static int nUpdatedVolumes; /* Updated with entry in UpdateList, salvage after crash flag on */
1676 static int updateSize; /* number of entries possible */
1677 #define UPDATE_LIST_SIZE 100 /* size increment */
1679 void VAddToVolumeUpdateList_r(Error *ec, Volume *vp)
1682 vp->updateTime = FT_ApproxTime();
1683 if (V_dontSalvage(vp) == 0)
1685 V_dontSalvage(vp) = 0;
1686 VSyncVolume_r(ec, vp);
1690 updateSize = UPDATE_LIST_SIZE;
1691 UpdateList = (VolumeId *) malloc(sizeof (VolumeId) * updateSize);
1693 if (nUpdatedVolumes == updateSize) {
1694 updateSize += UPDATE_LIST_SIZE;
1695 UpdateList = (VolumeId *) realloc(UpdateList, sizeof (VolumeId) * updateSize);
1698 UpdateList[nUpdatedVolumes++] = V_id(vp);
1701 static void VScanUpdateList() {
1702 register int i, gap;
1703 register Volume *vp;
1705 afs_int32 now = FT_ApproxTime();
1706 /* Be careful with this code, since it works with interleaved calls to AddToVolumeUpdateList */
1707 for (i = gap = 0; i<nUpdatedVolumes; i++) {
1708 vp = VGetVolume_r(&error, UpdateList[i-gap] = UpdateList[i]);
1711 } else if (vp->nUsers == 1 && now - vp->updateTime > SALVAGE_INTERVAL) {
1712 V_dontSalvage(vp) = DONT_SALVAGE;
1713 VUpdateVolume_r(&error, vp); /* No need to fsync--not critical */
1718 #ifndef AFS_PTHREAD_ENV
1720 #endif /* !AFS_PTHREAD_ENV */
1722 nUpdatedVolumes -= gap;
1725 /***************************************************/
1726 /* Add on routines to manage a volume header cache */
1727 /***************************************************/
1729 static struct volHeader *volumeLRU;
1731 /* Allocate a bunch of headers; string them together */
1732 static void InitLRU(howMany)
1735 register struct volHeader *hp;
1736 if (programType != fileServer)
1738 hp = (struct volHeader *)(calloc(howMany, sizeof(struct volHeader)));
1740 ReleaseVolumeHeader(hp++);
1743 /* Get a volume header from the LRU list; update the old one if necessary */
1744 /* Returns 1 if there was already a header, which is removed from the LRU list */
1745 static int GetVolumeHeader(vp)
1746 register Volume *vp;
1749 register struct volHeader *hd;
1751 static int everLogged = 0;
1753 old = (vp->header != 0); /* old == volume already has a header */
1754 if (programType != fileServer) {
1756 hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1765 if (volumeLRU == hd)
1766 volumeLRU = hd->next;
1767 assert(hd->back == vp);
1771 hd = volumeLRU->prev; /* not currently in use and least recently used */
1773 hd = (struct volHeader *) calloc(1, sizeof(*vp->header));
1774 hd->prev = hd->next = hd; /* make it look like single elt LRU */
1776 Log("****Allocated more volume headers, probably leak****\n");
1781 if (hd->diskstuff.inUse) {
1782 WriteVolumeHeader_r(&error, hd->back);
1783 /* Ignore errors; catch them later */
1785 hd->back->header = 0;
1790 if (hd->next) { /* hd->next != 0 --> in LRU chain (we zero it later) */
1791 hd->prev->next = hd->next; /* pull hd out of LRU list */
1792 hd->next->prev = hd->prev; /* if hd only element, this is noop */
1794 hd->next = hd->prev = 0;
1795 /* if not in LRU chain, next test won't be true */
1796 if (hd == volumeLRU) /* last header item, turn into empty list */
1797 volumeLRU = (struct volHeader *) 0;
1802 /* Put it at the top of the LRU chain */
1803 static void ReleaseVolumeHeader(hd)
1804 register struct volHeader *hd;
1806 if (programType != fileServer)
1808 if (!hd || hd->next) /* no header, or header already released */
1811 hd->next = hd->prev = hd;
1813 hd->prev = volumeLRU->prev;
1814 hd->next = volumeLRU;
1815 hd->prev->next = hd->next->prev = hd;
1820 static void FreeVolumeHeader(vp)
1821 register Volume *vp;
1823 register struct volHeader *hd = vp->header;
1826 if (programType == fileServer) {
1827 ReleaseVolumeHeader(hd);
1837 /***************************************************/
1838 /* Routines to add volume to hash chain, delete it */
1839 /***************************************************/
1841 static void AddVolumeToHashTable(vp, hashid)
1842 register Volume *vp;
1844 int hash = VOLUME_HASH(hashid);
1845 vp->hashid = hashid;
1846 vp->hashNext = VolumeHashTable[hash];
1847 VolumeHashTable[hash] = vp;
1848 vp->vnodeHashOffset = VolumeHashOffset_r();
1851 static void DeleteVolumeFromHashTable(vp)
1852 register Volume *vp;
1854 int hash = VOLUME_HASH(vp->hashid);
1855 if (VolumeHashTable[hash] == vp)
1856 VolumeHashTable[hash] = vp->hashNext;
1858 Volume *tvp = VolumeHashTable[hash];
1861 while (tvp->hashNext && tvp->hashNext != vp)
1862 tvp = tvp->hashNext;
1863 if (tvp->hashNext == NULL)
1865 tvp->hashNext = vp->hashNext;
1870 void VPrintCacheStats_r(void)
1872 register struct VnodeClassInfo *vcp;
1873 vcp = &VnodeClassInfo[vLarge];
1874 Log("Large vnode cache, %d entries, %d allocs, %d gets (%d reads), %d writes\n",
1875 vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1876 vcp = &VnodeClassInfo[vSmall];
1877 Log("Small vnode cache,%d entries, %d allocs, %d gets (%d reads), %d writes\n",
1878 vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
1879 Log("Volume header cache, %d entries, %d gets, %d replacements\n",
1880 VolumeCacheSize, VolumeGets, VolumeReplacements);
1883 void VPrintCacheStats(void)
1886 VPrintCacheStats_r();