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
13 Institution: The Information Technology Center, Carnegie-Mellon University
16 #include <afs/param.h>
17 #include <afsconfig.h>
23 #ifdef AFS_PTHREAD_ENV
25 #else /* AFS_PTHREAD_ENV */
26 #include <afs/assert.h>
27 #endif /* AFS_PTHREAD_ENV */
30 #include <afs/afsint.h>
32 #include <afs/errors.h>
35 #include <afs/afssyscalls.h>
38 #include "partition.h"
40 #if defined(AFS_SGI_ENV)
41 #include "sys/types.h"
53 #include <sys/fcntl.h>
56 #endif /* AFS_NT40_ENV */
60 struct VnodeClassInfo VnodeClassInfo[nVNODECLASSES];
62 private int moveHash();
64 #define BAD_IGET -1000
66 /* There are two separate vnode queue types defined here:
67 * Each hash conflict chain -- is singly linked, with a single head
68 * pointer. New entries are added at the beginning. Old
69 * entries are removed by linear search, which generally
70 * only occurs after a disk read).
71 * LRU chain -- is doubly linked, single head pointer.
72 * Entries are added at the head, reclaimed from the tail,
73 * or removed from anywhere in the queue.
77 /* Vnode hash table. Find hash chain by taking lower bits of
78 * (volume_hash_offset + vnode).
79 * This distributes the root inodes of the volumes over the
80 * hash table entries and also distributes the vnodes of
81 * volumes reasonably fairly. The volume_hash_offset field
82 * for each volume is established as the volume comes on line
83 * by using the VOLUME_HASH_OFFSET macro. This distributes the
84 * volumes fairly among the cache entries, both when servicing
85 * a small number of volumes and when servicing a large number.
88 /* logging stuff for finding bugs */
89 #define THELOGSIZE 5120
90 static afs_int32 theLog[THELOGSIZE];
91 static afs_int32 vnLogPtr=0;
92 VNLog(aop, anparms, av1, av2, av3, av4)
93 afs_int32 aop, anparms;
94 afs_int32 av1, av2, av3,av4; {
95 register afs_int32 temp;
98 /* copy data to array */
103 if (anparms>4) anparms = 4; /* do bounds checking */
105 temp = (aop<<16) | anparms;
106 theLog[vnLogPtr++] = temp;
107 if (vnLogPtr >= THELOGSIZE) vnLogPtr = 0;
108 for(temp=0;temp<anparms;temp++) {
109 theLog[vnLogPtr++] = data[temp];
110 if (vnLogPtr >= THELOGSIZE) vnLogPtr = 0;
114 /* VolumeHashOffset -- returns a new value to be stored in the
115 * volumeHashOffset of a Volume structure. Called when a
116 * volume is initialized. Sets the volumeHashOffset so that
117 * vnode cache entries are distributed reasonably between
118 * volumes (the root vnodes of the volumes will hash to
119 * different values, and spacing is maintained between volumes
120 * when there are not many volumes represented), and spread
121 * equally amongst vnodes within a single volume.
123 int VolumeHashOffset_r() {
124 static int nextVolumeHashOffset = 0;
125 /* hashindex Must be power of two in size */
127 # define hashMask ((1<<hashShift)-1)
128 static byte hashindex[1<<hashShift] = {0,128,64,192,32,160,96,224};
130 offset = hashindex[nextVolumeHashOffset&hashMask]
131 + (nextVolumeHashOffset>>hashShift);
132 nextVolumeHashOffset++;
136 /* Change hashindex (above) if you change this constant */
137 #define VNODE_HASH_TABLE_SIZE 256
138 private Vnode *VnodeHashTable[VNODE_HASH_TABLE_SIZE];
139 #define VNODE_HASH(volumeptr,vnodenumber)\
140 ((volumeptr->vnodeHashOffset + vnodenumber)&(VNODE_HASH_TABLE_SIZE-1))
142 /* Code to invalidate a vnode entry. Called when we've damaged a vnode, and want
143 to prevent future VGetVnode's from applying to it. Leaves it in the same hash bucket
144 but that shouldn't be important. */
145 VInvalidateVnode_r(avnode)
146 register struct Vnode *avnode; {
147 avnode->changed_newTime = 0; /* don't let it get flushed out again */
148 avnode->changed_oldTime = 0;
149 avnode->delete = 0; /* it isn't deleted, erally */
150 avnode->cacheCheck = 0; /* invalid: prevents future vnode searches from working */
153 /* Not normally called by general client; called by volume.c */
154 VInitVnodes(class,nVnodes)
159 register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
161 vcp->allocs = vcp->gets = vcp->reads = vcp->writes = 0;
162 vcp->cacheSize = nVnodes;
165 assert(CHECKSIZE_SMALLVNODE);
167 vcp->residentSize = SIZEOF_SMALLVNODE;
168 vcp->diskSize = SIZEOF_SMALLDISKVNODE;
169 vcp->magic = SMALLVNODEMAGIC;
173 vcp->residentSize = SIZEOF_LARGEVNODE;
174 vcp->diskSize = SIZEOF_LARGEDISKVNODE;
175 vcp->magic = LARGEVNODEMAGIC;
178 { int s = vcp->diskSize-1;
188 va = (byte *) calloc(nVnodes,vcp->residentSize);
191 Vnode *vnp = (Vnode *) va;
192 vnp->nUsers = 0; /* no context switches */
193 Lock_Init(&vnp->lock);
194 vnp->changed_oldTime = 0;
195 vnp->changed_newTime = 0;
196 vnp->volumePtr = NULL;
198 vnp->delete = vnp->vnodeNumber = 0;
199 #ifdef AFS_PTHREAD_ENV
200 vnp->writer = (pthread_t) 0;
201 #else /* AFS_PTHREAD_ENV */
202 vnp->writer = (PROCESS) 0;
203 #endif /* AFS_PTHREAD_ENV */
206 if (vcp->lruHead == NULL)
207 vcp->lruHead = vnp->lruNext = vnp->lruPrev = vnp;
209 vnp->lruNext = vcp->lruHead;
210 vnp->lruPrev = vcp->lruHead->lruPrev;
211 vcp->lruHead->lruPrev = vnp;
212 vnp->lruPrev->lruNext = vnp;
215 va += vcp->residentSize;
220 /* allocate an *unused* vnode from the LRU chain, going backwards of course. It shouldn't
221 be necessary to specify that nUsers == 0 since if it is in the list, nUsers
222 should be 0. Things shouldn't be in lruq unless no one is using them. */
223 Vnode *VGetFreeVnode_r(vcp)
224 struct VnodeClassInfo *vcp; {
227 vnp = vcp->lruHead->lruPrev;
228 if (vnp->nUsers != 0 || CheckLock(&vnp->lock))
229 Abort("locked vnode in lruq");
230 VNLog(1, 2, vnp->vnodeNumber, (afs_int32) vnp);
231 IH_RELEASE(vnp->handle);
236 static mlkLastAlloc = 0;
237 static mlkLastOver = 0;
238 static mlkLastDelete = 0;
240 Vnode *VAllocVnode(ec,vp,type)
247 retVal = VAllocVnode_r(ec, vp, type);
252 Vnode *VAllocVnode_r(ec,vp,type)
259 int newHash, bitNumber;
260 register struct VnodeClassInfo *vcp;
265 if (programType == fileServer && !V_inUse(vp)) {
266 if (vp->specialStatus) {
267 *ec = vp->specialStatus;
273 class = vnodeTypeToClass(type);
274 vcp = &VnodeClassInfo[class];
276 if (!VolumeWriteable(vp)) {
281 unique = vp->nextVnodeUnique++;
283 unique = vp->nextVnodeUnique++;
285 if (vp->nextVnodeUnique > V_uniquifier(vp)) {
286 VUpdateVolume_r(ec,vp);
291 if (programType == fileServer) {
292 VAddToVolumeUpdateList_r(ec, vp);
297 /* Find a slot in the bit map */
298 bitNumber = VAllocBitmapEntry_r(ec,vp,&vp->vnodeIndex[class]);
301 vnodeNumber = bitNumberToVnodeNumber(bitNumber,class);
303 VNLog(2, 1, vnodeNumber);
304 /* Prepare to move it to the new hash chain */
305 newHash = VNODE_HASH(vp, vnodeNumber);
306 for (vnp = VnodeHashTable[newHash];
307 vnp && (vnp->vnodeNumber!=vnodeNumber || vnp->volumePtr!=vp
308 || vnp->volumePtr->cacheCheck!=vnp->cacheCheck);
312 /* slot already exists. May even not be in lruq (consider store file locking a file being deleted)
313 so we may have to wait for it below */
314 VNLog(3, 2, vnodeNumber, (afs_int32) vnp);
316 /* If first user, remove it from the LRU chain. We can assume that
317 there is at least one item in the queue */
318 if (++vnp->nUsers == 1) {
319 if (vnp == vcp->lruHead)
320 vcp->lruHead = vcp->lruHead->lruNext;
321 vnp->lruPrev->lruNext = vnp->lruNext;
322 vnp->lruNext->lruPrev = vnp->lruPrev;
323 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
324 Abort("VGetVnode: lru chain addled!\n");
325 /* This won't block */
326 ObtainWriteLock(&vnp->lock);
328 /* follow locking hierarchy */
330 ObtainWriteLock(&vnp->lock);
333 #ifdef AFS_PTHREAD_ENV
334 vnp->writer = pthread_self();
335 #else /* AFS_PTHREAD_ENV */
336 LWP_CurrentProcess(&vnp->writer);
337 #endif /* AFS_PTHREAD_ENV */
340 vnp = VGetFreeVnode_r(vcp);
341 /* Remove vnode from LRU chain and grab a write lock */
342 if (vnp == vcp->lruHead)
343 vcp->lruHead = vcp->lruHead->lruNext;
344 vnp->lruPrev->lruNext = vnp->lruNext;
345 vnp->lruNext->lruPrev = vnp->lruPrev;
346 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
347 Abort("VGetVnode: lru chain addled!\n");
348 /* Initialize the header fields so noone allocates another
349 vnode with the same number */
350 vnp->vnodeNumber = vnodeNumber;
352 vnp->cacheCheck = vp->cacheCheck;
354 moveHash(vnp, newHash);
355 /* This will never block */
356 ObtainWriteLock(&vnp->lock);
357 #ifdef AFS_PTHREAD_ENV
358 vnp->writer = pthread_self();
359 #else /* AFS_PTHREAD_ENV */
360 LWP_CurrentProcess(&vnp->writer);
361 #endif /* AFS_PTHREAD_ENV */
362 /* Sanity check: is this vnode really not in use? */
365 IHandle_t *ihP = vp->vnodeIndex[class].handle;
367 off_t off = vnodeIndexOffset(vcp, vnodeNumber);
372 Abort("VAllocVnode: can't open index file!\n");
373 if ((size = FDH_SIZE(fdP)) < 0)
374 Abort("VAllocVnode: can't stat index file!\n");
375 if (FDH_SEEK(fdP, off, SEEK_SET) < 0)
376 Abort("VAllocVnode: can't seek on index file!\n");
378 if (FDH_READ(fdP, &vnp->disk, vcp->diskSize) == vcp->diskSize) {
379 if (vnp->disk.type != vNull)
380 Abort("VAllocVnode: addled bitmap or index!\n");
383 /* growing file - grow in a reasonable increment */
384 char *buf = (char *)malloc(16*1024);
386 FDH_WRITE(fdP, buf, 16*1024);
392 VNLog(4, 2, vnodeNumber, (afs_int32) vnp);
395 VNLog(5, 1, (afs_int32) vnp);
396 #ifdef AFS_PTHREAD_ENV
397 vnp->writer = pthread_self();
398 #else /* AFS_PTHREAD_ENV */
399 LWP_CurrentProcess(&vnp->writer);
400 #endif /* AFS_PTHREAD_ENV */
401 bzero(&vnp->disk, sizeof(vnp->disk));
402 vnp->changed_newTime = 0; /* set this bit when vnode is updated */
403 vnp->changed_oldTime = 0; /* set this on CopyOnWrite. */
405 vnp->disk.vnodeMagic = vcp->magic;
406 vnp->disk.type = type;
407 vnp->disk.uniquifier = unique;
413 Vnode *VGetVnode(ec,vp,vnodeNumber,locktype)
417 int locktype; /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
421 retVal = VGetVnode_r(ec, vp, vnodeNumber, locktype);
426 Vnode *VGetVnode_r(ec,vp,vnodeNumber,locktype)
430 int locktype; /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
435 struct VnodeClassInfo *vcp;
438 mlkReason = 0; /* last call didn't fail */
440 if (vnodeNumber == 0) {
446 VNLog(100, 1, vnodeNumber);
447 if (programType == fileServer && !V_inUse(vp)) {
448 *ec = (vp->specialStatus ? vp->specialStatus : VOFFLINE);
450 /* If the volume is VBUSY (being cloned or dumped) and this is
451 * a READ operation, then don't fail.
453 if ((*ec != VBUSY) || (locktype != READ_LOCK)) {
459 class = vnodeIdToClass(vnodeNumber);
460 vcp = &VnodeClassInfo[class];
461 if (locktype == WRITE_LOCK && !VolumeWriteable(vp)) {
467 if (locktype == WRITE_LOCK && programType == fileServer) {
468 VAddToVolumeUpdateList_r(ec, vp);
470 mlkReason = 1000 + *ec;
475 /* See whether the vnode is in the cache. */
476 newHash = VNODE_HASH(vp, vnodeNumber);
477 for (vnp = VnodeHashTable[newHash];
478 vnp && (vnp->vnodeNumber!=vnodeNumber || vnp->volumePtr!=vp
479 || vnp->volumePtr->cacheCheck!=vnp->cacheCheck);
485 IHandle_t *ihP = vp->vnodeIndex[class].handle;
487 /* Not in cache; tentatively grab most distantly used one from the LRU
490 vnp = VGetFreeVnode_r(vcp);
491 /* Remove it from the old hash chain */
492 moveHash(vnp, newHash);
493 /* Remove it from the LRU chain */
494 if (vnp == vcp->lruHead)
495 vcp->lruHead = vcp->lruHead->lruNext;
496 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
497 Abort("VGetVnode: lru chain addled!\n");
498 vnp->lruPrev->lruNext = vnp->lruNext;
499 vnp->lruNext->lruPrev = vnp->lruPrev;
501 vnp->changed_newTime = vnp->changed_oldTime = 0;
503 vnp->vnodeNumber = vnodeNumber;
505 vnp->cacheCheck = vp->cacheCheck;
508 /* This will never block */
509 ObtainWriteLock(&vnp->lock);
510 #ifdef AFS_PTHREAD_ENV
511 vnp->writer = pthread_self();
512 #else /* AFS_PTHREAD_ENV */
513 LWP_CurrentProcess(&vnp->writer);
514 #endif /* AFS_PTHREAD_ENV */
516 /* Read vnode from volume index */
520 Log("VGetVnode: can't open index dev=%d, i=%s\n",
521 vp->device, PrintInode(NULL,
522 vp->vnodeIndex[class].handle->ih_ino));
526 else if (FDH_SEEK(fdP, vnodeIndexOffset(vcp, vnodeNumber),
528 Log ("VGetVnode: can't seek on index file vn=%d\n",vnodeNumber);
531 FDH_REALLYCLOSE(fdP);
533 else if ((n = FDH_READ(fdP, (char*)&vnp->disk, vcp->diskSize))
535 /* Don't take volume off line if the inumber is out of range
536 or the inode table is full. */
537 FDH_REALLYCLOSE(fdP);
540 Log("VGetVnode: bad inumber %s\n",
541 PrintInode(NULL, vp->vnodeIndex[class].handle->ih_ino));
545 /* Check for disk errors. Anything else just means that the vnode
547 if (n == -1 && errno == EIO) {
548 Log("VGetVnode: Couldn't read vnode %d, volume %u (%s); volume needs salvage\n",
549 vnodeNumber, V_id(vp), V_name(vp));
557 VInvalidateVnode_r(vnp);
558 if (vnp->nUsers-- == 1)
559 StickOnLruChain_r(vnp,vcp);
560 ReleaseWriteLock(&vnp->lock);
565 /* Quick check to see that the data is reasonable */
566 if (vnp->disk.vnodeMagic != vcp->magic || vnp->disk.type == vNull) {
567 if (vnp->disk.type == vNull) {
570 VInvalidateVnode_r(vnp);
571 if (vnp->nUsers-- == 1)
572 StickOnLruChain_r(vnp,vcp);
573 ReleaseWriteLock(&vnp->lock);
574 return NULL; /* The vnode is not allocated */
577 struct vnodeIndex *index = &vp->vnodeIndex[class];
578 int bitNumber = vnodeIdToBitNumber(vnodeNumber);
579 int offset = bitNumber >> 3;
581 /* Test to see if vnode number is valid. */
582 if ((offset >= index->bitmapSize) ||
583 ((*(index->bitmap+offset) & (1<<(bitNumber&0x7))) == 0)) {
584 Log("VGetVnode: Request for unallocated vnode %u, volume %u (%s) denied.\n",
585 vnodeNumber, V_id(vp), V_name(vp));
590 Log("VGetVnode: Bad magic number, vnode %d, volume %u (%s); volume needs salvage\n",
591 vnodeNumber, V_id(vp), V_name(vp));
592 vp->goingOffline = 1; /* used to call VOffline, but that would mess
593 up the volume ref count if called here */
597 VInvalidateVnode_r(vnp);
598 if (vnp->nUsers-- == 1)
599 StickOnLruChain_r(vnp,vcp);
600 ReleaseWriteLock(&vnp->lock);
604 IH_INIT(vnp->handle, V_device(vp), V_parentId(vp), VN_GET_INO(vnp));
605 ReleaseWriteLock(&vnp->lock);
607 VNLog(101, 2, vnodeNumber, (afs_int32) vnp);
608 if (++vnp->nUsers == 1) {
609 /* First user. Remove it from the LRU chain. We can assume that
610 there is at least one item in the queue */
611 if (vnp == vcp->lruHead)
612 vcp->lruHead = vcp->lruHead->lruNext;
613 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
614 Abort("VGetVnode: lru chain addled!\n");
615 vnp->lruPrev->lruNext = vnp->lruNext;
616 vnp->lruNext->lruPrev = vnp->lruPrev;
620 if (locktype == READ_LOCK)
621 ObtainReadLock(&vnp->lock);
623 ObtainWriteLock(&vnp->lock);
624 #ifdef AFS_PTHREAD_ENV
625 vnp->writer = pthread_self();
626 #else /* AFS_PTHREAD_ENV */
627 LWP_CurrentProcess(&vnp->writer);
628 #endif /* AFS_PTHREAD_ENV */
631 /* Check that the vnode hasn't been removed while we were obtaining
633 VNLog(102, 2, vnodeNumber, (afs_int32) vnp);
634 if (vnp->disk.type == vNull) {
635 if (vnp->nUsers-- == 1)
636 StickOnLruChain_r(vnp,vcp);
637 if (locktype == READ_LOCK)
638 ReleaseReadLock(&vnp->lock);
640 ReleaseWriteLock(&vnp->lock);
643 /* vnode is labelled correctly by now, so we don't have to invalidate it */
646 if (programType == fileServer)
647 VBumpVolumeUsage_r(vnp->volumePtr);/* Hack; don't know where it should be
648 called from. Maybe VGetVolume */
653 int TrustVnodeCacheEntry = 1;
654 /* This variable is bogus--when it's set to 0, the hash chains fill
655 up with multiple versions of the same vnode. Should fix this!! */
670 int writeLocked, offset;
672 struct VnodeClassInfo *vcp;
676 assert (vnp->nUsers != 0);
677 class = vnodeIdToClass(vnp->vnodeNumber);
678 vcp = &VnodeClassInfo[class];
679 assert(vnp->disk.vnodeMagic == vcp->magic);
680 VNLog(200, 2, vnp->vnodeNumber, (afs_int32) vnp);
682 writeLocked = WriteLocked(&vnp->lock);
684 #ifdef AFS_PTHREAD_ENV
685 pthread_t thisProcess = pthread_self();
686 #else /* AFS_PTHREAD_ENV */
688 LWP_CurrentProcess(&thisProcess);
689 #endif /* AFS_PTHREAD_ENV */
690 VNLog(201, 2, (afs_int32) vnp,
691 ((vnp->changed_newTime) << 1) | ((vnp->changed_oldTime) << 1) | vnp->delete);
692 if (thisProcess != vnp->writer)
693 Abort("VPutVnode: Vnode at 0x%x locked by another process!\n",vnp);
694 if (vnp->changed_oldTime || vnp->changed_newTime || vnp->delete) {
695 Volume *vp = vnp->volumePtr;
696 afs_int32 now = FT_ApproxTime();
697 assert(vnp->cacheCheck == vp->cacheCheck);
700 /* No longer any directory entries for this vnode. Free the Vnode */
701 bzero(&vnp->disk, sizeof (vnp->disk));
702 mlkLastDelete = vnp->vnodeNumber;
703 /* delete flag turned off further down */
704 VNLog(202, 2, vnp->vnodeNumber, (afs_int32) vnp);
705 } else if (vnp->changed_newTime) {
706 vnp->disk.serverModifyTime = now;
708 if (vnp->changed_newTime)
709 V_updateDate(vp) = vp->updateTime = now;
711 /* The vnode has been changed. Write it out to disk */
713 assert(V_needsSalvaged(vp));
716 IHandle_t *ihP = vp->vnodeIndex[class].handle;
721 Abort("VPutVnode: can't open index file!\n");
722 offset = vnodeIndexOffset(vcp, vnp->vnodeNumber);
723 if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
724 Abort("VPutVnode: can't seek on index file! fdp=0x%x offset=%d, errno=%d\n",
727 code = FDH_WRITE(fdP, &vnp->disk, vcp->diskSize);
728 if (code != vcp->diskSize) {
729 /* Don't force volume offline if the inumber is out of
730 * range or the inode table is full.
733 if (code == BAD_IGET) {
734 Log("VPutVnode: bad inumber %s\n",
735 PrintInode(NULL, vp->vnodeIndex[class].handle->ih_ino));
738 Log("VPutVnode: Couldn't write vnode %d, volume %u (%s)\n",
739 vnp->vnodeNumber, V_id(vnp->volumePtr),
740 V_name(vnp->volumePtr));
745 FDH_REALLYCLOSE(fdP);
751 /* If the vnode is to be deleted, and we wrote the vnode out,
752 * free its bitmap entry. Do after the vnode is written so we
753 * don't allocate from bitmap before the vnode is written
754 * (doing so could cause a "addled bitmap" message).
756 if (vnp->delete && !*ec) {
757 VFreeBitMapEntry_r(ec, &vp->vnodeIndex[class],
758 vnodeIdToBitNumber(vnp->vnodeNumber));
762 vnp->changed_newTime = vnp->changed_oldTime = 0;
764 } else { /* Not write locked */
765 if (vnp->changed_newTime || vnp->changed_oldTime || vnp->delete)
766 Abort("VPutVnode: Change or delete flag for vnode 0x%x is set but vnode is not write locked!\n", vnp);
769 /* Do not look at disk portion of vnode after this point; it may
770 have been deleted above */
771 if (vnp->nUsers-- == 1)
772 StickOnLruChain_r(vnp,vcp);
776 ReleaseWriteLock(&vnp->lock);
778 ReleaseReadLock(&vnp->lock);
782 * Make an attempt to convert a vnode lock from write to read.
783 * Do nothing if the vnode isn't write locked or the vnode has
786 int VVnodeWriteToRead(ec,vnp)
792 retVal = VVnodeWriteToRead_r(ec, vnp);
797 int VVnodeWriteToRead_r(ec,vnp)
803 struct VnodeClassInfo *vcp;
805 #ifdef AFS_PTHREAD_ENV
806 pthread_t thisProcess;
807 #else /* AFS_PTHREAD_ENV */
809 #endif /* AFS_PTHREAD_ENV */
812 assert (vnp->nUsers != 0);
813 class = vnodeIdToClass(vnp->vnodeNumber);
814 vcp = &VnodeClassInfo[class];
815 assert(vnp->disk.vnodeMagic == vcp->magic);
816 writeLocked = WriteLocked(&vnp->lock);
817 VNLog(300, 2, vnp->vnodeNumber, (afs_int32) vnp);
823 #ifdef AFS_PTHREAD_ENV
824 thisProcess = pthread_self();
825 #else /* AFS_PTHREAD_ENV */
826 LWP_CurrentProcess(&thisProcess);
827 #endif /* AFS_PTHREAD_ENV */
829 VNLog(301, 2, (afs_int32) vnp,
830 ((vnp->changed_newTime) << 1) | ((vnp->changed_oldTime) << 1) |
832 if (thisProcess != vnp->writer)
833 Abort("VPutVnode: Vnode at 0x%x locked by another process!\n",vnp);
837 if (vnp->changed_oldTime || vnp->changed_newTime) {
838 Volume *vp = vnp->volumePtr;
839 afs_int32 now = FT_ApproxTime();
840 assert(vnp->cacheCheck == vp->cacheCheck);
841 if (vnp->changed_newTime)
842 vnp->disk.serverModifyTime = now;
843 if (vnp->changed_newTime)
844 V_updateDate(vp) = vp->updateTime = now;
846 /* The inode has been changed. Write it out to disk */
848 assert(V_needsSalvaged(vp));
851 IHandle_t *ihP = vp->vnodeIndex[class].handle;
853 off_t off = vnodeIndexOffset(vcp, vnp->vnodeNumber);
857 Abort("VPutVnode: can't open index file!\n");
858 code = FDH_SEEK(fdP, off, SEEK_SET);
860 Abort("VPutVnode: can't seek on index file!\n");
861 code = FDH_WRITE(fdP, &vnp->disk, vcp->diskSize);
862 if (code != vcp->diskSize) {
864 * Don't force volume offline if the inumber is out of
865 * range or the inode table is full.
870 Log("VPutVnode: bad inumber %d\n",
871 vp->vnodeIndex[class].handle->ih_ino);
874 Log("VPutVnode: Couldn't write vnode %d, volume %u (%s)\n",
875 vnp->vnodeNumber, V_id(vnp->volumePtr),
876 V_name(vnp->volumePtr));
886 vnp->changed_newTime = vnp->changed_oldTime = 0;
889 ConvertWriteToReadLock(&vnp->lock);
893 /* Move the vnode, vnp, to the new hash table given by the
894 hash table index, newHash */
895 static int moveHash(vnp, newHash)
900 /* Remove it from the old hash chain */
901 tvnp = VnodeHashTable[vnp->hashIndex];
903 VnodeHashTable[vnp->hashIndex] = vnp->hashNext;
905 while (tvnp && tvnp->hashNext != vnp)
906 tvnp = tvnp->hashNext;
908 tvnp->hashNext = vnp->hashNext;
910 /* Add it to the new hash chain */
911 vnp->hashNext = VnodeHashTable[newHash];
912 VnodeHashTable[newHash] = vnp;
913 vnp->hashIndex = newHash;
916 StickOnLruChain_r(vnp,vcp)
918 register struct VnodeClassInfo *vcp;
920 /* Add it to the circular LRU list */
921 if (vcp->lruHead == NULL)
922 Abort("VPutVnode: vcp->lruHead==NULL");
924 vnp->lruNext = vcp->lruHead;
925 vnp->lruPrev = vcp->lruHead->lruPrev;
926 vcp->lruHead->lruPrev = vnp;
927 vnp->lruPrev->lruNext = vnp;
930 /* If the vnode was just deleted, put it at the end of the chain so it
931 will be reused immediately */
933 vcp->lruHead = vnp->lruNext;
934 /* If caching is turned off, set volumeptr to NULL to invalidate the
936 if (!TrustVnodeCacheEntry)
937 vnp->volumePtr = NULL;
940 /* VCloseVnodeFiles - called when a volume is going off line. All open
941 * files for vnodes in that volume are closed. This might be excessive,
942 * since we may only be taking one volume of a volume group offline.
944 void VCloseVnodeFiles_r(Volume *vp)
949 for (i=0; i<VNODE_HASH_TABLE_SIZE; i++) {
950 for (vnp = VnodeHashTable[i]; vnp; vnp = vnp->hashNext) {
951 if (vnp->volumePtr == vp) {
952 IH_REALLYCLOSE(vnp->handle);
958 /* VReleaseVnodeFiles - called when a volume is going detached. All open
959 * files for vnodes in that volume are closed and all inode handles
960 * for vnodes in that volume are released.
962 void VReleaseVnodeFiles_r(Volume *vp)
967 for (i=0; i<VNODE_HASH_TABLE_SIZE; i++) {
968 for (vnp = VnodeHashTable[i]; vnp; vnp = vnp->hashNext) {
969 if (vnp->volumePtr == vp) {
970 IH_RELEASE(vnp->handle);