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>
26 #include <afs/afsint.h>
29 #include <sys/param.h>
30 #if !defined(AFS_SGI_ENV)
33 #else /* AFS_OSF_ENV */
34 #ifdef AFS_VFSINCL_ENV
37 #include <sys/fs/ufs_fs.h>
39 #if defined(AFS_DARWIN_ENV) || defined(AFS_XBSD_ENV)
40 #include <ufs/ufs/dinode.h>
41 #include <ufs/ffs/fs.h>
46 #else /* AFS_VFSINCL_ENV */
47 #if !defined(AFS_AIX_ENV) && !defined(AFS_LINUX20_ENV) && !defined(AFS_XBSD_ENV)
50 #endif /* AFS_VFSINCL_ENV */
51 #endif /* AFS_OSF_ENV */
52 #endif /* AFS_SGI_ENV */
53 #endif /* AFS_NT40_ENV */
71 #if defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
73 #include <sys/mnttab.h>
74 #include <sys/mntent.h>
80 #if defined(AFS_SGI_ENV)
83 #ifdef AFS_SGI_EFS_IOPS_ENV
84 #define ROOTINO EFS_ROOTINO
85 #include <sys/fs/efs.h>
86 #include "sgiefs/efs.h" /* until 5.1 release */
91 #ifndef AFS_LINUX20_ENV
92 #include <fstab.h> /* Need to find in libc 5, present in libc 6 */
95 #endif /* AFS_SGI_ENV */
97 #endif /* AFS_HPUX_ENV */
101 #include <netinet/in.h>
102 #include <sys/wait.h>
105 #include <sys/time.h>
106 #endif /* ITIMER_REAL */
107 #endif /* AFS_NT40_ENV */
108 #if defined(AFS_SUN5_ENV) || defined(AFS_NT40_ENV) || defined(AFS_LINUX20_ENV)
115 #include <afs/errors.h>
118 #include <afs/afssyscalls.h>
120 #include <afs/afsutil.h>
126 #include "partition.h"
127 #ifdef AFS_PTHREAD_ENV
129 #else /* AFS_PTHREAD_ENV */
130 #include "afs/assert.h"
131 #endif /* AFS_PTHREAD_ENV */
139 #define afs_stat stat64
140 #define afs_fstat fstat64
141 #define afs_open open64
142 #else /* !O_LARGEFILE */
143 #define afs_stat stat
144 #define afs_fstat fstat
145 #define afs_open open
146 #endif /* !O_LARGEFILE */
148 #ifdef AFS_PTHREAD_ENV
149 pthread_mutex_t vol_glock_mutex;
150 pthread_mutex_t vol_attach_mutex;
151 pthread_mutex_t vol_fsync_mutex;
152 pthread_mutex_t vol_trans_mutex;
153 pthread_cond_t vol_put_volume_cond;
154 pthread_cond_t vol_sleep_cond;
155 int vol_attach_threads = 1;
156 #endif /* AFS_PTHREAD_ENV */
159 extern void *calloc(), *realloc();
162 /*@printflike@*/ extern void Log(const char *format, ...);
164 /* Forward declarations */
165 static Volume *attach2(Error * ec, char *path,
166 register struct VolumeHeader *header,
167 struct DiskPartition *partp, int isbusy);
168 static void FreeVolume(Volume * vp);
169 static void VScanUpdateList(void);
170 static void InitLRU(int howMany);
171 static int GetVolumeHeader(register Volume * vp);
172 static void ReleaseVolumeHeader(register struct volHeader *hd);
173 static void FreeVolumeHeader(register Volume * vp);
174 static void AddVolumeToHashTable(register Volume * vp, int hashid);
175 static void DeleteVolumeFromHashTable(register Volume * vp);
176 static int VHold(Volume * vp);
177 static int VHold_r(Volume * vp);
178 static void GetBitmap(Error * ec, Volume * vp, VnodeClass class);
179 static void GetVolumePath(Error * ec, VolId volumeId, char **partitionp,
181 static void VReleaseVolumeHandles_r(Volume * vp);
182 static void VCloseVolumeHandles_r(Volume * vp);
184 int LogLevel; /* Vice loglevel--not defined as extern so that it will be
185 * defined when not linked with vice, XXXX */
186 ProgramType programType; /* The type of program using the package */
189 #define VOLUME_BITMAP_GROWSIZE 16 /* bytes, => 128vnodes */
190 /* Must be a multiple of 4 (1 word) !! */
191 #define VOLUME_HASH_TABLE_SIZE 128 /* Must be a power of 2!! */
192 #define VOLUME_HASH(volumeId) (volumeId&(VOLUME_HASH_TABLE_SIZE-1))
193 private Volume *VolumeHashTable[VOLUME_HASH_TABLE_SIZE];
196 /* This macro is used where an ffs() call does not exist. Was in util/ffs.c */
200 afs_int32 ffs_tmp = x;
204 for (ffs_i = 1;; ffs_i++) {
211 #endif /* !AFS_HAVE_FFS */
213 #ifdef AFS_PTHREAD_ENV
214 #include "rx/rx_queue.h"
215 typedef struct diskpartition_queue_t {
216 struct rx_queue queue;
217 struct DiskPartition * diskP;
218 } diskpartition_queue_t;
219 typedef struct vinitvolumepackage_thread_t {
220 struct rx_queue queue;
221 pthread_cond_t thread_done_cv;
222 int n_threads_complete;
223 } vinitvolumepackage_thread_t;
224 static void * VInitVolumePackageThread(void * args);
225 #endif /* AFS_PTHREAD_ENV */
227 struct Lock vol_listLock; /* Lock obtained when listing volumes: prevents a volume from being missed if the volume is attached during a list volumes */
229 extern struct Lock FSYNC_handler_lock;
231 static int TimeZoneCorrection; /* Number of seconds west of GMT */
233 /* Common message used when the volume goes off line */
234 char *VSalvageMessage =
235 "Files in this volume are currently unavailable; call operations";
237 int VInit; /* 0 - uninitialized,
238 * 1 - initialized but not all volumes have been attached,
239 * 2 - initialized and all volumes have been attached,
240 * 3 - initialized, all volumes have been attached, and
241 * VConnectFS() has completed. */
244 bit32 VolumeCacheCheck; /* Incremented everytime a volume goes on line--
245 * used to stamp volume headers and in-core
246 * vnodes. When the volume goes on-line the
247 * vnode will be invalidated
248 * access only with VOL_LOCK held */
250 int VolumeCacheSize = 200, VolumeGets = 0, VolumeReplacements = 0, Vlooks = 0;
254 VInitVolumePackage(ProgramType pt, int nLargeVnodes, int nSmallVnodes,
255 int connect, int volcache)
257 int errors = 0; /* Number of errors while finding vice partitions. */
263 #ifdef AFS_PTHREAD_ENV
264 assert(pthread_mutex_init(&vol_glock_mutex, NULL) == 0);
265 assert(pthread_mutex_init(&vol_attach_mutex, NULL) == 0);
266 assert(pthread_mutex_init(&vol_fsync_mutex, NULL) == 0);
267 assert(pthread_mutex_init(&vol_trans_mutex, NULL) == 0);
268 assert(pthread_cond_init(&vol_put_volume_cond, NULL) == 0);
269 assert(pthread_cond_init(&vol_sleep_cond, NULL) == 0);
270 #else /* AFS_PTHREAD_ENV */
272 #endif /* AFS_PTHREAD_ENV */
273 Lock_Init(&vol_listLock);
274 Lock_Init(&FSYNC_handler_lock);
275 srandom(time(0)); /* For VGetVolumeInfo */
276 gettimeofday(&tv, &tz);
277 TimeZoneCorrection = tz.tz_minuteswest * 60;
279 /* Ok, we have done enough initialization that fileserver can
280 * start accepting calls, even though the volumes may not be
281 * available just yet.
285 if (programType == fileServer) {
286 /* File server or "stand" */
290 if (volcache > VolumeCacheSize)
291 VolumeCacheSize = volcache;
292 InitLRU(VolumeCacheSize);
294 VInitVnodes(vLarge, nLargeVnodes);
295 VInitVnodes(vSmall, nSmallVnodes);
298 errors = VAttachPartitions();
302 if (programType == fileServer) {
303 struct DiskPartition *diskP;
304 #ifdef AFS_PTHREAD_ENV
305 struct vinitvolumepackage_thread_t params;
306 struct diskpartition_queue_t * dpq;
309 pthread_attr_t attrs;
311 assert(pthread_cond_init(¶ms.thread_done_cv,NULL) == 0);
313 params.n_threads_complete = 0;
315 /* create partition work queue */
316 for (len=0, diskP = DiskPartitionList; diskP; diskP = diskP->next, len++) {
317 dpq = (diskpartition_queue_t *) malloc(sizeof(struct diskpartition_queue_t));
320 queue_Prepend(¶ms,dpq);
323 assert(pthread_attr_init(&attrs) == 0);
324 assert(pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED) == 0);
326 len = MIN(len, vol_attach_threads);
329 for (i=0; i < len; i++) {
330 assert(pthread_create
331 (&tid, &attrs, &VInitVolumePackageThread,
335 while(params.n_threads_complete < len) {
336 pthread_cond_wait(¶ms.thread_done_cv,&vol_glock_mutex);
340 assert(pthread_cond_destroy(¶ms.thread_done_cv) == 0);
342 #else /* AFS_PTHREAD_ENV */
346 /* Attach all the volumes in this partition */
347 for (diskP = DiskPartitionList; diskP; diskP = diskP->next) {
348 int nAttached = 0, nUnattached = 0;
349 Log("Partition %s: attaching volumes\n", diskP->name);
350 dirp = opendir(VPartitionPath(diskP));
352 while ((dp = readdir(dirp))) {
354 p = strrchr(dp->d_name, '.');
355 if (p != NULL && strcmp(p, VHDREXT) == 0) {
358 vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
360 (*(vp ? &nAttached : &nUnattached))++;
361 if (error == VOFFLINE)
362 Log("Volume %d stays offline (/vice/offline/%s exists)\n", VolumeNumber(dp->d_name), dp->d_name);
363 else if (LogLevel >= 5) {
364 Log("Partition %s: attached volume %d (%s)\n",
365 diskP->name, VolumeNumber(dp->d_name),
373 Log("Partition %s: attached %d volumes; %d volumes not attached\n", diskP->name, nAttached, nUnattached);
376 #endif /* AFS_PTHREAD_ENV */
379 VInit = 2; /* Initialized, and all volumes have been attached */
380 if (programType == volumeUtility && connect) {
382 Log("Unable to connect to file server; aborted\n");
383 Lock_Destroy(&FSYNC_handler_lock);
390 #ifdef AFS_PTHREAD_ENV
392 VInitVolumePackageThread(void * args) {
393 int errors = 0; /* Number of errors while finding vice partitions. */
397 struct DiskPartition *diskP;
398 struct vinitvolumepackage_thread_t * params;
399 struct diskpartition_queue_t * dpq;
401 params = (vinitvolumepackage_thread_t *) args;
405 /* Attach all the volumes in this partition */
406 while (queue_IsNotEmpty(params)) {
407 int nAttached = 0, nUnattached = 0;
409 dpq = queue_First(params,diskpartition_queue_t);
415 Log("Partition %s: attaching volumes\n", diskP->name);
416 dirp = opendir(VPartitionPath(diskP));
418 while ((dp = readdir(dirp))) {
420 p = strrchr(dp->d_name, '.');
421 if (p != NULL && strcmp(p, VHDREXT) == 0) {
424 vp = VAttachVolumeByName(&error, diskP->name, dp->d_name,
426 (*(vp ? &nAttached : &nUnattached))++;
427 if (error == VOFFLINE)
428 Log("Volume %d stays offline (/vice/offline/%s exists)\n", VolumeNumber(dp->d_name), dp->d_name);
429 else if (LogLevel >= 5) {
430 Log("Partition %s: attached volume %d (%s)\n",
431 diskP->name, VolumeNumber(dp->d_name),
439 Log("Partition %s: attached %d volumes; %d volumes not attached\n", diskP->name, nAttached, nUnattached);
444 params->n_threads_complete++;
445 pthread_cond_signal(¶ms->thread_done_cv);
449 #endif /* AFS_PTHREAD_ENV */
451 /* This must be called by any volume utility which needs to run while the
452 file server is also running. This is separated from VInitVolumePackage so
453 that a utility can fork--and each of the children can independently
454 initialize communication with the file server */
460 retVal = VConnectFS_r();
469 assert(VInit == 2 && programType == volumeUtility);
470 rc = FSYNC_clientInit();
477 VDisconnectFS_r(void)
479 assert(programType == volumeUtility);
496 register Volume *vp, *np;
497 register afs_int32 code;
499 Log("VShutdown: shutting down on-line volumes...\n");
500 for (i = 0; i < VOLUME_HASH_TABLE_SIZE; i++) {
501 /* try to hold first volume in the hash table */
502 for (vp = VolumeHashTable[i]; vp; vp = vp->hashNext) {
506 /* otherwise we go around again, trying another volume */
510 Log("VShutdown: Attempting to take volume %u offline.\n",
512 /* first compute np before releasing vp, in case vp disappears
513 * after releasing. Hold it, so it doesn't disapear. If we
514 * can't hold it, try the next one in the chain. Invariant
515 * at the top of this loop is that vp is held (has extra ref count).
517 for (np = vp->hashNext; np; np = np->hashNext) {
522 /* next, take the volume offline (drops reference count) */
523 VOffline_r(vp, "File server was shut down");
524 vp = np; /* next guy to try */
527 Log("VShutdown: complete.\n");
540 ReadHeader(Error * ec, IHandle_t * h, char *to, int size, bit32 magic,
543 struct versionStamp *vsn;
558 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
560 FDH_REALLYCLOSE(fdP);
563 vsn = (struct versionStamp *)to;
564 if (FDH_READ(fdP, to, size) != size || vsn->magic != magic) {
566 FDH_REALLYCLOSE(fdP);
571 /* Check is conditional, in case caller wants to inspect version himself */
572 if (version && vsn->version != version) {
577 /* VolumeHeaderToDisk
578 * Allows for storing 64 bit inode numbers in on-disk volume header
582 VolumeHeaderToDisk(VolumeDiskHeader_t * dh, VolumeHeader_t * h)
585 memset((char *)dh, 0, sizeof(VolumeDiskHeader_t));
586 dh->stamp = h->stamp;
588 dh->parent = h->parent;
590 #ifdef AFS_64BIT_IOPS_ENV
591 dh->volumeInfo_lo = (afs_int32) h->volumeInfo & 0xffffffff;
592 dh->volumeInfo_hi = (afs_int32) (h->volumeInfo >> 32) & 0xffffffff;
593 dh->smallVnodeIndex_lo = (afs_int32) h->smallVnodeIndex & 0xffffffff;
594 dh->smallVnodeIndex_hi =
595 (afs_int32) (h->smallVnodeIndex >> 32) & 0xffffffff;
596 dh->largeVnodeIndex_lo = (afs_int32) h->largeVnodeIndex & 0xffffffff;
597 dh->largeVnodeIndex_hi =
598 (afs_int32) (h->largeVnodeIndex >> 32) & 0xffffffff;
599 dh->linkTable_lo = (afs_int32) h->linkTable & 0xffffffff;
600 dh->linkTable_hi = (afs_int32) (h->linkTable >> 32) & 0xffffffff;
602 dh->volumeInfo_lo = h->volumeInfo;
603 dh->smallVnodeIndex_lo = h->smallVnodeIndex;
604 dh->largeVnodeIndex_lo = h->largeVnodeIndex;
605 dh->linkTable_lo = h->linkTable;
609 /* DiskToVolumeHeader
610 * Reads volume header file from disk, convering 64 bit inodes
611 * if required. Makes the assumption that AFS has *always*
612 * zero'd the volume header file so that high parts of inode
613 * numbers are 0 in older (SGI EFS) volume header files.
616 DiskToVolumeHeader(VolumeHeader_t * h, VolumeDiskHeader_t * dh)
618 memset((char *)h, 0, sizeof(VolumeHeader_t));
619 h->stamp = dh->stamp;
621 h->parent = dh->parent;
623 #ifdef AFS_64BIT_IOPS_ENV
625 (Inode) dh->volumeInfo_lo | ((Inode) dh->volumeInfo_hi << 32);
628 (Inode) dh->smallVnodeIndex_lo | ((Inode) dh->
629 smallVnodeIndex_hi << 32);
632 (Inode) dh->largeVnodeIndex_lo | ((Inode) dh->
633 largeVnodeIndex_hi << 32);
635 (Inode) dh->linkTable_lo | ((Inode) dh->linkTable_hi << 32);
637 h->volumeInfo = dh->volumeInfo_lo;
638 h->smallVnodeIndex = dh->smallVnodeIndex_lo;
639 h->largeVnodeIndex = dh->largeVnodeIndex_lo;
640 h->linkTable = dh->linkTable_lo;
646 WriteVolumeHeader_r(ec, vp)
650 IHandle_t *h = V_diskDataHandle(vp);
660 if (FDH_SEEK(fdP, 0, SEEK_SET) < 0) {
662 FDH_REALLYCLOSE(fdP);
665 if (FDH_WRITE(fdP, (char *)&V_disk(vp), sizeof(V_disk(vp)))
666 != sizeof(V_disk(vp))) {
668 FDH_REALLYCLOSE(fdP);
674 /* Attach an existing volume, given its pathname, and return a
675 pointer to the volume header information. The volume also
676 normally goes online at this time. An offline volume
677 must be reattached to make it go online */
679 VAttachVolumeByName(Error * ec, char *partition, char *name, int mode)
684 retVal = VAttachVolumeByName_r(ec, partition, name, mode);
691 VAttachVolumeByName_r(Error * ec, char *partition, char *name, int mode)
695 struct afs_stat status;
696 struct VolumeDiskHeader diskHeader;
697 struct VolumeHeader iheader;
698 struct DiskPartition *partp;
702 if (programType == volumeUtility) {
704 VLockPartition_r(partition);
706 if (programType == fileServer) {
707 vp = VGetVolume_r(ec, VolumeNumber(name));
711 if (vp->specialStatus == VBUSY)
713 VDetachVolume_r(ec, vp);
715 Log("VAttachVolume: Error detaching volume (%s)\n", name);
720 if (!(partp = VGetPartition_r(partition, 0))) {
722 Log("VAttachVolume: Error getting partition (%s)\n", partition);
727 strcpy(path, VPartitionPath(partp));
731 if ((fd = afs_open(path, O_RDONLY)) == -1 || afs_fstat(fd, &status) == -1) {
732 Log("VAttachVolume: Failed to open %s (errno %d)\n", path, errno);
739 n = read(fd, &diskHeader, sizeof(diskHeader));
742 if (n != sizeof(diskHeader)
743 || diskHeader.stamp.magic != VOLUMEHEADERMAGIC) {
744 Log("VAttachVolume: Error reading volume header %s\n", path);
748 if (diskHeader.stamp.version != VOLUMEHEADERVERSION) {
749 Log("VAttachVolume: Volume %s, version number is incorrect; volume needs salvaged\n", path);
754 DiskToVolumeHeader(&iheader, &diskHeader);
755 if (programType == volumeUtility && mode != V_SECRETLY && mode != V_PEEK) {
756 if (FSYNC_askfs(iheader.id, partition, FSYNC_NEEDVOLUME, mode)
758 Log("VAttachVolume: attach of volume %u apparently denied by file server\n", iheader.id);
759 *ec = VNOVOL; /* XXXX */
764 vp = attach2(ec, path, &iheader, partp, isbusy);
765 if (programType == volumeUtility && vp) {
766 /* duplicate computation in fssync.c about whether the server
767 * takes the volume offline or not. If the volume isn't
768 * offline, we must not return it when we detach the volume,
769 * or the server will abort */
770 if (mode == V_READONLY || mode == V_PEEK
771 || (!VolumeWriteable(vp) && (mode == V_CLONE || mode == V_DUMP)))
772 vp->needsPutBack = 0;
774 vp->needsPutBack = 1;
776 /* OK, there's a problem here, but one that I don't know how to
777 * fix right now, and that I don't think should arise often.
778 * Basically, we should only put back this volume to the server if
779 * it was given to us by the server, but since we don't have a vp,
780 * we can't run the VolumeWriteable function to find out as we do
781 * above when computing vp->needsPutBack. So we send it back, but
782 * there's a path in VAttachVolume on the server which may abort
783 * if this volume doesn't have a header. Should be pretty rare
784 * for all of that to happen, but if it does, probably the right
785 * fix is for the server to allow the return of readonly volumes
786 * that it doesn't think are really checked out. */
787 if (programType == volumeUtility && vp == NULL &&
788 mode != V_SECRETLY && mode != V_PEEK) {
789 FSYNC_askfs(iheader.id, partition, FSYNC_ON, 0);
790 } else if (programType == fileServer && vp) {
791 V_needsCallback(vp) = 0;
793 if (VInit >= 2 && V_BreakVolumeCallbacks) {
794 Log("VAttachVolume: Volume %u was changed externally; breaking callbacks\n", V_id(vp));
795 (*V_BreakVolumeCallbacks) (V_id(vp));
798 VUpdateVolume_r(ec, vp);
800 Log("VAttachVolume: Error updating volume\n");
805 if (VolumeWriteable(vp) && V_dontSalvage(vp) == 0) {
806 /* This is a hack: by temporarily settint the incore
807 * dontSalvage flag ON, the volume will be put back on the
808 * Update list (with dontSalvage OFF again). It will then
809 * come back in N minutes with DONT_SALVAGE eventually
810 * set. This is the way that volumes that have never had
811 * it set get it set; or that volumes that have been
812 * offline without DONT SALVAGE having been set also
813 * eventually get it set */
814 V_dontSalvage(vp) = DONT_SALVAGE;
815 VAddToVolumeUpdateList_r(ec, vp);
817 Log("VAttachVolume: Error adding volume to update list\n");
824 Log("VOnline: volume %u (%s) attached and online\n", V_id(vp),
828 if (programType == volumeUtility) {
829 VUnlockPartition_r(partition);
838 attach2(Error * ec, char *path, register struct VolumeHeader * header,
839 struct DiskPartition * partp, int isbusy)
845 vp = (Volume *) calloc(1, sizeof(Volume));
847 vp->specialStatus = (byte) (isbusy ? VBUSY : 0);
848 vp->device = partp->device;
849 vp->partition = partp;
850 IH_INIT(vp->vnodeIndex[vLarge].handle, partp->device, header->parent,
851 header->largeVnodeIndex);
852 IH_INIT(vp->vnodeIndex[vSmall].handle, partp->device, header->parent,
853 header->smallVnodeIndex);
854 IH_INIT(vp->diskDataHandle, partp->device, header->parent,
856 IH_INIT(vp->linkHandle, partp->device, header->parent, header->linkTable);
857 vp->shuttingDown = 0;
858 vp->goingOffline = 0;
862 vp->cacheCheck = ++VolumeCacheCheck;
863 /* just in case this ever rolls over */
865 vp->cacheCheck = ++VolumeCacheCheck;
869 (void)ReadHeader(ec, V_diskDataHandle(vp), (char *)&V_disk(vp),
870 sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
874 Log("VAttachVolume: Error reading diskDataHandle vol header %s; error=%u\n", path, *ec);
877 struct IndexFileHeader iHead;
879 #if OPENAFS_VOL_STATS
881 * We just read in the diskstuff part of the header. If the detailed
882 * volume stats area has not yet been initialized, we should bzero the
883 * area and mark it as initialized.
885 if (!(V_stat_initialized(vp))) {
886 memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
887 V_stat_initialized(vp) = 1;
889 #endif /* OPENAFS_VOL_STATS */
891 (void)ReadHeader(ec, vp->vnodeIndex[vSmall].handle,
892 (char *)&iHead, sizeof(iHead),
893 SMALLINDEXMAGIC, SMALLINDEXVERSION);
896 Log("VAttachVolume: Error reading smallVnode vol header %s; error=%u\n", path, *ec);
900 struct IndexFileHeader iHead;
902 (void)ReadHeader(ec, vp->vnodeIndex[vLarge].handle,
903 (char *)&iHead, sizeof(iHead),
904 LARGEINDEXMAGIC, LARGEINDEXVERSION);
907 Log("VAttachVolume: Error reading largeVnode vol header %s; error=%u\n", path, *ec);
912 struct versionStamp stamp;
914 (void)ReadHeader(ec, V_linkHandle(vp), (char *)&stamp,
915 sizeof(stamp), LINKTABLEMAGIC, LINKTABLEVERSION);
918 Log("VAttachVolume: Error reading namei vol header %s; error=%u\n", path, *ec);
923 Log("VAttachVolume: Error attaching volume %s; volume needs salvage; error=%u\n", path, *ec);
927 if (V_needsSalvaged(vp)) {
928 if (vp->specialStatus)
929 vp->specialStatus = 0;
930 Log("VAttachVolume: volume salvage flag is ON for %s; volume needs salvage\n", path);
935 if (programType == fileServer) {
937 if (V_inUse(vp) && VolumeWriteable(vp)) {
938 if (!V_needsSalvaged(vp)) {
939 V_needsSalvaged(vp) = 1;
940 VUpdateVolume_r(ec, vp);
943 Log("VAttachVolume: volume %s needs to be salvaged; not attached.\n", path);
947 #endif /* FAST_RESTART */
948 if (V_destroyMe(vp) == DESTROY_ME) {
950 Log("VAttachVolume: volume %s is junk; it should be destroyed at next salvage\n", path);
956 AddVolumeToHashTable(vp, V_id(vp));
957 vp->nextVnodeUnique = V_uniquifier(vp);
958 vp->vnodeIndex[vSmall].bitmap = vp->vnodeIndex[vLarge].bitmap = NULL;
960 if (programType == fileServer && VolumeWriteable(vp)) {
962 for (i = 0; i < nVNODECLASSES; i++) {
964 GetBitmap(ec, vp, i);
968 Log("VAttachVolume: error getting bitmap for volume (%s)\n",
974 #endif /* BITMAP_LATER */
976 if (programType == fileServer) {
977 if (vp->specialStatus)
978 vp->specialStatus = 0;
979 if (V_blessed(vp) && V_inService(vp) && !V_needsSalvaged(vp)) {
981 V_offlineMessage(vp)[0] = '\0';
988 /* Attach an existing volume.
989 The volume also normally goes online at this time.
990 An offline volume must be reattached to make it go online.
994 VAttachVolume(Error * ec, VolumeId volumeId, int mode)
999 retVal = VAttachVolume_r(ec, volumeId, mode);
1006 VAttachVolume_r(Error * ec, VolumeId volumeId, int mode)
1009 GetVolumePath(ec, volumeId, &part, &name);
1011 register Volume *vp;
1013 vp = VGetVolume_r(&error, volumeId);
1015 assert(V_inUse(vp) == 0);
1016 VDetachVolume_r(ec, vp);
1020 return VAttachVolumeByName_r(ec, part, name, mode);
1023 /* Increment a reference count to a volume, sans context swaps. Requires
1024 * possibly reading the volume header in from the disk, since there's
1025 * an invariant in the volume package that nUsers>0 ==> vp->header is valid.
1027 * N.B. This call can fail if we can't read in the header!! In this case
1028 * we still guarantee we won't context swap, but the ref count won't be
1029 * incremented (otherwise we'd violate the invariant).
1032 VHold_r(register Volume * vp)
1036 if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
1037 VolumeReplacements++;
1038 ReadHeader(&error, V_diskDataHandle(vp), (char *)&V_disk(vp),
1039 sizeof(V_disk(vp)), VOLUMEINFOMAGIC, VOLUMEINFOVERSION);
1048 VHold(register Volume * vp)
1052 retVal = VHold_r(vp);
1058 VTakeOffline_r(register Volume * vp)
1060 assert(vp->nUsers > 0);
1061 assert(programType == fileServer);
1062 vp->goingOffline = 1;
1063 V_needsSalvaged(vp) = 1;
1067 VTakeOffline(register Volume * vp)
1075 VPutVolume_r(register Volume * vp)
1077 assert(--vp->nUsers >= 0);
1078 if (vp->nUsers == 0) {
1079 ReleaseVolumeHeader(vp->header);
1080 if (vp->goingOffline) {
1082 assert(programType == fileServer);
1083 vp->goingOffline = 0;
1085 VUpdateVolume_r(&error, vp);
1086 VCloseVolumeHandles_r(vp);
1088 Log("VOffline: Volume %u (%s) is now offline", V_id(vp),
1090 if (V_offlineMessage(vp)[0])
1091 Log(" (%s)", V_offlineMessage(vp));
1094 #ifdef AFS_PTHREAD_ENV
1095 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1096 #else /* AFS_PTHREAD_ENV */
1097 LWP_NoYieldSignal(VPutVolume);
1098 #endif /* AFS_PTHREAD_ENV */
1100 if (vp->shuttingDown) {
1101 VReleaseVolumeHandles_r(vp);
1103 if (programType == fileServer)
1104 #ifdef AFS_PTHREAD_ENV
1105 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1106 #else /* AFS_PTHREAD_ENV */
1107 LWP_NoYieldSignal(VPutVolume);
1108 #endif /* AFS_PTHREAD_ENV */
1114 VPutVolume(register Volume * vp)
1121 /* Get a pointer to an attached volume. The pointer is returned regardless
1122 of whether or not the volume is in service or on/off line. An error
1123 code, however, is returned with an indication of the volume's status */
1125 VGetVolume(Error * ec, VolId volumeId)
1129 retVal = VGetVolume_r(ec, volumeId);
1135 VGetVolume_r(Error * ec, VolId volumeId)
1138 unsigned short V0 = 0, V1 = 0, V2 = 0, V3 = 0, V4 = 0, V5 = 0, V6 =
1139 0, V7 = 0, V8 = 0, V9 = 0;
1140 unsigned short V10 = 0, V11 = 0, V12 = 0, V13 = 0, V14 = 0, V15 = 0;
1145 for (vp = VolumeHashTable[VOLUME_HASH(volumeId)];
1146 vp && vp->hashid != volumeId; vp = vp->hashNext)
1153 /* Until we have reached an initialization level of 2
1154 * we don't know whether this volume exists or not.
1155 * We can't sleep and retry later because before a volume
1156 * is attached, the caller tries to get it first. Just
1157 * return VOFFLINE and the caller can choose whether to
1158 * retry the command or not. */
1169 if (vp->nUsers == 0 && !GetVolumeHeader(vp)) {
1171 VolumeReplacements++;
1172 ReadHeader(ec, V_diskDataHandle(vp), (char *)&V_disk(vp),
1173 sizeof(V_disk(vp)), VOLUMEINFOMAGIC,
1177 /* Only log the error if it was a totally unexpected error. Simply
1178 * a missing inode is likely to be caused by the volume being deleted */
1179 if (errno != ENXIO || LogLevel)
1180 Log("Volume %u: couldn't reread volume header\n",
1188 if (vp->shuttingDown) {
1194 if (programType == fileServer) {
1196 if (vp->goingOffline) {
1198 #ifdef AFS_PTHREAD_ENV
1199 pthread_cond_wait(&vol_put_volume_cond, &vol_glock_mutex);
1200 #else /* AFS_PTHREAD_ENV */
1201 LWP_WaitProcess(VPutVolume);
1202 #endif /* AFS_PTHREAD_ENV */
1205 if (vp->specialStatus) {
1207 *ec = vp->specialStatus;
1208 } else if (V_inService(vp) == 0 || V_blessed(vp) == 0) {
1211 } else if (V_inUse(vp) == 0) {
1221 /* if no error, bump nUsers */
1230 /* For both VForceOffline and VOffline, we close all relevant handles.
1231 * For VOffline, if we re-attach the volume, the files may possible be
1232 * different than before.
1235 VReleaseVolumeHandles_r(Volume * vp)
1237 DFlushVolume(V_id(vp));
1238 VReleaseVnodeFiles_r(vp);
1240 /* Too time consuming and unnecessary for the volserver */
1241 if (programType != volumeUtility) {
1242 IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1243 IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1244 IH_CONDSYNC(vp->diskDataHandle);
1246 IH_CONDSYNC(vp->linkHandle);
1247 #endif /* AFS_NT40_ENV */
1250 IH_RELEASE(vp->vnodeIndex[vLarge].handle);
1251 IH_RELEASE(vp->vnodeIndex[vSmall].handle);
1252 IH_RELEASE(vp->diskDataHandle);
1253 IH_RELEASE(vp->linkHandle);
1256 /* Force the volume offline, set the salvage flag. No further references to
1257 * the volume through the volume package will be honored. */
1259 VForceOffline_r(Volume * vp)
1264 strcpy(V_offlineMessage(vp),
1265 "Forced offline due to internal error: volume needs to be salvaged");
1266 Log("Volume %u forced offline: it needs salvaging!\n", V_id(vp));
1268 vp->goingOffline = 0;
1269 V_needsSalvaged(vp) = 1;
1270 VUpdateVolume_r(&error, vp);
1271 #ifdef AFS_PTHREAD_ENV
1272 assert(pthread_cond_broadcast(&vol_put_volume_cond) == 0);
1273 #else /* AFS_PTHREAD_ENV */
1274 LWP_NoYieldSignal(VPutVolume);
1275 #endif /* AFS_PTHREAD_ENV */
1277 VReleaseVolumeHandles_r(vp);
1282 VForceOffline(Volume * vp)
1285 VForceOffline_r(vp);
1289 /* The opposite of VAttachVolume. The volume header is written to disk, with
1290 the inUse bit turned off. A copy of the header is maintained in memory,
1291 however (which is why this is VOffline, not VDetach).
1294 VOffline_r(Volume * vp, char *message)
1297 VolumeId vid = V_id(vp);
1298 assert(programType != volumeUtility);
1303 if (V_offlineMessage(vp)[0] == '\0')
1304 strncpy(V_offlineMessage(vp), message, sizeof(V_offlineMessage(vp)));
1305 V_offlineMessage(vp)[sizeof(V_offlineMessage(vp)) - 1] = '\0';
1306 vp->goingOffline = 1;
1308 vp = VGetVolume_r(&error, vid); /* Wait for it to go offline */
1309 if (vp) /* In case it was reattached... */
1314 VOffline(Volume * vp, char *message)
1317 VOffline_r(vp, message);
1321 /* For VDetachVolume, we close all cached file descriptors, but keep
1322 * the Inode handles in case we need to read from a busy volume.
1325 VCloseVolumeHandles_r(Volume * vp)
1327 DFlushVolume(V_id(vp));
1328 VCloseVnodeFiles_r(vp);
1330 /* Too time consuming and unnecessary for the volserver */
1331 if (programType != volumeUtility) {
1332 IH_CONDSYNC(vp->vnodeIndex[vLarge].handle);
1333 IH_CONDSYNC(vp->vnodeIndex[vSmall].handle);
1334 IH_CONDSYNC(vp->diskDataHandle);
1336 IH_CONDSYNC(vp->linkHandle);
1337 #endif /* AFS_NT40_ENV */
1340 IH_REALLYCLOSE(vp->vnodeIndex[vLarge].handle);
1341 IH_REALLYCLOSE(vp->vnodeIndex[vSmall].handle);
1342 IH_REALLYCLOSE(vp->diskDataHandle);
1343 IH_REALLYCLOSE(vp->linkHandle);
1346 /* This gets used for the most part by utility routines that don't want
1347 * to keep all the volume headers around. Generally, the file server won't
1348 * call this routine, because then the offline message in the volume header
1349 * (or other information) will still be available to clients. For NAMEI, also
1350 * close the file handles.
1353 VDetachVolume_r(Error * ec, Volume * vp)
1356 struct DiskPartition *tpartp;
1357 int notifyServer, useDone;
1359 *ec = 0; /* always "succeeds" */
1360 if (programType == volumeUtility) {
1361 notifyServer = vp->needsPutBack;
1362 useDone = (V_destroyMe(vp) == DESTROY_ME);
1364 tpartp = vp->partition;
1366 DeleteVolumeFromHashTable(vp);
1367 vp->shuttingDown = 1;
1369 /* Will be detached sometime in the future--this is OK since volume is offline */
1371 if (programType == volumeUtility && notifyServer) {
1373 * Note: The server is not notified in the case of a bogus volume
1374 * explicitly to make it possible to create a volume, do a partial
1375 * restore, then abort the operation without ever putting the volume
1376 * online. This is essential in the case of a volume move operation
1377 * between two partitions on the same server. In that case, there
1378 * would be two instances of the same volume, one of them bogus,
1379 * which the file server would attempt to put on line
1382 /* don't put online */
1383 FSYNC_askfs(volume, tpartp->name, FSYNC_DONE, 0);
1385 /* fs can use it again */
1386 FSYNC_askfs(volume, tpartp->name, FSYNC_ON, 0);
1387 /* Dettaching it so break all callbacks on it */
1388 if (V_BreakVolumeCallbacks) {
1389 Log("volume %u detached; breaking all call backs\n", volume);
1390 (*V_BreakVolumeCallbacks) (volume);
1397 VDetachVolume(Error * ec, Volume * vp)
1400 VDetachVolume_r(ec, vp);
1406 VAllocBitmapEntry_r(Error * ec, Volume * vp, register struct vnodeIndex
1409 register byte *bp, *ep;
1411 /* This test is probably redundant */
1412 if (!VolumeWriteable(vp)) {
1413 *ec = (bit32) VREADONLY;
1417 if ((programType == fileServer) && !index->bitmap) {
1420 if (vp->specialStatus == VBUSY) {
1421 if (vp->goingOffline) { /* vos dump waiting for the volume to
1422 * go offline. We probably come here
1423 * from AddNewReadableResidency */
1427 while (vp->specialStatus == VBUSY)
1428 #ifdef AFS_PTHREAD_ENV
1430 #else /* AFS_PTHREAD_ENV */
1432 #endif /* AFS_PTHREAD_ENV */
1436 if (!index->bitmap) {
1437 vp->specialStatus = VBUSY; /* Stop anyone else from using it. */
1438 for (i = 0; i < nVNODECLASSES; i++) {
1440 GetBitmap(ec, vp, i);
1443 vp->specialStatus = 0;
1444 vp->shuttingDown = 1; /* Let who has it free it. */
1449 vp->specialStatus = 0; /* Allow others to have access. */
1452 #endif /* BITMAP_LATER */
1453 bp = index->bitmap + index->bitmapOffset;
1454 ep = index->bitmap + index->bitmapSize;
1456 if ((*(bit32 *) bp) != (bit32) 0xffffffff) {
1458 index->bitmapOffset = (afs_uint32) (bp - index->bitmap);
1461 o = ffs(~*bp) - 1; /* ffs is documented in BSTRING(3) */
1463 return (VnodeId) ((bp - index->bitmap) * 8 + o);
1465 bp += sizeof(bit32) /* i.e. 4 */ ;
1467 /* No bit map entry--must grow bitmap */
1469 realloc(index->bitmap, index->bitmapSize + VOLUME_BITMAP_GROWSIZE);
1472 bp += index->bitmapSize;
1473 memset(bp, 0, VOLUME_BITMAP_GROWSIZE);
1474 index->bitmapOffset = index->bitmapSize;
1475 index->bitmapSize += VOLUME_BITMAP_GROWSIZE;
1477 return index->bitmapOffset * 8;
1481 VAllocBitmapEntry(Error * ec, Volume * vp, register struct vnodeIndex * index)
1485 retVal = VAllocBitmapEntry_r(ec, vp, index);
1491 VFreeBitMapEntry_r(Error * ec, register struct vnodeIndex *index,
1494 unsigned int offset;
1499 #endif /* BITMAP_LATER */
1500 offset = bitNumber >> 3;
1501 if (offset >= index->bitmapSize) {
1505 if (offset < index->bitmapOffset)
1506 index->bitmapOffset = offset & ~3; /* Truncate to nearest bit32 */
1507 *(index->bitmap + offset) &= ~(1 << (bitNumber & 0x7));
1511 VFreeBitMapEntry(Error * ec, register struct vnodeIndex *index,
1515 VFreeBitMapEntry_r(ec, index, bitNumber);
1520 VUpdateVolume_r(Error * ec, Volume * vp)
1523 if (programType == fileServer)
1525 (V_inUse(vp) ? V_nextVnodeUnique(vp) +
1526 200 : V_nextVnodeUnique(vp));
1527 /*printf("Writing volume header for '%s'\n", V_name(vp)); */
1528 WriteVolumeHeader_r(ec, vp);
1530 Log("VUpdateVolume: error updating volume header, volume %u (%s)\n",
1531 V_id(vp), V_name(vp));
1532 VForceOffline_r(vp);
1537 VUpdateVolume(Error * ec, Volume * vp)
1540 VUpdateVolume_r(ec, vp);
1545 VSyncVolume_r(Error * ec, Volume * vp)
1548 VUpdateVolume_r(ec, vp);
1551 fdP = IH_OPEN(V_diskDataHandle(vp));
1552 assert(fdP != NULL);
1553 code = FDH_SYNC(fdP);
1560 VSyncVolume(Error * ec, Volume * vp)
1563 VSyncVolume_r(ec, vp);
1568 FreeVolume(Volume * vp)
1573 for (i = 0; i < nVNODECLASSES; i++)
1574 if (vp->vnodeIndex[i].bitmap)
1575 free(vp->vnodeIndex[i].bitmap);
1576 FreeVolumeHeader(vp);
1577 DeleteVolumeFromHashTable(vp);
1582 GetBitmap(Error * ec, Volume * vp, VnodeClass class)
1584 StreamHandle_t *file;
1587 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
1588 struct vnodeIndex *vip = &vp->vnodeIndex[class];
1589 struct VnodeDiskObject *vnode;
1590 unsigned int unique = 0;
1594 #endif /* BITMAP_LATER */
1598 fdP = IH_OPEN(vip->handle);
1599 assert(fdP != NULL);
1600 file = FDH_FDOPEN(fdP, "r");
1601 assert(file != NULL);
1602 vnode = (VnodeDiskObject *) malloc(vcp->diskSize);
1603 assert(vnode != NULL);
1604 size = OS_SIZE(fdP->fd_fd);
1606 nVnodes = (size <= vcp->diskSize ? 0 : size - vcp->diskSize)
1608 vip->bitmapSize = ((nVnodes / 8) + 10) / 4 * 4; /* The 10 is a little extra so
1609 * a few files can be created in this volume,
1610 * the whole thing is rounded up to nearest 4
1611 * bytes, because the bit map allocator likes
1614 BitMap = (byte *) calloc(1, vip->bitmapSize);
1615 assert(BitMap != NULL);
1616 #else /* BITMAP_LATER */
1617 vip->bitmap = (byte *) calloc(1, vip->bitmapSize);
1618 assert(vip->bitmap != NULL);
1619 vip->bitmapOffset = 0;
1620 #endif /* BITMAP_LATER */
1621 if (STREAM_SEEK(file, vcp->diskSize, 0) != -1) {
1623 for (bitNumber = 0; bitNumber < nVnodes + 100; bitNumber++) {
1624 if (STREAM_READ(vnode, vcp->diskSize, 1, file) != 1)
1626 if (vnode->type != vNull) {
1627 if (vnode->vnodeMagic != vcp->magic) {
1628 Log("GetBitmap: addled vnode index in volume %s; volume needs salvage\n", V_name(vp));
1633 *(BitMap + (bitNumber >> 3)) |= (1 << (bitNumber & 0x7));
1634 #else /* BITMAP_LATER */
1635 *(vip->bitmap + (bitNumber >> 3)) |= (1 << (bitNumber & 0x7));
1636 #endif /* BITMAP_LATER */
1637 if (unique <= vnode->uniquifier)
1638 unique = vnode->uniquifier + 1;
1640 #ifndef AFS_PTHREAD_ENV
1641 if ((bitNumber & 0x00ff) == 0x0ff) { /* every 256 iterations */
1644 #endif /* !AFS_PTHREAD_ENV */
1647 if (vp->nextVnodeUnique < unique) {
1648 Log("GetBitmap: bad volume uniquifier for volume %s; volume needs salvage\n", V_name(vp));
1651 /* Paranoia, partly justified--I think fclose after fdopen
1652 * doesn't seem to close fd. In any event, the documentation
1653 * doesn't specify, so it's safer to close it twice.
1659 /* There may have been a racing condition with some other thread, both
1660 * creating the bitmaps for this volume. If the other thread was faster
1661 * the pointer to bitmap should already be filled and we can free ours.
1663 if (vip->bitmap == NULL) {
1664 vip->bitmap = BitMap;
1665 vip->bitmapOffset = 0;
1667 free((byte *) BitMap);
1668 #endif /* BITMAP_LATER */
1672 GetVolumePath(Error * ec, VolId volumeId, char **partitionp, char **namep)
1674 static char partition[VMAXPATHLEN], name[VMAXPATHLEN];
1675 char path[VMAXPATHLEN];
1677 struct DiskPartition *dp;
1681 (void)afs_snprintf(&name[1], (sizeof name) - 1, VFORMAT, volumeId);
1682 for (dp = DiskPartitionList; dp; dp = dp->next) {
1683 struct afs_stat status;
1684 strcpy(path, VPartitionPath(dp));
1686 if (afs_stat(path, &status) == 0) {
1687 strcpy(partition, dp->name);
1694 *partitionp = *namep = NULL;
1696 *partitionp = partition;
1702 VolumeNumber(char *name)
1706 return atoi(name + 1);
1710 VolumeExternalName(VolumeId volumeId)
1712 static char name[VMAXPATHLEN];
1713 (void)afs_snprintf(name, sizeof name, VFORMAT, volumeId);
1717 #if OPENAFS_VOL_STATS
1718 #define OneDay (86400) /* 24 hours' worth of seconds */
1720 #define OneDay (24*60*60) /* 24 hours */
1721 #endif /* OPENAFS_VOL_STATS */
1723 #define Midnight(date) ((date-TimeZoneCorrection)/OneDay*OneDay+TimeZoneCorrection)
1725 /*------------------------------------------------------------------------
1726 * [export] VAdjustVolumeStatistics
1729 * If we've passed midnight, we need to update all the day use
1730 * statistics as well as zeroing the detailed volume statistics
1731 * (if we are implementing them).
1734 * vp : Pointer to the volume structure describing the lucky
1735 * volume being considered for update.
1741 * Nothing interesting.
1745 *------------------------------------------------------------------------*/
1748 VAdjustVolumeStatistics_r(register Volume * vp)
1750 unsigned int now = FT_ApproxTime();
1752 if (now - V_dayUseDate(vp) > OneDay) {
1755 ndays = (now - V_dayUseDate(vp)) / OneDay;
1756 for (i = 6; i > ndays - 1; i--)
1757 V_weekUse(vp)[i] = V_weekUse(vp)[i - ndays];
1758 for (i = 0; i < ndays - 1 && i < 7; i++)
1759 V_weekUse(vp)[i] = 0;
1761 V_weekUse(vp)[ndays - 1] = V_dayUse(vp);
1763 V_dayUseDate(vp) = Midnight(now);
1765 #if OPENAFS_VOL_STATS
1767 * All we need to do is bzero the entire VOL_STATS_BYTES of
1768 * the detailed volume statistics area.
1770 memset((char *)(V_stat_area(vp)), 0, VOL_STATS_BYTES);
1771 #endif /* OPENAFS_VOL_STATS */
1774 /*It's been more than a day of collection */
1776 * Always return happily.
1779 } /*VAdjustVolumeStatistics */
1782 VAdjustVolumeStatistics(register Volume * vp)
1786 retVal = VAdjustVolumeStatistics_r(vp);
1792 VBumpVolumeUsage_r(register Volume * vp)
1794 unsigned int now = FT_ApproxTime();
1795 if (now - V_dayUseDate(vp) > OneDay)
1796 VAdjustVolumeStatistics_r(vp);
1798 * Save the volume header image to disk after every 128 bumps to dayUse.
1800 if ((V_dayUse(vp)++ & 127) == 0) {
1802 VUpdateVolume_r(&error, vp);
1807 VBumpVolumeUsage(register Volume * vp)
1810 VBumpVolumeUsage_r(vp);
1815 VSetDiskUsage_r(void)
1817 static int FifteenMinuteCounter = 0;
1820 /* NOTE: Don't attempt to access the partitions list until the
1821 * initialization level indicates that all volumes are attached,
1822 * which implies that all partitions are initialized. */
1823 #ifdef AFS_PTHREAD_ENV
1825 #else /* AFS_PTHREAD_ENV */
1827 #endif /* AFS_PTHREAD_ENV */
1830 VResetDiskUsage_r();
1831 if (++FifteenMinuteCounter == 3) {
1832 FifteenMinuteCounter = 0;
1845 /* The number of minutes that a volume hasn't been updated before the
1846 * "Dont salvage" flag in the volume header will be turned on */
1847 #define SALVAGE_INTERVAL (10*60)
1849 static VolumeId *UpdateList; /* Pointer to array of Volume ID's */
1850 static int nUpdatedVolumes; /* Updated with entry in UpdateList, salvage after crash flag on */
1851 static int updateSize; /* number of entries possible */
1852 #define UPDATE_LIST_SIZE 100 /* size increment */
1855 VAddToVolumeUpdateList_r(Error * ec, Volume * vp)
1858 vp->updateTime = FT_ApproxTime();
1859 if (V_dontSalvage(vp) == 0)
1861 V_dontSalvage(vp) = 0;
1862 VSyncVolume_r(ec, vp);
1866 updateSize = UPDATE_LIST_SIZE;
1867 UpdateList = (VolumeId *) malloc(sizeof(VolumeId) * updateSize);
1869 if (nUpdatedVolumes == updateSize) {
1870 updateSize += UPDATE_LIST_SIZE;
1872 (VolumeId *) realloc(UpdateList,
1873 sizeof(VolumeId) * updateSize);
1876 assert(UpdateList != NULL);
1877 UpdateList[nUpdatedVolumes++] = V_id(vp);
1881 VScanUpdateList(void)
1883 register int i, gap;
1884 register Volume *vp;
1886 afs_uint32 now = FT_ApproxTime();
1887 /* Be careful with this code, since it works with interleaved calls to AddToVolumeUpdateList */
1888 for (i = gap = 0; i < nUpdatedVolumes; i++) {
1889 vp = VGetVolume_r(&error, UpdateList[i - gap] = UpdateList[i]);
1892 } else if (vp->nUsers == 1 && now - vp->updateTime > SALVAGE_INTERVAL) {
1893 V_dontSalvage(vp) = DONT_SALVAGE;
1894 VUpdateVolume_r(&error, vp); /* No need to fsync--not critical */
1899 #ifndef AFS_PTHREAD_ENV
1901 #endif /* !AFS_PTHREAD_ENV */
1903 nUpdatedVolumes -= gap;
1906 /***************************************************/
1907 /* Add on routines to manage a volume header cache */
1908 /***************************************************/
1910 static struct volHeader *volumeLRU;
1912 /* Allocate a bunch of headers; string them together */
1914 InitLRU(int howMany)
1916 register struct volHeader *hp;
1917 if (programType != fileServer)
1919 hp = (struct volHeader *)(calloc(howMany, sizeof(struct volHeader)));
1921 ReleaseVolumeHeader(hp++);
1924 /* Get a volume header from the LRU list; update the old one if necessary */
1925 /* Returns 1 if there was already a header, which is removed from the LRU list */
1927 GetVolumeHeader(register Volume * vp)
1930 register struct volHeader *hd;
1932 static int everLogged = 0;
1934 old = (vp->header != NULL); /* old == volume already has a header */
1935 if (programType != fileServer) {
1937 hd = (struct volHeader *)calloc(1, sizeof(*vp->header));
1945 if (volumeLRU == hd)
1946 volumeLRU = hd->next;
1947 assert(hd->back == vp);
1950 /* not currently in use and least recently used */
1951 hd = volumeLRU->prev;
1953 hd = (struct volHeader *)calloc(1, sizeof(*vp->header));
1954 /* make it look like single elt LRU */
1955 hd->prev = hd->next = hd;
1957 Log("****Allocated more volume headers, probably leak****\n");
1962 if (hd->diskstuff.inUse) {
1963 WriteVolumeHeader_r(&error, hd->back);
1964 /* Ignore errors; catch them later */
1966 hd->back->header = 0;
1971 if (hd->next) { /* hd->next != 0 --> in LRU chain (we zero it later) */
1972 hd->prev->next = hd->next; /* pull hd out of LRU list */
1973 hd->next->prev = hd->prev; /* if hd only element, this is noop */
1975 hd->next = hd->prev = 0;
1976 /* if not in LRU chain, next test won't be true */
1977 if (hd == volumeLRU) /* last header item, turn into empty list */
1983 /* Put it at the top of the LRU chain */
1985 ReleaseVolumeHeader(register struct volHeader *hd)
1987 if (programType != fileServer)
1989 if (!hd || hd->next) /* no header, or header already released */
1992 hd->next = hd->prev = hd;
1994 hd->prev = volumeLRU->prev;
1995 hd->next = volumeLRU;
1996 hd->prev->next = hd->next->prev = hd;
2002 FreeVolumeHeader(register Volume * vp)
2004 register struct volHeader *hd = vp->header;
2007 if (programType == fileServer) {
2008 ReleaseVolumeHeader(hd);
2017 /***************************************************/
2018 /* Routines to add volume to hash chain, delete it */
2019 /***************************************************/
2022 AddVolumeToHashTable(register Volume * vp, int hashid)
2024 int hash = VOLUME_HASH(hashid);
2025 vp->hashid = hashid;
2026 vp->hashNext = VolumeHashTable[hash];
2027 VolumeHashTable[hash] = vp;
2028 vp->vnodeHashOffset = VolumeHashOffset_r();
2032 DeleteVolumeFromHashTable(register Volume * vp)
2034 int hash = VOLUME_HASH(vp->hashid);
2035 if (VolumeHashTable[hash] == vp)
2036 VolumeHashTable[hash] = vp->hashNext;
2038 Volume *tvp = VolumeHashTable[hash];
2041 while (tvp->hashNext && tvp->hashNext != vp)
2042 tvp = tvp->hashNext;
2043 if (tvp->hashNext == NULL)
2045 tvp->hashNext = vp->hashNext;
2051 VPrintCacheStats_r(void)
2053 register struct VnodeClassInfo *vcp;
2054 vcp = &VnodeClassInfo[vLarge];
2055 Log("Large vnode cache, %d entries, %d allocs, %d gets (%d reads), %d writes\n", vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
2056 vcp = &VnodeClassInfo[vSmall];
2057 Log("Small vnode cache,%d entries, %d allocs, %d gets (%d reads), %d writes\n", vcp->cacheSize, vcp->allocs, vcp->gets, vcp->reads, vcp->writes);
2058 Log("Volume header cache, %d entries, %d gets, %d replacements\n",
2059 VolumeCacheSize, VolumeGets, VolumeReplacements);
2063 VPrintCacheStats(void)
2066 VPrintCacheStats_r();