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
9 * Portions Copyright (c) 2005-2008 Sine Nomine Associates
15 Institution: The Information Technology Center, Carnegie-Mellon University
18 #include <afsconfig.h>
19 #include <afs/param.h>
25 #ifdef HAVE_SYS_FILE_H
30 #ifdef AFS_PTHREAD_ENV
33 #include "rx/rx_queue.h"
34 #include <afs/afsint.h>
36 #include <afs/errors.h>
39 #include <afs/afssyscalls.h>
43 #include "volume_inline.h"
44 #include "vnode_inline.h"
45 #include "partition.h"
52 struct VnodeClassInfo VnodeClassInfo[nVNODECLASSES];
54 void VNLog(afs_int32 aop, afs_int32 anparms, ... );
61 #define BAD_IGET -1000
63 /* There are two separate vnode queue types defined here:
64 * Each hash conflict chain -- is singly linked, with a single head
65 * pointer. New entries are added at the beginning. Old
66 * entries are removed by linear search, which generally
67 * only occurs after a disk read).
68 * LRU chain -- is doubly linked, single head pointer.
69 * Entries are added at the head, reclaimed from the tail,
70 * or removed from anywhere in the queue.
74 /* Vnode hash table. Find hash chain by taking lower bits of
75 * (volume_hash_offset + vnode).
76 * This distributes the root inodes of the volumes over the
77 * hash table entries and also distributes the vnodes of
78 * volumes reasonably fairly. The volume_hash_offset field
79 * for each volume is established as the volume comes on line
80 * by using the VOLUME_HASH_OFFSET macro. This distributes the
81 * volumes fairly among the cache entries, both when servicing
82 * a small number of volumes and when servicing a large number.
85 /* logging stuff for finding bugs */
86 #define THELOGSIZE 5120
87 static afs_int32 theLog[THELOGSIZE];
88 static afs_int32 vnLogPtr = 0;
90 VNLog(afs_int32 aop, afs_int32 anparms, ... )
95 va_start(ap, anparms);
98 anparms = 4; /* do bounds checking */
100 temp = (aop << 16) | anparms;
101 theLog[vnLogPtr++] = temp;
102 if (vnLogPtr >= THELOGSIZE)
104 for (temp = 0; temp < anparms; temp++) {
105 theLog[vnLogPtr++] = va_arg(ap, afs_int32);
106 if (vnLogPtr >= THELOGSIZE)
112 /* VolumeHashOffset -- returns a new value to be stored in the
113 * volumeHashOffset of a Volume structure. Called when a
114 * volume is initialized. Sets the volumeHashOffset so that
115 * vnode cache entries are distributed reasonably between
116 * volumes (the root vnodes of the volumes will hash to
117 * different values, and spacing is maintained between volumes
118 * when there are not many volumes represented), and spread
119 * equally amongst vnodes within a single volume.
122 VolumeHashOffset_r(void)
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] =
129 { 0, 128, 64, 192, 32, 160, 96, 224 };
131 offset = hashindex[nextVolumeHashOffset & hashMask]
132 + (nextVolumeHashOffset >> hashShift);
133 nextVolumeHashOffset++;
137 /* Change hashindex (above) if you change this constant */
138 #define VNODE_HASH_TABLE_SIZE 256
139 private Vnode *VnodeHashTable[VNODE_HASH_TABLE_SIZE];
140 #define VNODE_HASH(volumeptr,vnodenumber)\
141 ((volumeptr->vnodeHashOffset + vnodenumber)&(VNODE_HASH_TABLE_SIZE-1))
145 * add a vnode to the volume's vnode list.
147 * @param[in] vp volume object pointer
148 * @param[in] vnp vnode object pointer
150 * @note for DAFS, it may seem like we should be acquiring a lightweight ref
151 * on vp, but this would actually break things. Right now, this is ok
152 * because we destroy all vnode cache contents during during volume
157 * @internal volume package internal use only
160 AddToVVnList(Volume * vp, Vnode * vnp)
162 if (queue_IsOnQueue(vnp))
166 Vn_cacheCheck(vnp) = vp->cacheCheck;
167 queue_Append(&vp->vnode_list, vnp);
168 Vn_stateFlags(vnp) |= VN_ON_VVN;
172 * delete a vnode from the volume's vnode list.
176 * @internal volume package internal use only
179 DeleteFromVVnList(Vnode * vnp)
181 Vn_volume(vnp) = NULL;
183 if (!queue_IsOnQueue(vnp))
187 Vn_stateFlags(vnp) &= ~(VN_ON_VVN);
191 * add a vnode to the end of the lru.
193 * @param[in] vcp vnode class info object pointer
194 * @param[in] vnp vnode object pointer
196 * @internal vnode package internal use only
199 AddToVnLRU(struct VnodeClassInfo * vcp, Vnode * vnp)
201 if (Vn_stateFlags(vnp) & VN_ON_LRU) {
205 /* Add it to the circular LRU list */
206 if (vcp->lruHead == NULL)
207 Abort("VPutVnode: vcp->lruHead==NULL");
209 vnp->lruNext = vcp->lruHead;
210 vnp->lruPrev = vcp->lruHead->lruPrev;
211 vcp->lruHead->lruPrev = vnp;
212 vnp->lruPrev->lruNext = vnp;
216 /* If the vnode was just deleted, put it at the end of the chain so it
217 * will be reused immediately */
219 vcp->lruHead = vnp->lruNext;
221 Vn_stateFlags(vnp) |= VN_ON_LRU;
225 * delete a vnode from the lru.
227 * @param[in] vcp vnode class info object pointer
228 * @param[in] vnp vnode object pointer
230 * @internal vnode package internal use only
233 DeleteFromVnLRU(struct VnodeClassInfo * vcp, Vnode * vnp)
235 if (!(Vn_stateFlags(vnp) & VN_ON_LRU)) {
239 if (vnp == vcp->lruHead)
240 vcp->lruHead = vcp->lruHead->lruNext;
242 if ((vnp == vcp->lruHead) ||
243 (vcp->lruHead == NULL))
244 Abort("DeleteFromVnLRU: lru chain addled!\n");
246 vnp->lruPrev->lruNext = vnp->lruNext;
247 vnp->lruNext->lruPrev = vnp->lruPrev;
249 Vn_stateFlags(vnp) &= ~(VN_ON_LRU);
253 * add a vnode to the vnode hash table.
255 * @param[in] vnp vnode object pointer
259 * @post vnode on hash
261 * @internal vnode package internal use only
264 AddToVnHash(Vnode * vnp)
266 unsigned int newHash;
268 if (!(Vn_stateFlags(vnp) & VN_ON_HASH)) {
269 newHash = VNODE_HASH(Vn_volume(vnp), Vn_id(vnp));
270 vnp->hashNext = VnodeHashTable[newHash];
271 VnodeHashTable[newHash] = vnp;
272 vnp->hashIndex = newHash;
274 Vn_stateFlags(vnp) |= VN_ON_HASH;
279 * delete a vnode from the vnode hash table.
286 * @post vnode removed from hash
288 * @internal vnode package internal use only
291 DeleteFromVnHash(Vnode * vnp)
295 if (Vn_stateFlags(vnp) & VN_ON_HASH) {
296 tvnp = VnodeHashTable[vnp->hashIndex];
298 VnodeHashTable[vnp->hashIndex] = vnp->hashNext;
300 while (tvnp && tvnp->hashNext != vnp)
301 tvnp = tvnp->hashNext;
303 tvnp->hashNext = vnp->hashNext;
306 vnp->hashNext = NULL;
308 Vn_stateFlags(vnp) &= ~(VN_ON_HASH);
314 * invalidate a vnode cache entry.
316 * @param[in] avnode vnode object pointer
320 * @post vnode metadata invalidated.
321 * vnode removed from hash table.
322 * DAFS: vnode state set to VN_STATE_INVALID.
324 * @internal vnode package internal use only
327 VInvalidateVnode_r(struct Vnode *avnode)
329 avnode->changed_newTime = 0; /* don't let it get flushed out again */
330 avnode->changed_oldTime = 0;
331 avnode->delete = 0; /* it isn't deleted, really */
332 avnode->cacheCheck = 0; /* invalid: prevents future vnode searches from working */
333 DeleteFromVnHash(avnode);
334 #ifdef AFS_DEMAND_ATTACH_FS
335 VnChangeState_r(avnode, VN_STATE_INVALID);
341 * initialize vnode cache for a given vnode class.
343 * @param[in] class vnode class
344 * @param[in] nVnodes size of cache
346 * @post vnode cache allocated and initialized
348 * @internal volume package internal use only
350 * @note generally called by VInitVolumePackage_r
352 * @see VInitVolumePackage_r
355 VInitVnodes(VnodeClass class, int nVnodes)
358 struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
360 vcp->allocs = vcp->gets = vcp->reads = vcp->writes = 0;
361 vcp->cacheSize = nVnodes;
364 opr_Assert(CHECKSIZE_SMALLVNODE);
366 vcp->residentSize = SIZEOF_SMALLVNODE;
367 vcp->diskSize = SIZEOF_SMALLDISKVNODE;
368 vcp->magic = SMALLVNODEMAGIC;
372 vcp->residentSize = SIZEOF_LARGEVNODE;
373 vcp->diskSize = SIZEOF_LARGEDISKVNODE;
374 vcp->magic = LARGEVNODEMAGIC;
378 int s = vcp->diskSize - 1;
388 va = (byte *) calloc(nVnodes, vcp->residentSize);
389 opr_Assert(va != NULL);
391 Vnode *vnp = (Vnode *) va;
392 Vn_refcount(vnp) = 0; /* no context switches */
393 Vn_stateFlags(vnp) |= VN_ON_LRU;
394 #ifdef AFS_DEMAND_ATTACH_FS
395 CV_INIT(&Vn_stateCV(vnp), "vnode state", CV_DEFAULT, 0);
396 Vn_state(vnp) = VN_STATE_INVALID;
398 #else /* !AFS_DEMAND_ATTACH_FS */
399 Lock_Init(&vnp->lock);
400 #endif /* !AFS_DEMAND_ATTACH_FS */
401 vnp->changed_oldTime = 0;
402 vnp->changed_newTime = 0;
403 Vn_volume(vnp) = NULL;
404 Vn_cacheCheck(vnp) = 0;
405 vnp->delete = Vn_id(vnp) = 0;
406 #ifdef AFS_PTHREAD_ENV
407 vnp->writer = (pthread_t) 0;
408 #else /* AFS_PTHREAD_ENV */
409 vnp->writer = (PROCESS) 0;
410 #endif /* AFS_PTHREAD_ENV */
414 if (vcp->lruHead == NULL)
415 vcp->lruHead = vnp->lruNext = vnp->lruPrev = vnp;
417 vnp->lruNext = vcp->lruHead;
418 vnp->lruPrev = vcp->lruHead->lruPrev;
419 vcp->lruHead->lruPrev = vnp;
420 vnp->lruPrev->lruNext = vnp;
423 va += vcp->residentSize;
430 * allocate an unused vnode from the lru chain.
432 * @param[in] vcp vnode class info object pointer
433 * @param[in] vp volume pointer
434 * @param[in] vnodeNumber new vnode number that the vnode will be used for
436 * @pre VOL_LOCK is held
438 * @post vnode object is removed from lru
439 * vnode is disassociated with its old volume, and associated with its
441 * vnode is removed from its old vnode hash table, and for DAFS, it is
442 * added to its new hash table
443 * state is set to VN_STATE_INVALID.
444 * inode handle is released.
445 * a reservation is held on the vnode object
447 * @note we traverse backwards along the lru circlist. It shouldn't
448 * be necessary to specify that nUsers == 0 since if it is in the list,
449 * nUsers should be 0. Things shouldn't be in lruq unless no one is
452 * @warning DAFS: VOL_LOCK is dropped while doing inode handle release
454 * @warning for non-DAFS, the vnode is _not_ hashed on the vnode hash table;
455 * non-DAFS must hash the vnode itself after loading data
457 * @return vnode object pointer
460 VGetFreeVnode_r(struct VnodeClassInfo * vcp, struct Volume *vp,
465 vnp = vcp->lruHead->lruPrev;
466 #ifdef AFS_DEMAND_ATTACH_FS
467 if (Vn_refcount(vnp) != 0 || VnIsExclusiveState(Vn_state(vnp)) ||
468 Vn_readers(vnp) != 0)
469 Abort("VGetFreeVnode_r: in-use vnode in lruq");
471 if (Vn_refcount(vnp) != 0 || CheckLock(&vnp->lock))
472 Abort("VGetFreeVnode_r: locked vnode in lruq");
474 VNLog(1, 2, Vn_id(vnp), (intptr_t)vnp, 0, 0);
477 * it's going to be overwritten soon enough.
478 * remove from LRU, delete hash entry, and
479 * disassociate from old parent volume before
480 * we have a chance to drop the vol glock
482 DeleteFromVnLRU(vcp, vnp);
483 DeleteFromVnHash(vnp);
484 if (Vn_volume(vnp)) {
485 DeleteFromVVnList(vnp);
488 /* we must re-hash the vnp _before_ we drop the glock again; otherwise,
489 * someone else might try to grab the same vnode id, and we'll both alloc
490 * a vnode object for the same vn id, bypassing vnode locking */
491 Vn_id(vnp) = vnodeNumber;
492 VnCreateReservation_r(vnp);
493 AddToVVnList(vp, vnp);
494 #ifdef AFS_DEMAND_ATTACH_FS
498 /* drop the file descriptor */
500 #ifdef AFS_DEMAND_ATTACH_FS
501 VnChangeState_r(vnp, VN_STATE_RELEASING);
504 /* release is, potentially, a highly latent operation due to a couple
506 * - ihandle package lock contention
507 * - closing file descriptor(s) associated with ih
509 * Hance, we perform outside of the volume package lock in order to
510 * reduce the probability of contention.
512 IH_RELEASE(vnp->handle);
513 #ifdef AFS_DEMAND_ATTACH_FS
518 #ifdef AFS_DEMAND_ATTACH_FS
519 VnChangeState_r(vnp, VN_STATE_INVALID);
527 * lookup a vnode in the vnode cache hash table.
529 * @param[in] vp pointer to volume object
530 * @param[in] vnodeId vnode id
534 * @post matching vnode object or NULL is returned
536 * @return vnode object pointer
537 * @retval NULL no matching vnode object was found in the cache
539 * @internal vnode package internal use only
541 * @note this symbol is exported strictly for fssync debug protocol use
544 VLookupVnode(Volume * vp, VnodeId vnodeId)
547 unsigned int newHash;
549 newHash = VNODE_HASH(vp, vnodeId);
550 for (vnp = VnodeHashTable[newHash];
552 ((Vn_id(vnp) != vnodeId) ||
553 (Vn_volume(vnp) != vp) ||
554 (vp->cacheCheck != Vn_cacheCheck(vnp))));
555 vnp = vnp->hashNext);
562 VAllocVnode(Error * ec, Volume * vp, VnodeType type, VnodeId in_vnode, Unique in_unique)
566 retVal = VAllocVnode_r(ec, vp, type, in_vnode, in_unique);
572 * allocate a new vnode.
574 * @param[out] ec error code return
575 * @param[in] vp volume object pointer
576 * @param[in] type desired vnode type
577 * @param[in] type desired vnode ID (optional)
578 * @param[in] type desired vnode Unique (optional)
580 * @return vnode object pointer
582 * @pre VOL_LOCK held;
583 * heavyweight ref held on vp
585 * @post vnode allocated and returned
588 VAllocVnode_r(Error * ec, Volume * vp, VnodeType type, VnodeId in_vnode, Unique in_unique)
593 struct VnodeClassInfo *vcp;
596 struct vnodeIndex *index;
599 #ifdef AFS_DEMAND_ATTACH_FS
600 VolState vol_state_save;
605 #ifdef AFS_DEMAND_ATTACH_FS
607 * once a volume has entered an error state, don't permit
608 * further operations to proceed
609 * -- tkeiser 11/21/2007
611 VWaitExclusiveState_r(vp);
612 if (VIsErrorState(V_attachState(vp))) {
613 /* XXX is VSALVAGING acceptable here? */
619 if (programType == fileServer && !V_inUse(vp)) {
620 if (vp->specialStatus) {
621 *ec = vp->specialStatus;
627 class = vnodeTypeToClass(type);
628 vcp = &VnodeClassInfo[class];
630 if (!VolumeWriteable(vp)) {
631 *ec = (bit32) VREADONLY;
635 if (vp->nextVnodeUnique > V_uniquifier(vp)) {
636 VUpdateVolume_r(ec, vp, 0);
641 if (programType == fileServer) {
642 VAddToVolumeUpdateList_r(ec, vp);
648 * If in_vnode and in_unique are specified, we are asked to
649 * allocate a specifc vnode slot. Used by RW replication to
650 * keep vnode IDs consistent with the master.
656 unique = vp->nextVnodeUnique++;
658 rollover = 1; /* nextVnodeUnique rolled over */
659 vp->nextVnodeUnique = 2; /* 1 is reserved for the root vnode */
660 unique = vp->nextVnodeUnique++;
663 if (vp->nextVnodeUnique > V_uniquifier(vp) || rollover) {
664 VUpdateVolume_r(ec, vp, 0);
669 /* Find a slot in the bit map */
670 bitNumber = VAllocBitmapEntry_r(ec, vp, &vp->vnodeIndex[class],
671 VOL_ALLOC_BITMAP_WAIT);
675 vnodeNumber = bitNumberToVnodeNumber(bitNumber, class);
677 index = &vp->vnodeIndex[class];
682 /* Catch us up to where the master is */
683 if (in_unique > vp->nextVnodeUnique)
684 vp->nextVnodeUnique = in_unique+1;
686 if (vp->nextVnodeUnique > V_uniquifier(vp)) {
687 VUpdateVolume_r(ec, vp, 0);
693 bitNumber = vnodeIdToBitNumber(in_vnode);
694 offset = bitNumber >> 3;
696 /* Mark vnode in use. Grow bitmap if needed. */
697 if ((offset >= index->bitmapSize)
698 || ((*(index->bitmap + offset) & (1 << (bitNumber & 0x7))) == 0))
700 /* Should not happen */
701 if (*(index->bitmap + offset) & (1 << (bitNumber & 0x7))) {
706 *(index->bitmap + offset) |= (1 << (bitNumber & 0x7));
707 vnodeNumber = in_vnode;
712 * at this point we should be assured that V_attachState(vp) is non-exclusive
716 VNLog(2, 1, vnodeNumber, 0, 0, 0);
717 /* Prepare to move it to the new hash chain */
718 vnp = VLookupVnode(vp, vnodeNumber);
720 /* slot already exists. May even not be in lruq (consider store file locking a file being deleted)
721 * so we may have to wait for it below */
722 VNLog(3, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
724 VnCreateReservation_r(vnp);
725 if (Vn_refcount(vnp) == 1) {
726 /* we're the only user */
727 /* This won't block */
728 VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, WILL_NOT_DEADLOCK);
730 #ifdef AFS_DEMAND_ATTACH_FS
733 * vnode was cached, wait for any existing exclusive ops to finish.
734 * once we have reacquired the lock, re-verify volume state.
736 * note: any vnode error state is related to the old vnode; disregard.
738 VnWaitQuiescent_r(vnp);
739 if (VIsErrorState(V_attachState(vp))) {
740 VnUnlock(vnp, WRITE_LOCK);
741 VnCancelReservation_r(vnp);
747 /* other users present; follow locking hierarchy */
748 VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, MIGHT_DEADLOCK);
751 * verify state of the world hasn't changed
753 * (technically, this should never happen because cachecheck
754 * is only updated during a volume attach, which should not
755 * happen when refs are held)
757 if (Vn_volume(vnp)->cacheCheck != Vn_cacheCheck(vnp)) {
758 VnUnlock(vnp, WRITE_LOCK);
759 VnCancelReservation_r(vnp);
764 /* sanity check: vnode should be blank if it was deleted. If it's
765 * not blank, it is still in use somewhere; but the bitmap told us
766 * this vnode number was free, so something is wrong. */
767 if (vnp->disk.type != vNull) {
769 Log("VAllocVnode: addled bitmap or vnode object! (vol %" AFS_VOLID_FMT ", "
770 "vnode %p, number %ld, type %ld)\n", afs_printable_VolumeId_lu(vp->hashid), vnp,
771 (long)Vn_id(vnp), (long)vnp->disk.type);
773 VFreeBitMapEntry_r(&tmp, vp, &vp->vnodeIndex[class], bitNumber,
774 VOL_FREE_BITMAP_WAIT);
775 VInvalidateVnode_r(vnp);
776 VnUnlock(vnp, WRITE_LOCK);
777 VnCancelReservation_r(vnp);
778 #ifdef AFS_DEMAND_ATTACH_FS
779 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
781 VForceOffline_r(vp, 0);
787 /* no such vnode in the cache */
789 vnp = VGetFreeVnode_r(vcp, vp, vnodeNumber);
791 /* This will never block (guaranteed by check in VGetFreeVnode_r() */
792 VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, WILL_NOT_DEADLOCK);
794 #ifdef AFS_DEMAND_ATTACH_FS
795 VnChangeState_r(vnp, VN_STATE_ALLOC);
798 /* Sanity check: is this vnode really not in use? */
801 IHandle_t *ihP = vp->vnodeIndex[class].handle;
803 afs_foff_t off = vnodeIndexOffset(vcp, vnodeNumber);
806 /* XXX we have a potential race here if two threads
807 * allocate new vnodes at the same time, and they
808 * both decide it's time to extend the index
811 #ifdef AFS_DEMAND_ATTACH_FS
813 * this race has been eliminated for the DAFS case
814 * using exclusive state VOL_STATE_VNODE_ALLOC
816 * if this becomes a bottleneck, there are ways to
817 * improve parallelism for this code path
818 * -- tkeiser 11/28/2007
820 VCreateReservation_r(vp);
821 VWaitExclusiveState_r(vp);
822 vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_ALLOC);
828 Log("VAllocVnode: can't open index file!\n");
830 goto error_encountered;
832 if ((size = FDH_SIZE(fdP)) < 0) {
833 Log("VAllocVnode: can't stat index file!\n");
835 goto error_encountered;
837 if (off + vcp->diskSize <= size) {
838 if (FDH_PREAD(fdP, &vnp->disk, vcp->diskSize, off) != vcp->diskSize) {
839 Log("VAllocVnode: can't read index file!\n");
841 goto error_encountered;
843 if (vnp->disk.type != vNull) {
844 Log("VAllocVnode: addled bitmap or index!\n");
846 goto error_encountered;
849 /* growing file - grow in a reasonable increment */
850 char *buf = malloc(16 * 1024);
852 Log("VAllocVnode: can't grow vnode index: out of memory\n");
854 goto error_encountered;
856 memset(buf, 0, 16 * 1024);
857 if ((FDH_PWRITE(fdP, buf, 16 * 1024, off)) != 16 * 1024) {
858 Log("VAllocVnode: can't grow vnode index: write failed\n");
861 goto error_encountered;
868 #ifdef AFS_DEMAND_ATTACH_FS
869 VChangeState_r(vp, vol_state_save);
870 VCancelReservation_r(vp);
877 * close the file handle
879 * invalidate the vnode
880 * free up the bitmap entry (although salvager should take care of it)
882 * drop vnode lock and refs
887 VFreeBitMapEntry_r(&tmp, vp, &vp->vnodeIndex[class], bitNumber, 0 /*flags*/);
888 VInvalidateVnode_r(vnp);
889 VnUnlock(vnp, WRITE_LOCK);
890 VnCancelReservation_r(vnp);
891 #ifdef AFS_DEMAND_ATTACH_FS
892 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
893 VCancelReservation_r(vp);
895 VForceOffline_r(vp, 0);
900 VNLog(4, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
901 #ifndef AFS_DEMAND_ATTACH_FS
906 VNLog(5, 1, (intptr_t)vnp, 0, 0, 0);
907 memset(&vnp->disk, 0, sizeof(vnp->disk));
908 vnp->changed_newTime = 0; /* set this bit when vnode is updated */
909 vnp->changed_oldTime = 0; /* set this on CopyOnWrite. */
911 vnp->disk.vnodeMagic = vcp->magic;
912 vnp->disk.type = type;
913 vnp->disk.uniquifier = unique;
917 #ifdef AFS_DEMAND_ATTACH_FS
918 VnChangeState_r(vnp, VN_STATE_EXCLUSIVE);
924 * load a vnode from disk.
926 * @param[out] ec client error code return
927 * @param[in] vp volume object pointer
928 * @param[in] vnp vnode object pointer
929 * @param[in] vcp vnode class info object pointer
930 * @param[in] class vnode class enumeration
932 * @pre vnode is registered in appropriate data structures;
933 * caller holds a ref on vnode; VOL_LOCK is held
935 * @post vnode data is loaded from disk.
936 * vnode state is set to VN_STATE_ONLINE.
937 * on failure, vnode is invalidated.
939 * @internal vnode package internal use only
942 VnLoad(Error * ec, Volume * vp, Vnode * vnp,
943 struct VnodeClassInfo * vcp, VnodeClass class)
945 /* vnode not cached */
949 IHandle_t *ihP = vp->vnodeIndex[class].handle;
956 #ifdef AFS_DEMAND_ATTACH_FS
957 VnChangeState_r(vnp, VN_STATE_LOAD);
960 /* This will never block */
961 VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, WILL_NOT_DEADLOCK);
966 Log("VnLoad: can't open index dev=%u, i=%s\n", vp->device,
967 PrintInode(stmp, vp->vnodeIndex[class].handle->ih_ino));
969 goto error_encountered_nolock;
970 } else if ((nBytes = FDH_PREAD(fdP, (char *)&vnp->disk, vcp->diskSize, vnodeIndexOffset(vcp, Vn_id(vnp))))
972 /* Don't take volume off line if the inumber is out of range
973 * or the inode table is full. */
974 if (nBytes == BAD_IGET) {
975 Log("VnLoad: bad inumber %s\n",
976 PrintInode(stmp, vp->vnodeIndex[class].handle->ih_ino));
979 } else if (nBytes == -1 && errno == EIO) {
980 /* disk error; salvage */
981 Log("VnLoad: Couldn't read vnode %u, volume %" AFS_VOLID_FMT " (%s); volume needs salvage\n", Vn_id(vnp), afs_printable_VolumeId_lu(V_id(vp)), V_name(vp));
983 /* vnode is not allocated */
985 Log("VnLoad: Couldn't read vnode %u, volume %" AFS_VOLID_FMT " (%s); read %d bytes, errno %d\n",
986 Vn_id(vnp), afs_printable_VolumeId_lu(V_id(vp)), V_name(vp), (int)nBytes, errno);
990 goto error_encountered_nolock;
995 /* Quick check to see that the data is reasonable */
996 if (vnp->disk.vnodeMagic != vcp->magic || vnp->disk.type == vNull) {
997 if (vnp->disk.type == vNull) {
1001 struct vnodeIndex *index = &vp->vnodeIndex[class];
1002 unsigned int bitNumber = vnodeIdToBitNumber(Vn_id(vnp));
1003 unsigned int offset = bitNumber >> 3;
1005 #ifdef AFS_DEMAND_ATTACH_FS
1006 /* Make sure the volume bitmap isn't getting updated while we are
1008 VWaitExclusiveState_r(vp);
1011 /* Test to see if vnode number is valid. */
1012 if ((offset >= index->bitmapSize)
1013 || ((*(index->bitmap + offset) & (1 << (bitNumber & 0x7)))
1015 Log("VnLoad: Request for unallocated vnode %u, volume %" AFS_VOLID_FMT " (%s) denied.\n", Vn_id(vnp), afs_printable_VolumeId_lu(V_id(vp)), V_name(vp));
1019 Log("VnLoad: Bad magic number, vnode %u, volume %" AFS_VOLID_FMT " (%s); volume needs salvage\n", Vn_id(vnp), afs_printable_VolumeId_lu(V_id(vp)), V_name(vp));
1022 goto error_encountered;
1025 IH_INIT(vnp->handle, V_device(vp), afs_printable_VolumeId_lu(V_parentId(vp)), VN_GET_INO(vnp));
1026 VnUnlock(vnp, WRITE_LOCK);
1027 #ifdef AFS_DEMAND_ATTACH_FS
1028 VnChangeState_r(vnp, VN_STATE_ONLINE);
1033 error_encountered_nolock:
1035 FDH_REALLYCLOSE(fdP);
1041 #ifdef AFS_DEMAND_ATTACH_FS
1042 VRequestSalvage_r(&error, vp, SALVSYNC_ERROR, 0);
1044 VForceOffline_r(vp, 0);
1051 VInvalidateVnode_r(vnp);
1052 VnUnlock(vnp, WRITE_LOCK);
1056 * store a vnode to disk.
1058 * @param[out] ec error code output
1059 * @param[in] vp volume object pointer
1060 * @param[in] vnp vnode object pointer
1061 * @param[in] vcp vnode class info object pointer
1062 * @param[in] class vnode class enumeration
1064 * @pre VOL_LOCK held.
1065 * caller holds refs to volume and vnode.
1066 * DAFS: caller is responsible for performing state sanity checks.
1068 * @post vnode state is stored to disk.
1070 * @internal vnode package internal use only
1073 VnStore(Error * ec, Volume * vp, Vnode * vnp,
1074 struct VnodeClassInfo * vcp, VnodeClass class)
1078 IHandle_t *ihP = vp->vnodeIndex[class].handle;
1081 #ifdef AFS_DEMAND_ATTACH_FS
1082 VnState vn_state_save;
1087 #ifdef AFS_DEMAND_ATTACH_FS
1088 vn_state_save = VnChangeState_r(vnp, VN_STATE_STORE);
1091 offset = vnodeIndexOffset(vcp, Vn_id(vnp));
1095 Log("VnStore: can't open index file!\n");
1096 goto error_encountered;
1098 nBytes = FDH_PWRITE(fdP, &vnp->disk, vcp->diskSize, offset);
1099 if (nBytes != vcp->diskSize) {
1100 /* Don't force volume offline if the inumber is out of
1101 * range or the inode table is full.
1103 FDH_REALLYCLOSE(fdP);
1104 if (nBytes == BAD_IGET) {
1105 Log("VnStore: bad inumber %s\n",
1107 vp->vnodeIndex[class].handle->ih_ino));
1110 #ifdef AFS_DEMAND_ATTACH_FS
1111 VnChangeState_r(vnp, VN_STATE_ERROR);
1114 Log("VnStore: Couldn't write vnode %u, volume %" AFS_VOLID_FMT " (%s) (error %d)\n", Vn_id(vnp), afs_printable_VolumeId_lu(V_id(Vn_volume(vnp))), V_name(Vn_volume(vnp)), (int)nBytes);
1115 #ifdef AFS_DEMAND_ATTACH_FS
1116 goto error_encountered;
1119 VForceOffline_r(vp, 0);
1129 #ifdef AFS_DEMAND_ATTACH_FS
1130 VnChangeState_r(vnp, vn_state_save);
1135 #ifdef AFS_DEMAND_ATTACH_FS
1136 /* XXX instead of dumping core, let's try to request a salvage
1137 * and just fail the putvnode */
1141 VnChangeState_r(vnp, VN_STATE_ERROR);
1142 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
1149 * get a handle to a vnode object.
1151 * @param[out] ec error code
1152 * @param[in] vp volume object
1153 * @param[in] vnodeNumber vnode id
1154 * @param[in] locktype type of lock to acquire
1156 * @return vnode object pointer
1161 VGetVnode(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
1162 { /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
1165 retVal = VGetVnode_r(ec, vp, vnodeNumber, locktype);
1171 * get a handle to a vnode object.
1173 * @param[out] ec error code
1174 * @param[in] vp volume object
1175 * @param[in] vnodeNumber vnode id
1176 * @param[in] locktype type of lock to acquire
1178 * @return vnode object pointer
1180 * @internal vnode package internal use only
1182 * @pre VOL_LOCK held.
1183 * heavyweight ref held on volume object.
1186 VGetVnode_r(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
1187 { /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
1190 struct VnodeClassInfo *vcp;
1194 if (vnodeNumber == 0) {
1199 VNLog(100, 1, vnodeNumber, 0, 0, 0);
1201 #ifdef AFS_DEMAND_ATTACH_FS
1203 * once a volume has entered an error state, don't permit
1204 * further operations to proceed
1205 * -- tkeiser 11/21/2007
1207 VWaitExclusiveState_r(vp);
1208 if (VIsErrorState(V_attachState(vp))) {
1209 /* XXX is VSALVAGING acceptable here? */
1215 if (programType == fileServer && !V_inUse(vp)) {
1216 *ec = (vp->specialStatus ? vp->specialStatus : VOFFLINE);
1218 /* If the volume is VBUSY (being cloned or dumped) and this is
1219 * a READ operation, then don't fail.
1221 if ((*ec != VBUSY) || (locktype != READ_LOCK)) {
1226 class = vnodeIdToClass(vnodeNumber);
1227 vcp = &VnodeClassInfo[class];
1228 if (locktype == WRITE_LOCK && !VolumeWriteable(vp)) {
1229 *ec = (bit32) VREADONLY;
1233 if (locktype == WRITE_LOCK && programType == fileServer) {
1234 VAddToVolumeUpdateList_r(ec, vp);
1242 /* See whether the vnode is in the cache. */
1243 vnp = VLookupVnode(vp, vnodeNumber);
1245 /* vnode is in cache */
1247 VNLog(101, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
1248 VnCreateReservation_r(vnp);
1250 #ifdef AFS_DEMAND_ATTACH_FS
1252 * this is the one DAFS case where we may run into contention.
1253 * here's the basic control flow:
1255 * if locktype is READ_LOCK:
1256 * wait until vnode is not exclusive
1257 * set to VN_STATE_READ
1258 * increment read count
1261 * wait until vnode is quiescent
1262 * set to VN_STATE_EXCLUSIVE
1265 if (locktype == READ_LOCK) {
1266 VnWaitExclusiveState_r(vnp);
1268 VnWaitQuiescent_r(vnp);
1271 if (VnIsErrorState(Vn_state(vnp))) {
1272 VnCancelReservation_r(vnp);
1276 #endif /* AFS_DEMAND_ATTACH_FS */
1278 /* vnode not cached */
1280 /* Not in cache; tentatively grab most distantly used one from the LRU
1283 vnp = VGetFreeVnode_r(vcp, vp, vnodeNumber);
1286 vnp->changed_newTime = vnp->changed_oldTime = 0;
1290 * XXX for non-DAFS, there is a serious
1291 * race condition here:
1293 * two threads can race to load a vnode. the net
1294 * result is two struct Vnodes can be allocated
1295 * and hashed, which point to the same underlying
1296 * disk data store. conflicting vnode locks can
1297 * thus be held concurrently.
1299 * for non-DAFS to be safe, VOL_LOCK really shouldn't
1300 * be dropped in VnLoad. Of course, this would likely
1301 * lead to an unacceptable slow-down.
1304 VnLoad(ec, vp, vnp, vcp, class);
1306 VnCancelReservation_r(vnp);
1309 #ifndef AFS_DEMAND_ATTACH_FS
1314 * there is no possibility for contention. we "own" this vnode.
1320 * it is imperative that nothing drop vol lock between here
1321 * and the VnBeginRead/VnChangeState stanza below
1324 VnLock(vnp, locktype, VOL_LOCK_HELD, MIGHT_DEADLOCK);
1326 /* Check that the vnode hasn't been removed while we were obtaining
1328 VNLog(102, 2, vnodeNumber, (intptr_t) vnp, 0, 0);
1329 if ((vnp->disk.type == vNull) || (Vn_cacheCheck(vnp) == 0)) {
1330 VnUnlock(vnp, locktype);
1331 VnCancelReservation_r(vnp);
1333 /* vnode is labelled correctly by now, so we don't have to invalidate it */
1337 #ifdef AFS_DEMAND_ATTACH_FS
1338 if (locktype == READ_LOCK) {
1341 VnChangeState_r(vnp, VN_STATE_EXCLUSIVE);
1345 if (programType == fileServer)
1346 VBumpVolumeUsage_r(Vn_volume(vnp)); /* Hack; don't know where it should be
1347 * called from. Maybe VGetVolume */
1352 int TrustVnodeCacheEntry = 1;
1353 /* This variable is bogus--when it's set to 0, the hash chains fill
1354 up with multiple versions of the same vnode. Should fix this!! */
1356 VPutVnode(Error * ec, Vnode * vnp)
1359 VPutVnode_r(ec, vnp);
1364 * put back a handle to a vnode object.
1366 * @param[out] ec client error code
1367 * @param[in] vnp vnode object pointer
1369 * @pre VOL_LOCK held.
1370 * ref held on vnode.
1372 * @post ref dropped on vnode.
1373 * if vnode was modified or deleted, it is written out to disk
1374 * (assuming a write lock was held).
1376 * @internal volume package internal use only
1379 VPutVnode_r(Error * ec, Vnode * vnp)
1383 struct VnodeClassInfo *vcp;
1386 opr_Assert(Vn_refcount(vnp) != 0);
1387 class = vnodeIdToClass(Vn_id(vnp));
1388 vcp = &VnodeClassInfo[class];
1389 opr_Assert(vnp->disk.vnodeMagic == vcp->magic);
1390 VNLog(200, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
1392 #ifdef AFS_DEMAND_ATTACH_FS
1393 writeLocked = (Vn_state(vnp) == VN_STATE_EXCLUSIVE);
1395 writeLocked = WriteLocked(&vnp->lock);
1400 #ifdef AFS_PTHREAD_ENV
1401 pthread_t thisProcess = pthread_self();
1402 #else /* AFS_PTHREAD_ENV */
1403 PROCESS thisProcess;
1404 LWP_CurrentProcess(&thisProcess);
1405 #endif /* AFS_PTHREAD_ENV */
1406 VNLog(201, 2, (intptr_t) vnp,
1407 ((vnp->changed_newTime) << 1) | ((vnp->
1408 changed_oldTime) << 1) | vnp->
1410 if (thisProcess != vnp->writer)
1411 Abort("VPutVnode: Vnode at %"AFS_PTR_FMT" locked by another process!\n",
1415 if (vnp->changed_oldTime || vnp->changed_newTime || vnp->delete) {
1416 Volume *vp = Vn_volume(vnp);
1417 afs_uint32 now = FT_ApproxTime();
1418 opr_Assert(Vn_cacheCheck(vnp) == vp->cacheCheck);
1421 /* No longer any directory entries for this vnode. Free the Vnode */
1422 memset(&vnp->disk, 0, sizeof(vnp->disk));
1423 /* delete flag turned off further down */
1424 VNLog(202, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
1425 } else if (vnp->changed_newTime) {
1426 vnp->disk.serverModifyTime = now;
1428 if (vnp->changed_newTime)
1430 V_updateDate(vp) = vp->updateTime = now;
1431 if(V_volUpCounter(vp)< UINT_MAX)
1432 V_volUpCounter(vp)++;
1435 /* The vnode has been changed. Write it out to disk */
1437 #ifdef AFS_DEMAND_ATTACH_FS
1438 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
1440 opr_Assert(V_needsSalvaged(vp));
1444 VnStore(ec, vp, vnp, vcp, class);
1446 /* If the vnode is to be deleted, and we wrote the vnode out,
1447 * free its bitmap entry. Do after the vnode is written so we
1448 * don't allocate from bitmap before the vnode is written
1449 * (doing so could cause a "addled bitmap" message).
1451 if (vnp->delete && !*ec) {
1452 if (V_filecount(Vn_volume(vnp))-- < 1)
1453 V_filecount(Vn_volume(vnp)) = 0;
1454 VFreeBitMapEntry_r(ec, vp, &vp->vnodeIndex[class],
1455 vnodeIdToBitNumber(Vn_id(vnp)),
1456 VOL_FREE_BITMAP_WAIT);
1460 vnp->changed_newTime = vnp->changed_oldTime = 0;
1462 #ifdef AFS_DEMAND_ATTACH_FS
1463 VnChangeState_r(vnp, VN_STATE_ONLINE);
1465 } else { /* Not write locked */
1466 if (vnp->changed_newTime || vnp->changed_oldTime || vnp->delete)
1468 ("VPutVnode: Change or delete flag for vnode "
1469 "%"AFS_PTR_FMT" is set but vnode is not write locked!\n",
1471 #ifdef AFS_DEMAND_ATTACH_FS
1476 /* Do not look at disk portion of vnode after this point; it may
1477 * have been deleted above */
1479 VnUnlock(vnp, ((writeLocked) ? WRITE_LOCK : READ_LOCK));
1480 VnCancelReservation_r(vnp);
1484 * Make an attempt to convert a vnode lock from write to read.
1485 * Do nothing if the vnode isn't write locked or the vnode has
1489 VVnodeWriteToRead(Error * ec, Vnode * vnp)
1493 retVal = VVnodeWriteToRead_r(ec, vnp);
1499 * convert vnode handle from mutually exclusive to shared access.
1501 * @param[out] ec client error code
1502 * @param[in] vnp vnode object pointer
1504 * @return unspecified use (see out argument 'ec' for error code return)
1506 * @pre VOL_LOCK held.
1507 * ref held on vnode.
1508 * write lock held on vnode.
1510 * @post read lock held on vnode.
1511 * if vnode was modified, it has been written to disk.
1513 * @internal volume package internal use only
1516 VVnodeWriteToRead_r(Error * ec, Vnode * vnp)
1520 struct VnodeClassInfo *vcp;
1521 #ifdef AFS_PTHREAD_ENV
1522 pthread_t thisProcess;
1523 #else /* AFS_PTHREAD_ENV */
1524 PROCESS thisProcess;
1525 #endif /* AFS_PTHREAD_ENV */
1528 opr_Assert(Vn_refcount(vnp) != 0);
1529 class = vnodeIdToClass(Vn_id(vnp));
1530 vcp = &VnodeClassInfo[class];
1531 opr_Assert(vnp->disk.vnodeMagic == vcp->magic);
1532 VNLog(300, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
1534 #ifdef AFS_DEMAND_ATTACH_FS
1535 writeLocked = (Vn_state(vnp) == VN_STATE_EXCLUSIVE);
1537 writeLocked = WriteLocked(&vnp->lock);
1544 VNLog(301, 2, (intptr_t) vnp,
1545 ((vnp->changed_newTime) << 1) | ((vnp->
1546 changed_oldTime) << 1) | vnp->
1550 #ifdef AFS_PTHREAD_ENV
1551 thisProcess = pthread_self();
1552 #else /* AFS_PTHREAD_ENV */
1553 LWP_CurrentProcess(&thisProcess);
1554 #endif /* AFS_PTHREAD_ENV */
1555 if (thisProcess != vnp->writer)
1556 Abort("VPutVnode: Vnode at %"AFS_PTR_FMT
1557 " locked by another process!\n", vnp);
1562 if (vnp->changed_oldTime || vnp->changed_newTime) {
1563 Volume *vp = Vn_volume(vnp);
1564 afs_uint32 now = FT_ApproxTime();
1565 opr_Assert(Vn_cacheCheck(vnp) == vp->cacheCheck);
1566 if (vnp->changed_newTime)
1567 vnp->disk.serverModifyTime = now;
1568 if (vnp->changed_newTime)
1569 V_updateDate(vp) = vp->updateTime = now;
1571 /* The inode has been changed. Write it out to disk */
1573 #ifdef AFS_DEMAND_ATTACH_FS
1574 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
1576 opr_Assert(V_needsSalvaged(vp));
1580 VnStore(ec, vp, vnp, vcp, class);
1583 vnp->changed_newTime = vnp->changed_oldTime = 0;
1587 #ifdef AFS_DEMAND_ATTACH_FS
1588 VnChangeState_r(vnp, VN_STATE_ONLINE);
1591 ConvertWriteToReadLock(&vnp->lock);
1597 * initial size of ihandle pointer vector.
1599 * @see VInvalidateVnodesByVolume_r
1601 #define IH_VEC_BASE_SIZE 256
1604 * increment amount for growing ihandle pointer vector.
1606 * @see VInvalidateVnodesByVolume_r
1608 #define IH_VEC_INCREMENT 256
1611 * Compile list of ihandles to be released/reallyclosed at a later time.
1613 * @param[in] vp volume object pointer
1614 * @param[out] vec_out vector of ihandle pointers to be released/reallyclosed
1615 * @param[out] vec_len_out number of valid elements in ihandle vector
1617 * @pre - VOL_LOCK is held
1618 * - volume is in appropriate exclusive state (e.g. VOL_STATE_VNODE_CLOSE,
1619 * VOL_STATE_VNODE_RELEASE)
1621 * @post - all vnodes on VVn list are invalidated
1622 * - ih_vec is populated with all valid ihandles
1624 * @return operation status
1626 * @retval ENOMEM out of memory
1628 * @todo we should handle out of memory conditions more gracefully.
1630 * @internal vnode package internal use only
1633 VInvalidateVnodesByVolume_r(Volume * vp,
1634 IHandle_t *** vec_out,
1635 size_t * vec_len_out)
1639 size_t i = 0, vec_len;
1640 IHandle_t **ih_vec, **ih_vec_new;
1642 #ifdef AFS_DEMAND_ATTACH_FS
1644 #endif /* AFS_DEMAND_ATTACH_FS */
1646 vec_len = IH_VEC_BASE_SIZE;
1647 ih_vec = malloc(sizeof(IHandle_t *) * vec_len);
1648 #ifdef AFS_DEMAND_ATTACH_FS
1655 * Traverse the volume's vnode list. Pull all the ihandles out into a
1656 * thread-private array for later asynchronous processing.
1658 #ifdef AFS_DEMAND_ATTACH_FS
1661 for (queue_Scan(&vp->vnode_list, vnp, nvnp, Vnode)) {
1662 if (vnp->handle != NULL) {
1664 #ifdef AFS_DEMAND_ATTACH_FS
1667 vec_len += IH_VEC_INCREMENT;
1668 ih_vec_new = realloc(ih_vec, sizeof(IHandle_t *) * vec_len);
1669 #ifdef AFS_DEMAND_ATTACH_FS
1672 if (ih_vec_new == NULL) {
1676 ih_vec = ih_vec_new;
1677 #ifdef AFS_DEMAND_ATTACH_FS
1679 * Theoretically, the volume's VVn list should not change
1680 * because the volume is in an exclusive state. For the
1681 * sake of safety, we will restart the traversal from the
1682 * the beginning (which is not expensive because we're
1683 * deleting the items from the list as we go).
1685 goto restart_traversal;
1688 ih_vec[i++] = vnp->handle;
1691 DeleteFromVVnList(vnp);
1692 VInvalidateVnode_r(vnp);
1702 /* VCloseVnodeFiles - called when a volume is going off line. All open
1703 * files for vnodes in that volume are closed. This might be excessive,
1704 * since we may only be taking one volume of a volume group offline.
1707 VCloseVnodeFiles_r(Volume * vp)
1709 #ifdef AFS_DEMAND_ATTACH_FS
1710 VolState vol_state_save;
1712 IHandle_t ** ih_vec;
1715 #ifdef AFS_DEMAND_ATTACH_FS
1716 vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_CLOSE);
1717 #endif /* AFS_DEMAND_ATTACH_FS */
1719 /* XXX need better error handling here */
1720 opr_Verify(VInvalidateVnodesByVolume_r(vp, &ih_vec,
1725 * now we drop VOL_LOCK while we perform some potentially very
1726 * expensive operations in the background
1728 #ifdef AFS_DEMAND_ATTACH_FS
1732 for (i = 0; i < vec_len; i++) {
1733 IH_REALLYCLOSE(ih_vec[i]);
1734 IH_RELEASE(ih_vec[i]);
1739 #ifdef AFS_DEMAND_ATTACH_FS
1741 VChangeState_r(vp, vol_state_save);
1742 #endif /* AFS_DEMAND_ATTACH_FS */
1747 * shut down all vnode cache state for a given volume.
1749 * @param[in] vp volume object pointer
1751 * @pre VOL_LOCK is held
1753 * @post all file descriptors closed.
1754 * all inode handles released.
1755 * all vnode cache objects disassociated from volume.
1757 * @note for DAFS, these operations are performed outside the vol glock under
1758 * volume exclusive state VOL_STATE_VNODE_RELEASE. Please further note
1759 * that it would be a bug to acquire and release a volume reservation
1760 * during this exclusive operation. This is due to the fact that we are
1761 * generally called during the refcount 1->0 transition.
1763 * @todo we should handle failures in VInvalidateVnodesByVolume_r more
1766 * @see VInvalidateVnodesByVolume_r
1768 * @internal this routine is internal to the volume package
1771 VReleaseVnodeFiles_r(Volume * vp)
1773 #ifdef AFS_DEMAND_ATTACH_FS
1774 VolState vol_state_save;
1776 IHandle_t ** ih_vec;
1779 #ifdef AFS_DEMAND_ATTACH_FS
1780 vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_RELEASE);
1781 #endif /* AFS_DEMAND_ATTACH_FS */
1783 /* XXX need better error handling here */
1784 opr_Verify(VInvalidateVnodesByVolume_r(vp, &ih_vec,
1789 * now we drop VOL_LOCK while we perform some potentially very
1790 * expensive operations in the background
1792 #ifdef AFS_DEMAND_ATTACH_FS
1796 for (i = 0; i < vec_len; i++) {
1797 IH_RELEASE(ih_vec[i]);
1802 #ifdef AFS_DEMAND_ATTACH_FS
1804 VChangeState_r(vp, vol_state_save);
1805 #endif /* AFS_DEMAND_ATTACH_FS */