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 <afsconfig.h>
17 #include <afs/param.h>
31 #ifdef AFS_PTHREAD_ENV
33 #else /* AFS_PTHREAD_ENV */
34 #include <afs/assert.h>
35 #endif /* AFS_PTHREAD_ENV */
38 #include <afs/afsint.h>
40 #include <afs/errors.h>
43 #include <afs/afssyscalls.h>
47 #include "partition.h"
48 #if defined(AFS_SGI_ENV)
49 #include "sys/types.h"
61 #include <sys/fcntl.h>
64 #endif /* AFS_NT40_ENV */
67 /*@printflike@*/ extern void Log(const char *format, ...);
69 /*@printflike@*/ extern void Abort(const char *format, ...);
72 struct VnodeClassInfo VnodeClassInfo[nVNODECLASSES];
74 private int moveHash(register Vnode * vnp, bit32 newHash);
75 void StickOnLruChain_r(register Vnode * vnp,
76 register struct VnodeClassInfo *vcp);
78 #define BAD_IGET -1000
80 /* There are two separate vnode queue types defined here:
81 * Each hash conflict chain -- is singly linked, with a single head
82 * pointer. New entries are added at the beginning. Old
83 * entries are removed by linear search, which generally
84 * only occurs after a disk read).
85 * LRU chain -- is doubly linked, single head pointer.
86 * Entries are added at the head, reclaimed from the tail,
87 * or removed from anywhere in the queue.
91 /* Vnode hash table. Find hash chain by taking lower bits of
92 * (volume_hash_offset + vnode).
93 * This distributes the root inodes of the volumes over the
94 * hash table entries and also distributes the vnodes of
95 * volumes reasonably fairly. The volume_hash_offset field
96 * for each volume is established as the volume comes on line
97 * by using the VOLUME_HASH_OFFSET macro. This distributes the
98 * volumes fairly among the cache entries, both when servicing
99 * a small number of volumes and when servicing a large number.
102 /* logging stuff for finding bugs */
103 #define THELOGSIZE 5120
104 static afs_int32 theLog[THELOGSIZE];
105 static afs_int32 vnLogPtr = 0;
107 VNLog(aop, anparms, av1, av2, av3, av4)
108 afs_int32 aop, anparms;
109 afs_int32 av1, av2, av3, av4;
111 register afs_int32 temp;
114 /* copy data to array */
120 anparms = 4; /* do bounds checking */
122 temp = (aop << 16) | anparms;
123 theLog[vnLogPtr++] = temp;
124 if (vnLogPtr >= THELOGSIZE)
126 for (temp = 0; temp < anparms; temp++) {
127 theLog[vnLogPtr++] = data[temp];
128 if (vnLogPtr >= THELOGSIZE)
133 /* VolumeHashOffset -- returns a new value to be stored in the
134 * volumeHashOffset of a Volume structure. Called when a
135 * volume is initialized. Sets the volumeHashOffset so that
136 * vnode cache entries are distributed reasonably between
137 * volumes (the root vnodes of the volumes will hash to
138 * different values, and spacing is maintained between volumes
139 * when there are not many volumes represented), and spread
140 * equally amongst vnodes within a single volume.
143 VolumeHashOffset_r(void)
145 static int nextVolumeHashOffset = 0;
146 /* hashindex Must be power of two in size */
148 # define hashMask ((1<<hashShift)-1)
149 static byte hashindex[1 << hashShift] =
150 { 0, 128, 64, 192, 32, 160, 96, 224 };
152 offset = hashindex[nextVolumeHashOffset & hashMask]
153 + (nextVolumeHashOffset >> hashShift);
154 nextVolumeHashOffset++;
158 /* Change hashindex (above) if you change this constant */
159 #define VNODE_HASH_TABLE_SIZE 256
160 private Vnode *VnodeHashTable[VNODE_HASH_TABLE_SIZE];
161 #define VNODE_HASH(volumeptr,vnodenumber)\
162 ((volumeptr->vnodeHashOffset + vnodenumber)&(VNODE_HASH_TABLE_SIZE-1))
164 /* Code to invalidate a vnode entry. Called when we've damaged a vnode, and want
165 to prevent future VGetVnode's from applying to it. Leaves it in the same hash bucket
166 but that shouldn't be important. */
168 VInvalidateVnode_r(register struct Vnode *avnode)
170 avnode->changed_newTime = 0; /* don't let it get flushed out again */
171 avnode->changed_oldTime = 0;
172 avnode->delete = 0; /* it isn't deleted, erally */
173 avnode->cacheCheck = 0; /* invalid: prevents future vnode searches from working */
176 /* Not normally called by general client; called by volume.c */
178 VInitVnodes(VnodeClass class, int nVnodes)
181 register struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
183 vcp->allocs = vcp->gets = vcp->reads = vcp->writes = 0;
184 vcp->cacheSize = nVnodes;
187 assert(CHECKSIZE_SMALLVNODE);
189 vcp->residentSize = SIZEOF_SMALLVNODE;
190 vcp->diskSize = SIZEOF_SMALLDISKVNODE;
191 vcp->magic = SMALLVNODEMAGIC;
195 vcp->residentSize = SIZEOF_LARGEVNODE;
196 vcp->diskSize = SIZEOF_LARGEDISKVNODE;
197 vcp->magic = LARGEVNODEMAGIC;
201 int s = vcp->diskSize - 1;
211 va = (byte *) calloc(nVnodes, vcp->residentSize);
214 Vnode *vnp = (Vnode *) va;
215 vnp->nUsers = 0; /* no context switches */
216 Lock_Init(&vnp->lock);
217 vnp->changed_oldTime = 0;
218 vnp->changed_newTime = 0;
219 vnp->volumePtr = NULL;
221 vnp->delete = vnp->vnodeNumber = 0;
222 #ifdef AFS_PTHREAD_ENV
223 vnp->writer = (pthread_t) 0;
224 #else /* AFS_PTHREAD_ENV */
225 vnp->writer = (PROCESS) 0;
226 #endif /* AFS_PTHREAD_ENV */
229 if (vcp->lruHead == NULL)
230 vcp->lruHead = vnp->lruNext = vnp->lruPrev = vnp;
232 vnp->lruNext = vcp->lruHead;
233 vnp->lruPrev = vcp->lruHead->lruPrev;
234 vcp->lruHead->lruPrev = vnp;
235 vnp->lruPrev->lruNext = vnp;
238 va += vcp->residentSize;
244 /* allocate an *unused* vnode from the LRU chain, going backwards of course. It shouldn't
245 be necessary to specify that nUsers == 0 since if it is in the list, nUsers
246 should be 0. Things shouldn't be in lruq unless no one is using them. */
248 VGetFreeVnode_r(struct VnodeClassInfo * vcp)
252 vnp = vcp->lruHead->lruPrev;
253 if (vnp->nUsers != 0 || CheckLock(&vnp->lock))
254 Abort("locked vnode in lruq");
255 VNLog(1, 2, vnp->vnodeNumber, (afs_int32) vnp);
256 IH_RELEASE(vnp->handle);
260 static mlkReason = 0;
261 static mlkLastAlloc = 0;
262 static mlkLastOver = 0;
263 static mlkLastDelete = 0;
266 VAllocVnode(Error * ec, Volume * vp, VnodeType type)
270 retVal = VAllocVnode_r(ec, vp, type);
276 VAllocVnode_r(Error * ec, Volume * vp, VnodeType type)
280 int newHash, bitNumber;
281 register struct VnodeClassInfo *vcp;
286 if (programType == fileServer && !V_inUse(vp)) {
287 if (vp->specialStatus) {
288 *ec = vp->specialStatus;
294 class = vnodeTypeToClass(type);
295 vcp = &VnodeClassInfo[class];
297 if (!VolumeWriteable(vp)) {
298 *ec = (bit32) VREADONLY;
302 unique = vp->nextVnodeUnique++;
304 unique = vp->nextVnodeUnique++;
306 if (vp->nextVnodeUnique > V_uniquifier(vp)) {
307 VUpdateVolume_r(ec, vp);
312 if (programType == fileServer) {
313 VAddToVolumeUpdateList_r(ec, vp);
318 /* Find a slot in the bit map */
319 bitNumber = VAllocBitmapEntry_r(ec, vp, &vp->vnodeIndex[class]);
322 vnodeNumber = bitNumberToVnodeNumber(bitNumber, class);
324 VNLog(2, 1, vnodeNumber);
325 /* Prepare to move it to the new hash chain */
326 newHash = VNODE_HASH(vp, vnodeNumber);
327 for (vnp = VnodeHashTable[newHash];
328 vnp && (vnp->vnodeNumber != vnodeNumber || vnp->volumePtr != vp
329 || vnp->volumePtr->cacheCheck != vnp->cacheCheck);
330 vnp = vnp->hashNext);
332 /* slot already exists. May even not be in lruq (consider store file locking a file being deleted)
333 * so we may have to wait for it below */
334 VNLog(3, 2, vnodeNumber, (afs_int32) vnp);
336 /* If first user, remove it from the LRU chain. We can assume that
337 * there is at least one item in the queue */
338 if (++vnp->nUsers == 1) {
339 if (vnp == vcp->lruHead)
340 vcp->lruHead = vcp->lruHead->lruNext;
341 vnp->lruPrev->lruNext = vnp->lruNext;
342 vnp->lruNext->lruPrev = vnp->lruPrev;
343 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
344 Abort("VGetVnode: lru chain addled!\n");
345 /* This won't block */
346 ObtainWriteLock(&vnp->lock);
348 /* follow locking hierarchy */
350 ObtainWriteLock(&vnp->lock);
353 #ifdef AFS_PTHREAD_ENV
354 vnp->writer = pthread_self();
355 #else /* AFS_PTHREAD_ENV */
356 LWP_CurrentProcess(&vnp->writer);
357 #endif /* AFS_PTHREAD_ENV */
359 vnp = VGetFreeVnode_r(vcp);
360 /* Remove vnode from LRU chain and grab a write lock */
361 if (vnp == vcp->lruHead)
362 vcp->lruHead = vcp->lruHead->lruNext;
363 vnp->lruPrev->lruNext = vnp->lruNext;
364 vnp->lruNext->lruPrev = vnp->lruPrev;
365 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
366 Abort("VGetVnode: lru chain addled!\n");
367 /* Initialize the header fields so noone allocates another
368 * vnode with the same number */
369 vnp->vnodeNumber = vnodeNumber;
371 vnp->cacheCheck = vp->cacheCheck;
373 moveHash(vnp, newHash);
374 /* This will never block */
375 ObtainWriteLock(&vnp->lock);
376 #ifdef AFS_PTHREAD_ENV
377 vnp->writer = pthread_self();
378 #else /* AFS_PTHREAD_ENV */
379 LWP_CurrentProcess(&vnp->writer);
380 #endif /* AFS_PTHREAD_ENV */
381 /* Sanity check: is this vnode really not in use? */
384 IHandle_t *ihP = vp->vnodeIndex[class].handle;
386 off_t off = vnodeIndexOffset(vcp, vnodeNumber);
391 Abort("VAllocVnode: can't open index file!\n");
392 if ((size = FDH_SIZE(fdP)) < 0)
393 Abort("VAllocVnode: can't stat index file!\n");
394 if (FDH_SEEK(fdP, off, SEEK_SET) < 0)
395 Abort("VAllocVnode: can't seek on index file!\n");
397 if (FDH_READ(fdP, &vnp->disk, vcp->diskSize) == vcp->diskSize) {
398 if (vnp->disk.type != vNull)
399 Abort("VAllocVnode: addled bitmap or index!\n");
402 /* growing file - grow in a reasonable increment */
403 char *buf = (char *)malloc(16 * 1024);
405 Abort("VAllocVnode: malloc failed\n");
406 memset(buf, 0, 16 * 1024);
407 (void)FDH_WRITE(fdP, buf, 16 * 1024);
413 VNLog(4, 2, vnodeNumber, (afs_int32) vnp);
416 VNLog(5, 1, (afs_int32) vnp);
417 #ifdef AFS_PTHREAD_ENV
418 vnp->writer = pthread_self();
419 #else /* AFS_PTHREAD_ENV */
420 LWP_CurrentProcess(&vnp->writer);
421 #endif /* AFS_PTHREAD_ENV */
422 memset(&vnp->disk, 0, sizeof(vnp->disk));
423 vnp->changed_newTime = 0; /* set this bit when vnode is updated */
424 vnp->changed_oldTime = 0; /* set this on CopyOnWrite. */
426 vnp->disk.vnodeMagic = vcp->magic;
427 vnp->disk.type = type;
428 vnp->disk.uniquifier = unique;
431 vp->header->diskstuff.filecount++;
436 VGetVnode(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
437 { /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
440 retVal = VGetVnode_r(ec, vp, vnodeNumber, locktype);
446 VGetVnode_r(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
447 { /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
451 struct VnodeClassInfo *vcp;
454 mlkReason = 0; /* last call didn't fail */
456 if (vnodeNumber == 0) {
462 VNLog(100, 1, vnodeNumber);
463 if (programType == fileServer && !V_inUse(vp)) {
464 *ec = (vp->specialStatus ? vp->specialStatus : VOFFLINE);
466 /* If the volume is VBUSY (being cloned or dumped) and this is
467 * a READ operation, then don't fail.
469 if ((*ec != VBUSY) || (locktype != READ_LOCK)) {
475 class = vnodeIdToClass(vnodeNumber);
476 vcp = &VnodeClassInfo[class];
477 if (locktype == WRITE_LOCK && !VolumeWriteable(vp)) {
478 *ec = (bit32) VREADONLY;
483 if (locktype == WRITE_LOCK && programType == fileServer) {
484 VAddToVolumeUpdateList_r(ec, vp);
486 mlkReason = 1000 + *ec;
491 /* See whether the vnode is in the cache. */
492 newHash = VNODE_HASH(vp, vnodeNumber);
493 for (vnp = VnodeHashTable[newHash];
494 vnp && (vnp->vnodeNumber != vnodeNumber || vnp->volumePtr != vp
495 || vnp->volumePtr->cacheCheck != vnp->cacheCheck);
496 vnp = vnp->hashNext);
500 IHandle_t *ihP = vp->vnodeIndex[class].handle;
502 /* Not in cache; tentatively grab most distantly used one from the LRU
505 vnp = VGetFreeVnode_r(vcp);
506 /* Remove it from the old hash chain */
507 moveHash(vnp, newHash);
508 /* Remove it from the LRU chain */
509 if (vnp == vcp->lruHead)
510 vcp->lruHead = vcp->lruHead->lruNext;
511 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
512 Abort("VGetVnode: lru chain addled!\n");
513 vnp->lruPrev->lruNext = vnp->lruNext;
514 vnp->lruNext->lruPrev = vnp->lruPrev;
516 vnp->changed_newTime = vnp->changed_oldTime = 0;
518 vnp->vnodeNumber = vnodeNumber;
520 vnp->cacheCheck = vp->cacheCheck;
523 /* This will never block */
524 ObtainWriteLock(&vnp->lock);
525 #ifdef AFS_PTHREAD_ENV
526 vnp->writer = pthread_self();
527 #else /* AFS_PTHREAD_ENV */
528 LWP_CurrentProcess(&vnp->writer);
529 #endif /* AFS_PTHREAD_ENV */
531 /* Read vnode from volume index */
535 Log("VGetVnode: can't open index dev=%u, i=%s\n", vp->device,
536 PrintInode(NULL, vp->vnodeIndex[class].handle->ih_ino));
539 } else if (FDH_SEEK(fdP, vnodeIndexOffset(vcp, vnodeNumber), SEEK_SET)
541 Log("VGetVnode: can't seek on index file vn=%u\n", vnodeNumber);
544 FDH_REALLYCLOSE(fdP);
545 } else if ((n = FDH_READ(fdP, (char *)&vnp->disk, vcp->diskSize))
547 /* Don't take volume off line if the inumber is out of range
548 * or the inode table is full. */
549 FDH_REALLYCLOSE(fdP);
552 Log("VGetVnode: bad inumber %s\n",
553 PrintInode(NULL, vp->vnodeIndex[class].handle->ih_ino));
557 /* Check for disk errors. Anything else just means that the vnode
558 * is not allocated */
559 if (n == -1 && errno == EIO) {
560 Log("VGetVnode: Couldn't read vnode %u, volume %u (%s); volume needs salvage\n", vnodeNumber, V_id(vp), V_name(vp));
568 VInvalidateVnode_r(vnp);
569 if (vnp->nUsers-- == 1)
570 StickOnLruChain_r(vnp, vcp);
571 ReleaseWriteLock(&vnp->lock);
576 /* Quick check to see that the data is reasonable */
577 if (vnp->disk.vnodeMagic != vcp->magic || vnp->disk.type == vNull) {
578 if (vnp->disk.type == vNull) {
581 VInvalidateVnode_r(vnp);
582 if (vnp->nUsers-- == 1)
583 StickOnLruChain_r(vnp, vcp);
584 ReleaseWriteLock(&vnp->lock);
585 return NULL; /* The vnode is not allocated */
587 struct vnodeIndex *index = &vp->vnodeIndex[class];
588 unsigned int bitNumber = vnodeIdToBitNumber(vnodeNumber);
589 unsigned int offset = bitNumber >> 3;
591 /* Test to see if vnode number is valid. */
592 if ((offset >= index->bitmapSize)
593 || ((*(index->bitmap + offset) & (1 << (bitNumber & 0x7)))
595 Log("VGetVnode: Request for unallocated vnode %u, volume %u (%s) denied.\n", vnodeNumber, V_id(vp), V_name(vp));
599 Log("VGetVnode: Bad magic number, vnode %u, volume %u (%s); volume needs salvage\n", vnodeNumber, V_id(vp), V_name(vp));
600 vp->goingOffline = 1; /* used to call VOffline, but that would mess
601 * up the volume ref count if called here */
605 VInvalidateVnode_r(vnp);
606 if (vnp->nUsers-- == 1)
607 StickOnLruChain_r(vnp, vcp);
608 ReleaseWriteLock(&vnp->lock);
612 IH_INIT(vnp->handle, V_device(vp), V_parentId(vp), VN_GET_INO(vnp));
613 ReleaseWriteLock(&vnp->lock);
615 VNLog(101, 2, vnodeNumber, (afs_int32) vnp);
616 if (++vnp->nUsers == 1) {
617 /* First user. Remove it from the LRU chain. We can assume that
618 * there is at least one item in the queue */
619 if (vnp == vcp->lruHead)
620 vcp->lruHead = vcp->lruHead->lruNext;
621 if (vnp == vcp->lruHead || vcp->lruHead == NULL)
622 Abort("VGetVnode: lru chain addled!\n");
623 vnp->lruPrev->lruNext = vnp->lruNext;
624 vnp->lruNext->lruPrev = vnp->lruPrev;
628 if (locktype == READ_LOCK)
629 ObtainReadLock(&vnp->lock);
631 ObtainWriteLock(&vnp->lock);
632 #ifdef AFS_PTHREAD_ENV
633 vnp->writer = pthread_self();
634 #else /* AFS_PTHREAD_ENV */
635 LWP_CurrentProcess(&vnp->writer);
636 #endif /* AFS_PTHREAD_ENV */
639 /* Check that the vnode hasn't been removed while we were obtaining
641 VNLog(102, 2, vnodeNumber, (afs_int32) vnp);
642 if ((vnp->disk.type == vNull) || (vnp->cacheCheck == 0)) {
643 if (vnp->nUsers-- == 1)
644 StickOnLruChain_r(vnp, vcp);
645 if (locktype == READ_LOCK)
646 ReleaseReadLock(&vnp->lock);
648 ReleaseWriteLock(&vnp->lock);
651 /* vnode is labelled correctly by now, so we don't have to invalidate it */
654 if (programType == fileServer)
655 VBumpVolumeUsage_r(vnp->volumePtr); /* Hack; don't know where it should be
656 * called from. Maybe VGetVolume */
661 int TrustVnodeCacheEntry = 1;
662 /* This variable is bogus--when it's set to 0, the hash chains fill
663 up with multiple versions of the same vnode. Should fix this!! */
665 VPutVnode(Error * ec, register Vnode * vnp)
668 VPutVnode_r(ec, vnp);
673 VPutVnode_r(Error * ec, register Vnode * vnp)
675 int writeLocked, offset;
677 struct VnodeClassInfo *vcp;
681 assert(vnp->nUsers != 0);
682 class = vnodeIdToClass(vnp->vnodeNumber);
683 vcp = &VnodeClassInfo[class];
684 assert(vnp->disk.vnodeMagic == vcp->magic);
685 VNLog(200, 2, vnp->vnodeNumber, (afs_int32) vnp);
687 writeLocked = WriteLocked(&vnp->lock);
689 #ifdef AFS_PTHREAD_ENV
690 pthread_t thisProcess = pthread_self();
691 #else /* AFS_PTHREAD_ENV */
693 LWP_CurrentProcess(&thisProcess);
694 #endif /* AFS_PTHREAD_ENV */
695 VNLog(201, 2, (afs_int32) vnp,
696 ((vnp->changed_newTime) << 1) | ((vnp->
697 changed_oldTime) << 1) | vnp->
699 if (thisProcess != vnp->writer)
700 Abort("VPutVnode: Vnode at 0x%x locked by another process!\n",
702 if (vnp->changed_oldTime || vnp->changed_newTime || vnp->delete) {
703 Volume *vp = vnp->volumePtr;
704 afs_uint32 now = FT_ApproxTime();
705 assert(vnp->cacheCheck == vp->cacheCheck);
708 /* No longer any directory entries for this vnode. Free the Vnode */
709 memset(&vnp->disk, 0, sizeof(vnp->disk));
710 mlkLastDelete = vnp->vnodeNumber;
711 /* delete flag turned off further down */
712 VNLog(202, 2, vnp->vnodeNumber, (afs_int32) vnp);
713 } else if (vnp->changed_newTime) {
714 vnp->disk.serverModifyTime = now;
716 if (vnp->changed_newTime)
717 V_updateDate(vp) = vp->updateTime = now;
719 /* The vnode has been changed. Write it out to disk */
721 assert(V_needsSalvaged(vp));
724 IHandle_t *ihP = vp->vnodeIndex[class].handle;
729 Abort("VPutVnode: can't open index file!\n");
730 offset = vnodeIndexOffset(vcp, vnp->vnodeNumber);
731 if (FDH_SEEK(fdP, offset, SEEK_SET) < 0) {
733 ("VPutVnode: can't seek on index file! fdp=0x%x offset=%d, errno=%d\n",
736 code = FDH_WRITE(fdP, &vnp->disk, vcp->diskSize);
737 if (code != vcp->diskSize) {
738 /* Don't force volume offline if the inumber is out of
739 * range or the inode table is full.
742 if (code == BAD_IGET) {
743 Log("VPutVnode: bad inumber %s\n",
745 vp->vnodeIndex[class].handle->ih_ino));
748 Log("VPutVnode: Couldn't write vnode %u, volume %u (%s) (error %d)\n", vnp->vnodeNumber, V_id(vnp->volumePtr), V_name(vnp->volumePtr), code);
753 FDH_REALLYCLOSE(fdP);
758 /* If the vnode is to be deleted, and we wrote the vnode out,
759 * free its bitmap entry. Do after the vnode is written so we
760 * don't allocate from bitmap before the vnode is written
761 * (doing so could cause a "addled bitmap" message).
763 if (vnp->delete && !*ec) {
764 if (vnp->volumePtr->header->diskstuff.filecount-- < 1)
765 vnp->volumePtr->header->diskstuff.filecount = 0;
766 VFreeBitMapEntry_r(ec, &vp->vnodeIndex[class],
767 vnodeIdToBitNumber(vnp->vnodeNumber));
771 vnp->changed_newTime = vnp->changed_oldTime = 0;
773 } else { /* Not write locked */
774 if (vnp->changed_newTime || vnp->changed_oldTime || vnp->delete)
776 ("VPutVnode: Change or delete flag for vnode 0x%x is set but vnode is not write locked!\n",
780 /* Do not look at disk portion of vnode after this point; it may
781 * have been deleted above */
782 if (vnp->nUsers-- == 1)
783 StickOnLruChain_r(vnp, vcp);
787 ReleaseWriteLock(&vnp->lock);
789 ReleaseReadLock(&vnp->lock);
793 * Make an attempt to convert a vnode lock from write to read.
794 * Do nothing if the vnode isn't write locked or the vnode has
798 VVnodeWriteToRead(Error * ec, register Vnode * vnp)
802 retVal = VVnodeWriteToRead_r(ec, vnp);
808 VVnodeWriteToRead_r(Error * ec, register Vnode * vnp)
812 struct VnodeClassInfo *vcp;
814 #ifdef AFS_PTHREAD_ENV
815 pthread_t thisProcess;
816 #else /* AFS_PTHREAD_ENV */
818 #endif /* AFS_PTHREAD_ENV */
821 assert(vnp->nUsers != 0);
822 class = vnodeIdToClass(vnp->vnodeNumber);
823 vcp = &VnodeClassInfo[class];
824 assert(vnp->disk.vnodeMagic == vcp->magic);
825 writeLocked = WriteLocked(&vnp->lock);
826 VNLog(300, 2, vnp->vnodeNumber, (afs_int32) vnp);
831 #ifdef AFS_PTHREAD_ENV
832 thisProcess = pthread_self();
833 #else /* AFS_PTHREAD_ENV */
834 LWP_CurrentProcess(&thisProcess);
835 #endif /* AFS_PTHREAD_ENV */
837 VNLog(301, 2, (afs_int32) vnp,
838 ((vnp->changed_newTime) << 1) | ((vnp->
839 changed_oldTime) << 1) | vnp->
841 if (thisProcess != vnp->writer)
842 Abort("VPutVnode: Vnode at 0x%x locked by another process!\n",
847 if (vnp->changed_oldTime || vnp->changed_newTime) {
848 Volume *vp = vnp->volumePtr;
849 afs_uint32 now = FT_ApproxTime();
850 assert(vnp->cacheCheck == vp->cacheCheck);
851 if (vnp->changed_newTime)
852 vnp->disk.serverModifyTime = now;
853 if (vnp->changed_newTime)
854 V_updateDate(vp) = vp->updateTime = now;
856 /* The inode has been changed. Write it out to disk */
858 assert(V_needsSalvaged(vp));
861 IHandle_t *ihP = vp->vnodeIndex[class].handle;
863 off_t off = vnodeIndexOffset(vcp, vnp->vnodeNumber);
867 Abort("VPutVnode: can't open index file!\n");
868 code = FDH_SEEK(fdP, off, SEEK_SET);
870 Abort("VPutVnode: can't seek on index file!\n");
871 code = FDH_WRITE(fdP, &vnp->disk, vcp->diskSize);
872 if (code != vcp->diskSize) {
874 * Don't force volume offline if the inumber is out of
875 * range or the inode table is full.
878 if (code == BAD_IGET) {
879 Log("VPutVnode: bad inumber %s\n",
881 vp->vnodeIndex[class].handle->ih_ino));
884 Log("VPutVnode: Couldn't write vnode %u, volume %u (%s)\n", vnp->vnodeNumber, V_id(vnp->volumePtr), V_name(vnp->volumePtr));
894 vnp->changed_newTime = vnp->changed_oldTime = 0;
897 ConvertWriteToReadLock(&vnp->lock);
901 /* Move the vnode, vnp, to the new hash table given by the
902 hash table index, newHash */
904 moveHash(register Vnode * vnp, bit32 newHash)
907 /* Remove it from the old hash chain */
908 tvnp = VnodeHashTable[vnp->hashIndex];
910 VnodeHashTable[vnp->hashIndex] = vnp->hashNext;
912 while (tvnp && tvnp->hashNext != vnp)
913 tvnp = tvnp->hashNext;
915 tvnp->hashNext = vnp->hashNext;
917 /* Add it to the new hash chain */
918 vnp->hashNext = VnodeHashTable[newHash];
919 VnodeHashTable[newHash] = vnp;
920 vnp->hashIndex = newHash;
925 StickOnLruChain_r(register Vnode * vnp, register struct VnodeClassInfo *vcp)
927 /* Add it to the circular LRU list */
928 if (vcp->lruHead == NULL)
929 Abort("VPutVnode: vcp->lruHead==NULL");
931 vnp->lruNext = vcp->lruHead;
932 vnp->lruPrev = vcp->lruHead->lruPrev;
933 vcp->lruHead->lruPrev = vnp;
934 vnp->lruPrev->lruNext = vnp;
937 /* If the vnode was just deleted, put it at the end of the chain so it
938 * will be reused immediately */
940 vcp->lruHead = vnp->lruNext;
941 /* If caching is turned off, set volumeptr to NULL to invalidate the
943 if (!TrustVnodeCacheEntry)
944 vnp->volumePtr = NULL;
947 /* VCloseVnodeFiles - called when a volume is going off line. All open
948 * files for vnodes in that volume are closed. This might be excessive,
949 * since we may only be taking one volume of a volume group offline.
952 VCloseVnodeFiles_r(Volume * vp)
957 for (i = 0; i < VNODE_HASH_TABLE_SIZE; i++) {
958 for (vnp = VnodeHashTable[i]; vnp; vnp = vnp->hashNext) {
959 if (vnp->volumePtr == vp) {
960 IH_REALLYCLOSE(vnp->handle);
966 /* VReleaseVnodeFiles - called when a volume is going detached. All open
967 * files for vnodes in that volume are closed and all inode handles
968 * for vnodes in that volume are released.
971 VReleaseVnodeFiles_r(Volume * vp)
976 for (i = 0; i < VNODE_HASH_TABLE_SIZE; i++) {
977 for (vnp = VnodeHashTable[i]; vnp; vnp = vnp->hashNext) {
978 if (vnp->volumePtr == vp) {
979 IH_RELEASE(vnp->handle);