Switch to jhash for VNODE_HASH
[openafs.git] / src / vol / vnode.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  *
9  * Portions Copyright (c) 2005-2008 Sine Nomine Associates
10  */
11
12 /*
13         System:         VICE-TWO
14         Module:         vnode.c
15         Institution:    The Information Technology Center, Carnegie-Mellon University
16
17  */
18 #include <afsconfig.h>
19 #include <afs/param.h>
20
21 #include <roken.h>
22
23 #include <limits.h>
24
25 #ifdef HAVE_SYS_FILE_H
26 #include <sys/file.h>
27 #endif
28
29 #include <afs/opr.h>
30 #ifdef AFS_PTHREAD_ENV
31 #include <opr/lock.h>
32 #endif
33 #include <opr/jhash.h>
34 #include "rx/rx_queue.h"
35 #include <afs/afsint.h>
36 #include "nfs.h"
37 #include <afs/errors.h>
38 #include "lock.h"
39 #include "lwp.h"
40 #include <afs/afssyscalls.h>
41 #include "ihandle.h"
42 #include "vnode.h"
43 #include "volume.h"
44 #include "volume_inline.h"
45 #include "vnode_inline.h"
46 #include "partition.h"
47 #include "salvsync.h"
48 #include "common.h"
49 #ifdef AFS_NT40_ENV
50 #include "ntops.h"
51 #endif
52
53 struct VnodeClassInfo VnodeClassInfo[nVNODECLASSES];
54
55 void VNLog(afs_int32 aop, afs_int32 anparms, ... );
56
57 extern int LogLevel;
58
59 /* logging stuff for finding bugs */
60 #define THELOGSIZE      5120
61 static afs_int32 theLog[THELOGSIZE];
62 static afs_int32 vnLogPtr = 0;
63 void
64 VNLog(afs_int32 aop, afs_int32 anparms, ... )
65 {
66     afs_int32 temp;
67     va_list ap;
68
69     va_start(ap, anparms);
70
71     if (anparms > 4)
72         anparms = 4;            /* do bounds checking */
73
74     temp = (aop << 16) | anparms;
75     theLog[vnLogPtr++] = temp;
76     if (vnLogPtr >= THELOGSIZE)
77         vnLogPtr = 0;
78     for (temp = 0; temp < anparms; temp++) {
79         theLog[vnLogPtr++] = va_arg(ap, afs_int32);
80         if (vnLogPtr >= THELOGSIZE)
81             vnLogPtr = 0;
82     }
83     va_end(ap);
84 }
85
86
87 /* Vnode hash table.  Just use the Jenkins hash of the vnode number,
88  * with the volume ID as an initval because it's there.  (That will
89  * make the same vnode number in different volumes hash to a different
90  * value, which would probably not even be a big deal anyway.)
91  */
92
93 #define VNODE_HASH_TABLE_BITS 11
94 #define VNODE_HASH_TABLE_SIZE opr_jhash_size(VNODE_HASH_TABLE_BITS)
95 #define VNODE_HASH_TABLE_MASK opr_jhash_mask(VNODE_HASH_TABLE_BITS)
96 private Vnode *VnodeHashTable[VNODE_HASH_TABLE_SIZE];
97 #define VNODE_HASH(volumeptr,vnodenumber)\
98     (opr_jhash_int((vnodenumber), V_id((volumeptr))) & VNODE_HASH_TABLE_MASK)
99
100
101
102 #define BAD_IGET        -1000
103
104 /* There are two separate vnode queue types defined here:
105  * Each hash conflict chain -- is singly linked, with a single head
106  * pointer. New entries are added at the beginning. Old
107  * entries are removed by linear search, which generally
108  * only occurs after a disk read).
109  * LRU chain -- is doubly linked, single head pointer.
110  * Entries are added at the head, reclaimed from the tail,
111  * or removed from anywhere in the queue.
112  */
113
114 /**
115  * add a vnode to the volume's vnode list.
116  *
117  * @param[in] vp   volume object pointer
118  * @param[in] vnp  vnode object pointer
119  *
120  * @note for DAFS, it may seem like we should be acquiring a lightweight ref
121  *       on vp, but this would actually break things.  Right now, this is ok
122  *       because we destroy all vnode cache contents during during volume
123  *       detach.
124  *
125  * @pre VOL_LOCK held
126  *
127  * @internal volume package internal use only
128  */
129 void
130 AddToVVnList(Volume * vp, Vnode * vnp)
131 {
132     if (queue_IsOnQueue(vnp))
133         return;
134
135     Vn_volume(vnp) = vp;
136     Vn_cacheCheck(vnp) = vp->cacheCheck;
137     queue_Append(&vp->vnode_list, vnp);
138     Vn_stateFlags(vnp) |= VN_ON_VVN;
139 }
140
141 /**
142  * delete a vnode from the volume's vnode list.
143  *
144  * @pre VOL_LOCK held
145  *
146  * @internal volume package internal use only
147  */
148 void
149 DeleteFromVVnList(Vnode * vnp)
150 {
151     Vn_volume(vnp) = NULL;
152
153     if (!queue_IsOnQueue(vnp))
154         return;
155
156     queue_Remove(vnp);
157     Vn_stateFlags(vnp) &= ~(VN_ON_VVN);
158 }
159
160 /**
161  * add a vnode to the end of the lru.
162  *
163  * @param[in] vcp  vnode class info object pointer
164  * @param[in] vnp  vnode object pointer
165  *
166  * @internal vnode package internal use only
167  */
168 void
169 AddToVnLRU(struct VnodeClassInfo * vcp, Vnode * vnp)
170 {
171     if (Vn_stateFlags(vnp) & VN_ON_LRU) {
172         return;
173     }
174
175     /* Add it to the circular LRU list */
176     if (vcp->lruHead == NULL)
177         Abort("VPutVnode: vcp->lruHead==NULL");
178     else {
179         vnp->lruNext = vcp->lruHead;
180         vnp->lruPrev = vcp->lruHead->lruPrev;
181         vcp->lruHead->lruPrev = vnp;
182         vnp->lruPrev->lruNext = vnp;
183         vcp->lruHead = vnp;
184     }
185
186     /* If the vnode was just deleted, put it at the end of the chain so it
187      * will be reused immediately */
188     if (vnp->delete)
189         vcp->lruHead = vnp->lruNext;
190
191     Vn_stateFlags(vnp) |= VN_ON_LRU;
192 }
193
194 /**
195  * delete a vnode from the lru.
196  *
197  * @param[in] vcp  vnode class info object pointer
198  * @param[in] vnp  vnode object pointer
199  *
200  * @internal vnode package internal use only
201  */
202 void
203 DeleteFromVnLRU(struct VnodeClassInfo * vcp, Vnode * vnp)
204 {
205     if (!(Vn_stateFlags(vnp) & VN_ON_LRU)) {
206         return;
207     }
208
209     if (vnp == vcp->lruHead)
210         vcp->lruHead = vcp->lruHead->lruNext;
211
212     if ((vnp == vcp->lruHead) ||
213         (vcp->lruHead == NULL))
214         Abort("DeleteFromVnLRU: lru chain addled!\n");
215
216     vnp->lruPrev->lruNext = vnp->lruNext;
217     vnp->lruNext->lruPrev = vnp->lruPrev;
218
219     Vn_stateFlags(vnp) &= ~(VN_ON_LRU);
220 }
221
222 /**
223  * add a vnode to the vnode hash table.
224  *
225  * @param[in] vnp  vnode object pointer
226  *
227  * @pre VOL_LOCK held
228  *
229  * @post vnode on hash
230  *
231  * @internal vnode package internal use only
232  */
233 void
234 AddToVnHash(Vnode * vnp)
235 {
236     unsigned int newHash;
237
238     if (!(Vn_stateFlags(vnp) & VN_ON_HASH)) {
239         newHash = VNODE_HASH(Vn_volume(vnp), Vn_id(vnp));
240         vnp->hashNext = VnodeHashTable[newHash];
241         VnodeHashTable[newHash] = vnp;
242         vnp->hashIndex = newHash;
243
244         Vn_stateFlags(vnp) |= VN_ON_HASH;
245     }
246 }
247
248 /**
249  * delete a vnode from the vnode hash table.
250  *
251  * @param[in] vnp
252  * @param[in] hash
253  *
254  * @pre VOL_LOCK held
255  *
256  * @post vnode removed from hash
257  *
258  * @internal vnode package internal use only
259  */
260 void
261 DeleteFromVnHash(Vnode * vnp)
262 {
263     Vnode * tvnp;
264
265     if (Vn_stateFlags(vnp) & VN_ON_HASH) {
266         tvnp = VnodeHashTable[vnp->hashIndex];
267         if (tvnp == vnp)
268             VnodeHashTable[vnp->hashIndex] = vnp->hashNext;
269         else {
270             while (tvnp && tvnp->hashNext != vnp)
271                 tvnp = tvnp->hashNext;
272             if (tvnp)
273                 tvnp->hashNext = vnp->hashNext;
274         }
275
276         vnp->hashNext = NULL;
277         vnp->hashIndex = 0;
278         Vn_stateFlags(vnp) &= ~(VN_ON_HASH);
279     }
280 }
281
282
283 /**
284  * invalidate a vnode cache entry.
285  *
286  * @param[in] avnode   vnode object pointer
287  *
288  * @pre VOL_LOCK held
289  *
290  * @post vnode metadata invalidated.
291  *       vnode removed from hash table.
292  *       DAFS: vnode state set to VN_STATE_INVALID.
293  *
294  * @internal vnode package internal use only
295  */
296 void
297 VInvalidateVnode_r(struct Vnode *avnode)
298 {
299     avnode->changed_newTime = 0;        /* don't let it get flushed out again */
300     avnode->changed_oldTime = 0;
301     avnode->delete = 0;         /* it isn't deleted, really */
302     avnode->cacheCheck = 0;     /* invalid: prevents future vnode searches from working */
303     DeleteFromVnHash(avnode);
304 #ifdef AFS_DEMAND_ATTACH_FS
305     VnChangeState_r(avnode, VN_STATE_INVALID);
306 #endif
307 }
308
309
310 /**
311  * initialize vnode cache for a given vnode class.
312  *
313  * @param[in] class    vnode class
314  * @param[in] nVnodes  size of cache
315  *
316  * @post vnode cache allocated and initialized
317  *
318  * @internal volume package internal use only
319  *
320  * @note generally called by VInitVolumePackage_r
321  *
322  * @see VInitVolumePackage_r
323  */
324 int
325 VInitVnodes(VnodeClass class, int nVnodes)
326 {
327     byte *va;
328     struct VnodeClassInfo *vcp = &VnodeClassInfo[class];
329
330     vcp->allocs = vcp->gets = vcp->reads = vcp->writes = 0;
331     vcp->cacheSize = nVnodes;
332     switch (class) {
333     case vSmall:
334         opr_Assert(CHECKSIZE_SMALLVNODE);
335         vcp->lruHead = NULL;
336         vcp->residentSize = SIZEOF_SMALLVNODE;
337         vcp->diskSize = SIZEOF_SMALLDISKVNODE;
338         vcp->magic = SMALLVNODEMAGIC;
339         break;
340     case vLarge:
341         vcp->lruHead = NULL;
342         vcp->residentSize = SIZEOF_LARGEVNODE;
343         vcp->diskSize = SIZEOF_LARGEDISKVNODE;
344         vcp->magic = LARGEVNODEMAGIC;
345         break;
346     }
347     {
348         int s = vcp->diskSize - 1;
349         int n = 0;
350         while (s)
351             s >>= 1, n++;
352         vcp->logSize = n;
353     }
354
355     if (nVnodes == 0)
356         return 0;
357
358     va = (byte *) calloc(nVnodes, vcp->residentSize);
359     opr_Assert(va != NULL);
360     while (nVnodes--) {
361         Vnode *vnp = (Vnode *) va;
362         Vn_refcount(vnp) = 0;   /* no context switches */
363         Vn_stateFlags(vnp) |= VN_ON_LRU;
364 #ifdef AFS_DEMAND_ATTACH_FS
365         CV_INIT(&Vn_stateCV(vnp), "vnode state", CV_DEFAULT, 0);
366         Vn_state(vnp) = VN_STATE_INVALID;
367         Vn_readers(vnp) = 0;
368 #else /* !AFS_DEMAND_ATTACH_FS */
369         Lock_Init(&vnp->lock);
370 #endif /* !AFS_DEMAND_ATTACH_FS */
371         vnp->changed_oldTime = 0;
372         vnp->changed_newTime = 0;
373         Vn_volume(vnp) = NULL;
374         Vn_cacheCheck(vnp) = 0;
375         vnp->delete = Vn_id(vnp) = 0;
376 #ifdef AFS_PTHREAD_ENV
377         vnp->writer = (pthread_t) 0;
378 #else /* AFS_PTHREAD_ENV */
379         vnp->writer = (PROCESS) 0;
380 #endif /* AFS_PTHREAD_ENV */
381         vnp->hashIndex = 0;
382         vnp->handle = NULL;
383         Vn_class(vnp) = vcp;
384         if (vcp->lruHead == NULL)
385             vcp->lruHead = vnp->lruNext = vnp->lruPrev = vnp;
386         else {
387             vnp->lruNext = vcp->lruHead;
388             vnp->lruPrev = vcp->lruHead->lruPrev;
389             vcp->lruHead->lruPrev = vnp;
390             vnp->lruPrev->lruNext = vnp;
391             vcp->lruHead = vnp;
392         }
393         va += vcp->residentSize;
394     }
395     return 0;
396 }
397
398
399 /**
400  * allocate an unused vnode from the lru chain.
401  *
402  * @param[in] vcp  vnode class info object pointer
403  * @param[in] vp   volume pointer
404  * @param[in] vnodeNumber new vnode number that the vnode will be used for
405  *
406  * @pre VOL_LOCK is held
407  *
408  * @post vnode object is removed from lru
409  *       vnode is disassociated with its old volume, and associated with its
410  *         new volume
411  *       vnode is removed from its old vnode hash table, and for DAFS, it is
412  *         added to its new hash table
413  *       state is set to VN_STATE_INVALID.
414  *       inode handle is released.
415  *       a reservation is held on the vnode object
416  *
417  * @note we traverse backwards along the lru circlist.  It shouldn't
418  *       be necessary to specify that nUsers == 0 since if it is in the list,
419  *       nUsers should be 0.  Things shouldn't be in lruq unless no one is
420  *       using them.
421  *
422  * @warning DAFS: VOL_LOCK is dropped while doing inode handle release
423  *
424  * @warning for non-DAFS, the vnode is _not_ hashed on the vnode hash table;
425  *          non-DAFS must hash the vnode itself after loading data
426  *
427  * @return vnode object pointer
428  */
429 Vnode *
430 VGetFreeVnode_r(struct VnodeClassInfo * vcp, struct Volume *vp,
431                 VnodeId vnodeNumber)
432 {
433     Vnode *vnp;
434
435     vnp = vcp->lruHead->lruPrev;
436 #ifdef AFS_DEMAND_ATTACH_FS
437     if (Vn_refcount(vnp) != 0 || VnIsExclusiveState(Vn_state(vnp)) ||
438         Vn_readers(vnp) != 0)
439         Abort("VGetFreeVnode_r: in-use vnode in lruq");
440 #else
441     if (Vn_refcount(vnp) != 0 || CheckLock(&vnp->lock))
442         Abort("VGetFreeVnode_r: locked vnode in lruq");
443 #endif
444     VNLog(1, 2, Vn_id(vnp), (intptr_t)vnp, 0, 0);
445
446     /*
447      * it's going to be overwritten soon enough.
448      * remove from LRU, delete hash entry, and
449      * disassociate from old parent volume before
450      * we have a chance to drop the vol glock
451      */
452     DeleteFromVnLRU(vcp, vnp);
453     DeleteFromVnHash(vnp);
454     if (Vn_volume(vnp)) {
455         DeleteFromVVnList(vnp);
456     }
457
458     /* we must re-hash the vnp _before_ we drop the glock again; otherwise,
459      * someone else might try to grab the same vnode id, and we'll both alloc
460      * a vnode object for the same vn id, bypassing vnode locking */
461     Vn_id(vnp) = vnodeNumber;
462     VnCreateReservation_r(vnp);
463     AddToVVnList(vp, vnp);
464 #ifdef AFS_DEMAND_ATTACH_FS
465     AddToVnHash(vnp);
466 #endif
467
468     /* drop the file descriptor */
469     if (vnp->handle) {
470 #ifdef AFS_DEMAND_ATTACH_FS
471         VnChangeState_r(vnp, VN_STATE_RELEASING);
472         VOL_UNLOCK;
473 #endif
474         /* release is, potentially, a highly latent operation due to a couple
475          * factors:
476          *   - ihandle package lock contention
477          *   - closing file descriptor(s) associated with ih
478          *
479          * Hance, we perform outside of the volume package lock in order to
480          * reduce the probability of contention.
481          */
482         IH_RELEASE(vnp->handle);
483 #ifdef AFS_DEMAND_ATTACH_FS
484         VOL_LOCK;
485 #endif
486     }
487
488 #ifdef AFS_DEMAND_ATTACH_FS
489     VnChangeState_r(vnp, VN_STATE_INVALID);
490 #endif
491
492     return vnp;
493 }
494
495
496 /**
497  * lookup a vnode in the vnode cache hash table.
498  *
499  * @param[in] vp       pointer to volume object
500  * @param[in] vnodeId  vnode id
501  *
502  * @pre VOL_LOCK held
503  *
504  * @post matching vnode object or NULL is returned
505  *
506  * @return vnode object pointer
507  *   @retval NULL   no matching vnode object was found in the cache
508  *
509  * @internal vnode package internal use only
510  *
511  * @note this symbol is exported strictly for fssync debug protocol use
512  */
513 Vnode *
514 VLookupVnode(Volume * vp, VnodeId vnodeId)
515 {
516     Vnode * vnp;
517     unsigned int newHash;
518
519     newHash = VNODE_HASH(vp, vnodeId);
520     for (vnp = VnodeHashTable[newHash];
521          (vnp &&
522           ((Vn_id(vnp) != vnodeId) ||
523            (Vn_volume(vnp) != vp) ||
524            (vp->cacheCheck != Vn_cacheCheck(vnp))));
525          vnp = vnp->hashNext);
526
527     return vnp;
528 }
529
530
531 Vnode *
532 VAllocVnode(Error * ec, Volume * vp, VnodeType type, VnodeId in_vnode, Unique in_unique)
533 {
534     Vnode *retVal;
535     VOL_LOCK;
536     retVal = VAllocVnode_r(ec, vp, type, in_vnode, in_unique);
537     VOL_UNLOCK;
538     return retVal;
539 }
540
541 /**
542  * allocate a new vnode.
543  *
544  * @param[out] ec    error code return
545  * @param[in]  vp    volume object pointer
546  * @param[in]  type  desired vnode type
547  * @param[in]  type  desired vnode ID (optional)
548  * @param[in]  type  desired vnode Unique (optional)
549  *
550  * @return vnode object pointer
551  *
552  * @pre VOL_LOCK held;
553  *      heavyweight ref held on vp
554  *
555  * @post vnode allocated and returned
556  */
557 Vnode *
558 VAllocVnode_r(Error * ec, Volume * vp, VnodeType type, VnodeId in_vnode, Unique in_unique)
559 {
560     Vnode *vnp;
561     VnodeId vnodeNumber;
562     int bitNumber;
563     struct VnodeClassInfo *vcp;
564     VnodeClass class;
565     Unique unique;
566     struct vnodeIndex *index;
567     unsigned int offset;
568
569 #ifdef AFS_DEMAND_ATTACH_FS
570     VolState vol_state_save;
571 #endif
572
573     *ec = 0;
574
575 #ifdef AFS_DEMAND_ATTACH_FS
576     /*
577      * once a volume has entered an error state, don't permit
578      * further operations to proceed
579      *  -- tkeiser 11/21/2007
580      */
581     VWaitExclusiveState_r(vp);
582     if (VIsErrorState(V_attachState(vp))) {
583         /* XXX is VSALVAGING acceptable here? */
584         *ec = DAFS_VSALVAGE;
585         return NULL;
586     }
587 #endif
588
589     if (programType == fileServer && !V_inUse(vp)) {
590         if (vp->specialStatus) {
591             *ec = vp->specialStatus;
592         } else {
593             *ec = VOFFLINE;
594         }
595         return NULL;
596     }
597     class = vnodeTypeToClass(type);
598     vcp = &VnodeClassInfo[class];
599
600     if (!VolumeWriteable(vp)) {
601         *ec = (bit32) VREADONLY;
602         return NULL;
603     }
604
605     if (vp->nextVnodeUnique > V_uniquifier(vp)) {
606         VUpdateVolume_r(ec, vp, 0);
607         if (*ec)
608             return NULL;
609     }
610
611     if (programType == fileServer) {
612         VAddToVolumeUpdateList_r(ec, vp);
613         if (*ec)
614             return NULL;
615     }
616
617     /*
618      * If in_vnode and in_unique are specified, we are asked to
619      * allocate a specifc vnode slot.  Used by RW replication to
620      * keep vnode IDs consistent with the master.
621      */
622
623     if (!in_vnode) {
624         int rollover = 0;
625
626         unique = vp->nextVnodeUnique++;
627         if (unique == 0) {
628             rollover = 1;       /* nextVnodeUnique rolled over */
629             vp->nextVnodeUnique = 2;    /* 1 is reserved for the root vnode */
630             unique = vp->nextVnodeUnique++;
631         }
632
633         if (vp->nextVnodeUnique > V_uniquifier(vp) || rollover) {
634             VUpdateVolume_r(ec, vp, 0);
635             if (*ec)
636                 return NULL;
637         }
638
639         /* Find a slot in the bit map */
640         bitNumber = VAllocBitmapEntry_r(ec, vp, &vp->vnodeIndex[class],
641                 VOL_ALLOC_BITMAP_WAIT);
642
643         if (*ec)
644             return NULL;
645         vnodeNumber = bitNumberToVnodeNumber(bitNumber, class);
646     } else {
647         index = &vp->vnodeIndex[class];
648         if (!in_unique) {
649             *ec = VNOVNODE;
650             return NULL;
651         }
652         /* Catch us up to where the master is */
653         if (in_unique > vp->nextVnodeUnique)
654             vp->nextVnodeUnique = in_unique+1;
655
656         if (vp->nextVnodeUnique > V_uniquifier(vp)) {
657             VUpdateVolume_r(ec, vp, 0);
658             if (*ec)
659                 return NULL;
660         }
661
662         unique = in_unique;
663         bitNumber = vnodeIdToBitNumber(in_vnode);
664         offset = bitNumber >> 3;
665
666         /* Mark vnode in use. Grow bitmap if needed. */
667         if ((offset >= index->bitmapSize)
668                 || ((*(index->bitmap + offset) & (1 << (bitNumber & 0x7))) == 0))
669             VGrowBitmap(index);
670         /* Should not happen */
671         if (*(index->bitmap + offset) & (1 << (bitNumber & 0x7))) {
672             *ec = VNOVNODE;
673             return NULL;
674         }
675
676         *(index->bitmap + offset) |= (1 << (bitNumber & 0x7));
677         vnodeNumber = in_vnode;
678     }
679
680     /*
681      * DAFS:
682      * at this point we should be assured that V_attachState(vp) is non-exclusive
683      */
684
685  vnrehash:
686     VNLog(2, 1, vnodeNumber, 0, 0, 0);
687     /* Prepare to move it to the new hash chain */
688     vnp = VLookupVnode(vp, vnodeNumber);
689     if (vnp) {
690         /* slot already exists.  May even not be in lruq (consider store file locking a file being deleted)
691          * so we may have to wait for it below */
692         VNLog(3, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
693
694         VnCreateReservation_r(vnp);
695         if (Vn_refcount(vnp) == 1) {
696             /* we're the only user */
697             /* This won't block */
698             VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, WILL_NOT_DEADLOCK);
699         } else {
700 #ifdef AFS_DEMAND_ATTACH_FS
701             /*
702              * DAFS:
703              * vnode was cached, wait for any existing exclusive ops to finish.
704              * once we have reacquired the lock, re-verify volume state.
705              *
706              * note: any vnode error state is related to the old vnode; disregard.
707              */
708             VnWaitQuiescent_r(vnp);
709             if (VIsErrorState(V_attachState(vp))) {
710                 VnUnlock(vnp, WRITE_LOCK);
711                 VnCancelReservation_r(vnp);
712                 *ec = DAFS_VSALVAGE;
713                 return NULL;
714             }
715 #endif
716
717             /* other users present; follow locking hierarchy */
718             VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, MIGHT_DEADLOCK);
719
720             /*
721              * verify state of the world hasn't changed
722              *
723              * (technically, this should never happen because cachecheck
724              *  is only updated during a volume attach, which should not
725              *  happen when refs are held)
726              */
727             if (Vn_volume(vnp)->cacheCheck != Vn_cacheCheck(vnp)) {
728                 VnUnlock(vnp, WRITE_LOCK);
729                 VnCancelReservation_r(vnp);
730                 goto vnrehash;
731             }
732         }
733
734         /* sanity check: vnode should be blank if it was deleted. If it's
735          * not blank, it is still in use somewhere; but the bitmap told us
736          * this vnode number was free, so something is wrong. */
737         if (vnp->disk.type != vNull) {
738             Error tmp;
739             Log("VAllocVnode:  addled bitmap or vnode object! (vol %" AFS_VOLID_FMT ", "
740                 "vnode %p, number %ld, type %ld)\n", afs_printable_VolumeId_lu(vp->hashid), vnp,
741                 (long)Vn_id(vnp), (long)vnp->disk.type);
742             *ec = EIO;
743             VFreeBitMapEntry_r(&tmp, vp, &vp->vnodeIndex[class], bitNumber,
744                                VOL_FREE_BITMAP_WAIT);
745             VInvalidateVnode_r(vnp);
746             VnUnlock(vnp, WRITE_LOCK);
747             VnCancelReservation_r(vnp);
748 #ifdef AFS_DEMAND_ATTACH_FS
749             VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
750 #else
751             VForceOffline_r(vp, 0);
752 #endif
753             return NULL;
754         }
755
756     } else {
757         /* no such vnode in the cache */
758
759         vnp = VGetFreeVnode_r(vcp, vp, vnodeNumber);
760
761         /* This will never block (guaranteed by check in VGetFreeVnode_r() */
762         VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, WILL_NOT_DEADLOCK);
763
764 #ifdef AFS_DEMAND_ATTACH_FS
765         VnChangeState_r(vnp, VN_STATE_ALLOC);
766 #endif
767
768         /* Sanity check:  is this vnode really not in use? */
769         {
770             afs_sfsize_t size;
771             IHandle_t *ihP = vp->vnodeIndex[class].handle;
772             FdHandle_t *fdP;
773             afs_foff_t off = vnodeIndexOffset(vcp, vnodeNumber);
774             Error tmp;
775
776             /* XXX we have a potential race here if two threads
777              * allocate new vnodes at the same time, and they
778              * both decide it's time to extend the index
779              * file size...
780              */
781 #ifdef AFS_DEMAND_ATTACH_FS
782             /*
783              * this race has been eliminated for the DAFS case
784              * using exclusive state VOL_STATE_VNODE_ALLOC
785              *
786              * if this becomes a bottleneck, there are ways to
787              * improve parallelism for this code path
788              *   -- tkeiser 11/28/2007
789              */
790             VCreateReservation_r(vp);
791             VWaitExclusiveState_r(vp);
792             vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_ALLOC);
793 #endif
794
795             VOL_UNLOCK;
796             fdP = IH_OPEN(ihP);
797             if (fdP == NULL) {
798                 Log("VAllocVnode: can't open index file!\n");
799                 *ec = ENOENT;
800                 goto error_encountered;
801             }
802             if ((size = FDH_SIZE(fdP)) < 0) {
803                 Log("VAllocVnode: can't stat index file!\n");
804                 *ec = EIO;
805                 goto error_encountered;
806             }
807             if (off + vcp->diskSize <= size) {
808               if (FDH_PREAD(fdP, &vnp->disk, vcp->diskSize, off) != vcp->diskSize) {
809                     Log("VAllocVnode: can't read index file!\n");
810                     *ec = EIO;
811                     goto error_encountered;
812                 }
813                 if (vnp->disk.type != vNull) {
814                     Log("VAllocVnode:  addled bitmap or index!\n");
815                     *ec = EIO;
816                     goto error_encountered;
817                 }
818             } else {
819                 /* growing file - grow in a reasonable increment */
820                 char *buf = malloc(16 * 1024);
821                 if (!buf) {
822                     Log("VAllocVnode: can't grow vnode index: out of memory\n");
823                     *ec = ENOMEM;
824                     goto error_encountered;
825                 }
826                 memset(buf, 0, 16 * 1024);
827                 if ((FDH_PWRITE(fdP, buf, 16 * 1024, off)) != 16 * 1024) {
828                     Log("VAllocVnode: can't grow vnode index: write failed\n");
829                     *ec = EIO;
830                     free(buf);
831                     goto error_encountered;
832                 }
833                 free(buf);
834             }
835             FDH_CLOSE(fdP);
836             VOL_LOCK;
837
838 #ifdef AFS_DEMAND_ATTACH_FS
839             VChangeState_r(vp, vol_state_save);
840             VCancelReservation_r(vp);
841 #endif
842             goto sane;
843
844
845         error_encountered:
846             /*
847              * close the file handle
848              * acquire VOL_LOCK
849              * invalidate the vnode
850              * free up the bitmap entry (although salvager should take care of it)
851              * salvage the volume
852              * drop vnode lock and refs
853              */
854             if (fdP)
855                 FDH_CLOSE(fdP);
856             VOL_LOCK;
857             VFreeBitMapEntry_r(&tmp, vp, &vp->vnodeIndex[class], bitNumber, 0 /*flags*/);
858             VInvalidateVnode_r(vnp);
859             VnUnlock(vnp, WRITE_LOCK);
860             VnCancelReservation_r(vnp);
861 #ifdef AFS_DEMAND_ATTACH_FS
862             VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
863             VCancelReservation_r(vp);
864 #else
865             VForceOffline_r(vp, 0);
866 #endif
867             return NULL;
868         }
869     sane:
870         VNLog(4, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
871 #ifndef AFS_DEMAND_ATTACH_FS
872         AddToVnHash(vnp);
873 #endif
874     }
875
876     VNLog(5, 1, (intptr_t)vnp, 0, 0, 0);
877     memset(&vnp->disk, 0, sizeof(vnp->disk));
878     vnp->changed_newTime = 0;   /* set this bit when vnode is updated */
879     vnp->changed_oldTime = 0;   /* set this on CopyOnWrite. */
880     vnp->delete = 0;
881     vnp->disk.vnodeMagic = vcp->magic;
882     vnp->disk.type = type;
883     vnp->disk.uniquifier = unique;
884     vnp->handle = NULL;
885     vcp->allocs++;
886     V_filecount(vp)++;
887 #ifdef AFS_DEMAND_ATTACH_FS
888     VnChangeState_r(vnp, VN_STATE_EXCLUSIVE);
889 #endif
890     return vnp;
891 }
892
893 /**
894  * load a vnode from disk.
895  *
896  * @param[out] ec     client error code return
897  * @param[in]  vp     volume object pointer
898  * @param[in]  vnp    vnode object pointer
899  * @param[in]  vcp    vnode class info object pointer
900  * @param[in]  class  vnode class enumeration
901  *
902  * @pre vnode is registered in appropriate data structures;
903  *      caller holds a ref on vnode; VOL_LOCK is held
904  *
905  * @post vnode data is loaded from disk.
906  *       vnode state is set to VN_STATE_ONLINE.
907  *       on failure, vnode is invalidated.
908  *
909  * @internal vnode package internal use only
910  */
911 static void
912 VnLoad(Error * ec, Volume * vp, Vnode * vnp,
913        struct VnodeClassInfo * vcp, VnodeClass class)
914 {
915     /* vnode not cached */
916     Error error;
917     int dosalv = 1;
918     ssize_t nBytes;
919     IHandle_t *ihP = vp->vnodeIndex[class].handle;
920     FdHandle_t *fdP;
921     afs_ino_str_t stmp;
922
923     *ec = 0;
924     vcp->reads++;
925
926 #ifdef AFS_DEMAND_ATTACH_FS
927     VnChangeState_r(vnp, VN_STATE_LOAD);
928 #endif
929
930     /* This will never block */
931     VnLock(vnp, WRITE_LOCK, VOL_LOCK_HELD, WILL_NOT_DEADLOCK);
932
933     VOL_UNLOCK;
934     fdP = IH_OPEN(ihP);
935     if (fdP == NULL) {
936         Log("VnLoad: can't open index dev=%u, i=%s\n", vp->device,
937             PrintInode(stmp, vp->vnodeIndex[class].handle->ih_ino));
938         *ec = VIO;
939         goto error_encountered_nolock;
940     } else if ((nBytes = FDH_PREAD(fdP, (char *)&vnp->disk, vcp->diskSize, vnodeIndexOffset(vcp, Vn_id(vnp))))
941                != vcp->diskSize) {
942         /* Don't take volume off line if the inumber is out of range
943          * or the inode table is full. */
944         if (nBytes == BAD_IGET) {
945             Log("VnLoad: bad inumber %s\n",
946                 PrintInode(stmp, vp->vnodeIndex[class].handle->ih_ino));
947             *ec = VIO;
948             dosalv = 0;
949         } else if (nBytes == -1 && errno == EIO) {
950             /* disk error; salvage */
951             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));
952         } else {
953             /* vnode is not allocated */
954             if (LogLevel >= 5)
955                 Log("VnLoad: Couldn't read vnode %u, volume %" AFS_VOLID_FMT " (%s); read %d bytes, errno %d\n",
956                     Vn_id(vnp), afs_printable_VolumeId_lu(V_id(vp)), V_name(vp), (int)nBytes, errno);
957             *ec = VNOVNODE;
958             dosalv = 0;
959         }
960         goto error_encountered_nolock;
961     }
962     FDH_CLOSE(fdP);
963     VOL_LOCK;
964
965     /* Quick check to see that the data is reasonable */
966     if (vnp->disk.vnodeMagic != vcp->magic || vnp->disk.type == vNull) {
967         if (vnp->disk.type == vNull) {
968             *ec = VNOVNODE;
969             dosalv = 0;
970         } else {
971             struct vnodeIndex *index = &vp->vnodeIndex[class];
972             unsigned int bitNumber = vnodeIdToBitNumber(Vn_id(vnp));
973             unsigned int offset = bitNumber >> 3;
974
975 #ifdef AFS_DEMAND_ATTACH_FS
976             /* Make sure the volume bitmap isn't getting updated while we are
977              * checking it */
978             VWaitExclusiveState_r(vp);
979 #endif
980
981             /* Test to see if vnode number is valid. */
982             if ((offset >= index->bitmapSize)
983                 || ((*(index->bitmap + offset) & (1 << (bitNumber & 0x7)))
984                     == 0)) {
985                 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));
986                 *ec = VNOVNODE;
987                 dosalv = 0;
988             } else {
989                 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));
990             }
991         }
992         goto error_encountered;
993     }
994
995     IH_INIT(vnp->handle, V_device(vp), afs_printable_VolumeId_lu(V_parentId(vp)), VN_GET_INO(vnp));
996     VnUnlock(vnp, WRITE_LOCK);
997 #ifdef AFS_DEMAND_ATTACH_FS
998     VnChangeState_r(vnp, VN_STATE_ONLINE);
999 #endif
1000     return;
1001
1002
1003  error_encountered_nolock:
1004     if (fdP) {
1005         FDH_REALLYCLOSE(fdP);
1006     }
1007     VOL_LOCK;
1008
1009  error_encountered:
1010     if (dosalv) {
1011 #ifdef AFS_DEMAND_ATTACH_FS
1012         VRequestSalvage_r(&error, vp, SALVSYNC_ERROR, 0);
1013 #else
1014         VForceOffline_r(vp, 0);
1015         error = VSALVAGE;
1016 #endif
1017         if (!*ec)
1018             *ec = error;
1019     }
1020
1021     VInvalidateVnode_r(vnp);
1022     VnUnlock(vnp, WRITE_LOCK);
1023 }
1024
1025 /**
1026  * store a vnode to disk.
1027  *
1028  * @param[out] ec     error code output
1029  * @param[in]  vp     volume object pointer
1030  * @param[in]  vnp    vnode object pointer
1031  * @param[in]  vcp    vnode class info object pointer
1032  * @param[in]  class  vnode class enumeration
1033  *
1034  * @pre VOL_LOCK held.
1035  *      caller holds refs to volume and vnode.
1036  *      DAFS: caller is responsible for performing state sanity checks.
1037  *
1038  * @post vnode state is stored to disk.
1039  *
1040  * @internal vnode package internal use only
1041  */
1042 static void
1043 VnStore(Error * ec, Volume * vp, Vnode * vnp,
1044         struct VnodeClassInfo * vcp, VnodeClass class)
1045 {
1046     ssize_t nBytes;
1047     afs_foff_t offset;
1048     IHandle_t *ihP = vp->vnodeIndex[class].handle;
1049     FdHandle_t *fdP;
1050     afs_ino_str_t stmp;
1051 #ifdef AFS_DEMAND_ATTACH_FS
1052     VnState vn_state_save;
1053 #endif
1054
1055     *ec = 0;
1056
1057 #ifdef AFS_DEMAND_ATTACH_FS
1058     vn_state_save = VnChangeState_r(vnp, VN_STATE_STORE);
1059 #endif
1060
1061     offset = vnodeIndexOffset(vcp, Vn_id(vnp));
1062     VOL_UNLOCK;
1063     fdP = IH_OPEN(ihP);
1064     if (fdP == NULL) {
1065         Log("VnStore: can't open index file!\n");
1066         goto error_encountered;
1067     }
1068     nBytes = FDH_PWRITE(fdP, &vnp->disk, vcp->diskSize, offset);
1069     if (nBytes != vcp->diskSize) {
1070         /* Don't force volume offline if the inumber is out of
1071          * range or the inode table is full.
1072          */
1073         FDH_REALLYCLOSE(fdP);
1074         if (nBytes == BAD_IGET) {
1075             Log("VnStore: bad inumber %s\n",
1076                 PrintInode(stmp,
1077                            vp->vnodeIndex[class].handle->ih_ino));
1078             *ec = VIO;
1079             VOL_LOCK;
1080 #ifdef AFS_DEMAND_ATTACH_FS
1081             VnChangeState_r(vnp, VN_STATE_ERROR);
1082 #endif
1083         } else {
1084             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);
1085 #ifdef AFS_DEMAND_ATTACH_FS
1086             goto error_encountered;
1087 #else
1088             VOL_LOCK;
1089             VForceOffline_r(vp, 0);
1090             *ec = VSALVAGE;
1091 #endif
1092         }
1093         return;
1094     } else {
1095         FDH_CLOSE(fdP);
1096     }
1097
1098     VOL_LOCK;
1099 #ifdef AFS_DEMAND_ATTACH_FS
1100     VnChangeState_r(vnp, vn_state_save);
1101 #endif
1102     return;
1103
1104  error_encountered:
1105 #ifdef AFS_DEMAND_ATTACH_FS
1106     /* XXX instead of dumping core, let's try to request a salvage
1107      * and just fail the putvnode */
1108     if (fdP)
1109         FDH_CLOSE(fdP);
1110     VOL_LOCK;
1111     VnChangeState_r(vnp, VN_STATE_ERROR);
1112     VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
1113 #else
1114     opr_abort();
1115 #endif
1116 }
1117
1118 /**
1119  * get a handle to a vnode object.
1120  *
1121  * @param[out] ec           error code
1122  * @param[in]  vp           volume object
1123  * @param[in]  vnodeNumber  vnode id
1124  * @param[in]  locktype     type of lock to acquire
1125  *
1126  * @return vnode object pointer
1127  *
1128  * @see VGetVnode_r
1129  */
1130 Vnode *
1131 VGetVnode(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
1132 {                               /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
1133     Vnode *retVal;
1134     VOL_LOCK;
1135     retVal = VGetVnode_r(ec, vp, vnodeNumber, locktype);
1136     VOL_UNLOCK;
1137     return retVal;
1138 }
1139
1140 /**
1141  * get a handle to a vnode object.
1142  *
1143  * @param[out] ec           error code
1144  * @param[in]  vp           volume object
1145  * @param[in]  vnodeNumber  vnode id
1146  * @param[in]  locktype     type of lock to acquire
1147  *
1148  * @return vnode object pointer
1149  *
1150  * @internal vnode package internal use only
1151  *
1152  * @pre VOL_LOCK held.
1153  *      heavyweight ref held on volume object.
1154  */
1155 Vnode *
1156 VGetVnode_r(Error * ec, Volume * vp, VnodeId vnodeNumber, int locktype)
1157 {                               /* READ_LOCK or WRITE_LOCK, as defined in lock.h */
1158     Vnode *vnp;
1159     VnodeClass class;
1160     struct VnodeClassInfo *vcp;
1161
1162     *ec = 0;
1163
1164     if (vnodeNumber == 0) {
1165         *ec = VNOVNODE;
1166         return NULL;
1167     }
1168
1169     VNLog(100, 1, vnodeNumber, 0, 0, 0);
1170
1171 #ifdef AFS_DEMAND_ATTACH_FS
1172     /*
1173      * once a volume has entered an error state, don't permit
1174      * further operations to proceed
1175      *  -- tkeiser 11/21/2007
1176      */
1177     VWaitExclusiveState_r(vp);
1178     if (VIsErrorState(V_attachState(vp))) {
1179         /* XXX is VSALVAGING acceptable here? */
1180         *ec = VSALVAGING;
1181         return NULL;
1182     }
1183 #endif
1184
1185     if (programType == fileServer && !V_inUse(vp)) {
1186         *ec = (vp->specialStatus ? vp->specialStatus : VOFFLINE);
1187
1188         /* If the volume is VBUSY (being cloned or dumped) and this is
1189          * a READ operation, then don't fail.
1190          */
1191         if ((*ec != VBUSY) || (locktype != READ_LOCK)) {
1192             return NULL;
1193         }
1194         *ec = 0;
1195     }
1196     class = vnodeIdToClass(vnodeNumber);
1197     vcp = &VnodeClassInfo[class];
1198     if (locktype == WRITE_LOCK && !VolumeWriteable(vp)) {
1199         *ec = (bit32) VREADONLY;
1200         return NULL;
1201     }
1202
1203     if (locktype == WRITE_LOCK && programType == fileServer) {
1204         VAddToVolumeUpdateList_r(ec, vp);
1205         if (*ec) {
1206             return NULL;
1207         }
1208     }
1209
1210     vcp->gets++;
1211
1212     /* See whether the vnode is in the cache. */
1213     vnp = VLookupVnode(vp, vnodeNumber);
1214     if (vnp) {
1215         /* vnode is in cache */
1216
1217         VNLog(101, 2, vnodeNumber, (intptr_t)vnp, 0, 0);
1218         VnCreateReservation_r(vnp);
1219
1220 #ifdef AFS_DEMAND_ATTACH_FS
1221         /*
1222          * this is the one DAFS case where we may run into contention.
1223          * here's the basic control flow:
1224          *
1225          * if locktype is READ_LOCK:
1226          *   wait until vnode is not exclusive
1227          *   set to VN_STATE_READ
1228          *   increment read count
1229          *   done
1230          * else
1231          *   wait until vnode is quiescent
1232          *   set to VN_STATE_EXCLUSIVE
1233          *   done
1234          */
1235         if (locktype == READ_LOCK) {
1236             VnWaitExclusiveState_r(vnp);
1237         } else {
1238             VnWaitQuiescent_r(vnp);
1239         }
1240
1241         if (VnIsErrorState(Vn_state(vnp))) {
1242             VnCancelReservation_r(vnp);
1243             *ec = VSALVAGE;
1244             return NULL;
1245         }
1246 #endif /* AFS_DEMAND_ATTACH_FS */
1247     } else {
1248         /* vnode not cached */
1249
1250         /* Not in cache; tentatively grab most distantly used one from the LRU
1251          * chain */
1252         vcp->reads++;
1253         vnp = VGetFreeVnode_r(vcp, vp, vnodeNumber);
1254
1255         /* Initialize */
1256         vnp->changed_newTime = vnp->changed_oldTime = 0;
1257         vnp->delete = 0;
1258
1259         /*
1260          * XXX for non-DAFS, there is a serious
1261          * race condition here:
1262          *
1263          * two threads can race to load a vnode.  the net
1264          * result is two struct Vnodes can be allocated
1265          * and hashed, which point to the same underlying
1266          * disk data store.  conflicting vnode locks can
1267          * thus be held concurrently.
1268          *
1269          * for non-DAFS to be safe, VOL_LOCK really shouldn't
1270          * be dropped in VnLoad.  Of course, this would likely
1271          * lead to an unacceptable slow-down.
1272          */
1273
1274         VnLoad(ec, vp, vnp, vcp, class);
1275         if (*ec) {
1276             VnCancelReservation_r(vnp);
1277             return NULL;
1278         }
1279 #ifndef AFS_DEMAND_ATTACH_FS
1280         AddToVnHash(vnp);
1281 #endif
1282         /*
1283          * DAFS:
1284          * there is no possibility for contention. we "own" this vnode.
1285          */
1286     }
1287
1288     /*
1289      * DAFS:
1290      * it is imperative that nothing drop vol lock between here
1291      * and the VnBeginRead/VnChangeState stanza below
1292      */
1293
1294     VnLock(vnp, locktype, VOL_LOCK_HELD, MIGHT_DEADLOCK);
1295
1296     /* Check that the vnode hasn't been removed while we were obtaining
1297      * the lock */
1298     VNLog(102, 2, vnodeNumber, (intptr_t) vnp, 0, 0);
1299     if ((vnp->disk.type == vNull) || (Vn_cacheCheck(vnp) == 0)) {
1300         VnUnlock(vnp, locktype);
1301         VnCancelReservation_r(vnp);
1302         *ec = VNOVNODE;
1303         /* vnode is labelled correctly by now, so we don't have to invalidate it */
1304         return NULL;
1305     }
1306
1307 #ifdef AFS_DEMAND_ATTACH_FS
1308     if (locktype == READ_LOCK) {
1309         VnBeginRead_r(vnp);
1310     } else {
1311         VnChangeState_r(vnp, VN_STATE_EXCLUSIVE);
1312     }
1313 #endif
1314
1315     if (programType == fileServer)
1316         VBumpVolumeUsage_r(Vn_volume(vnp));     /* Hack; don't know where it should be
1317                                                  * called from.  Maybe VGetVolume */
1318     return vnp;
1319 }
1320
1321
1322 int TrustVnodeCacheEntry = 1;
1323 /* This variable is bogus--when it's set to 0, the hash chains fill
1324    up with multiple versions of the same vnode.  Should fix this!! */
1325 void
1326 VPutVnode(Error * ec, Vnode * vnp)
1327 {
1328     VOL_LOCK;
1329     VPutVnode_r(ec, vnp);
1330     VOL_UNLOCK;
1331 }
1332
1333 /**
1334  * put back a handle to a vnode object.
1335  *
1336  * @param[out] ec   client error code
1337  * @param[in]  vnp  vnode object pointer
1338  *
1339  * @pre VOL_LOCK held.
1340  *      ref held on vnode.
1341  *
1342  * @post ref dropped on vnode.
1343  *       if vnode was modified or deleted, it is written out to disk
1344  *       (assuming a write lock was held).
1345  *
1346  * @internal volume package internal use only
1347  */
1348 void
1349 VPutVnode_r(Error * ec, Vnode * vnp)
1350 {
1351     int writeLocked;
1352     VnodeClass class;
1353     struct VnodeClassInfo *vcp;
1354
1355     *ec = 0;
1356     opr_Assert(Vn_refcount(vnp) != 0);
1357     class = vnodeIdToClass(Vn_id(vnp));
1358     vcp = &VnodeClassInfo[class];
1359     opr_Assert(vnp->disk.vnodeMagic == vcp->magic);
1360     VNLog(200, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
1361
1362 #ifdef AFS_DEMAND_ATTACH_FS
1363     writeLocked = (Vn_state(vnp) == VN_STATE_EXCLUSIVE);
1364 #else
1365     writeLocked = WriteLocked(&vnp->lock);
1366 #endif
1367
1368     if (writeLocked) {
1369         /* sanity checks */
1370 #ifdef AFS_PTHREAD_ENV
1371         pthread_t thisProcess = pthread_self();
1372 #else /* AFS_PTHREAD_ENV */
1373         PROCESS thisProcess;
1374         LWP_CurrentProcess(&thisProcess);
1375 #endif /* AFS_PTHREAD_ENV */
1376         VNLog(201, 2, (intptr_t) vnp,
1377               ((vnp->changed_newTime) << 1) | ((vnp->
1378                                                 changed_oldTime) << 1) | vnp->
1379               delete, 0, 0);
1380         if (thisProcess != vnp->writer)
1381             Abort("VPutVnode: Vnode at %"AFS_PTR_FMT" locked by another process!\n",
1382                   vnp);
1383
1384
1385         if (vnp->changed_oldTime || vnp->changed_newTime || vnp->delete) {
1386             Volume *vp = Vn_volume(vnp);
1387             afs_uint32 now = FT_ApproxTime();
1388             opr_Assert(Vn_cacheCheck(vnp) == vp->cacheCheck);
1389
1390             if (vnp->delete) {
1391                 /* No longer any directory entries for this vnode. Free the Vnode */
1392                 memset(&vnp->disk, 0, sizeof(vnp->disk));
1393                 /* delete flag turned off further down */
1394                 VNLog(202, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
1395             } else if (vnp->changed_newTime) {
1396                 vnp->disk.serverModifyTime = now;
1397             }
1398             if (vnp->changed_newTime)
1399             {
1400                 V_updateDate(vp) = vp->updateTime = now;
1401                 if(V_volUpdateCounter(vp)< UINT_MAX)
1402                         V_volUpdateCounter(vp)++;
1403             }
1404
1405             /* The vnode has been changed. Write it out to disk */
1406             if (!V_inUse(vp)) {
1407 #ifdef AFS_DEMAND_ATTACH_FS
1408                 VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
1409 #else
1410                 opr_Assert(V_needsSalvaged(vp));
1411                 *ec = VSALVAGE;
1412 #endif
1413             } else {
1414                 VnStore(ec, vp, vnp, vcp, class);
1415
1416                 /* If the vnode is to be deleted, and we wrote the vnode out,
1417                  * free its bitmap entry. Do after the vnode is written so we
1418                  * don't allocate from bitmap before the vnode is written
1419                  * (doing so could cause a "addled bitmap" message).
1420                  */
1421                 if (vnp->delete && !*ec) {
1422                   if (V_filecount(Vn_volume(vnp))-- < 1)
1423                       V_filecount(Vn_volume(vnp)) = 0;
1424                     VFreeBitMapEntry_r(ec, vp, &vp->vnodeIndex[class],
1425                                        vnodeIdToBitNumber(Vn_id(vnp)),
1426                                        VOL_FREE_BITMAP_WAIT);
1427                 }
1428             }
1429             vcp->writes++;
1430             vnp->changed_newTime = vnp->changed_oldTime = 0;
1431         }
1432 #ifdef AFS_DEMAND_ATTACH_FS
1433         VnChangeState_r(vnp, VN_STATE_ONLINE);
1434 #endif
1435     } else {                    /* Not write locked */
1436         if (vnp->changed_newTime || vnp->changed_oldTime || vnp->delete)
1437             Abort
1438                 ("VPutVnode: Change or delete flag for vnode "
1439                  "%"AFS_PTR_FMT" is set but vnode is not write locked!\n",
1440                  vnp);
1441 #ifdef AFS_DEMAND_ATTACH_FS
1442         VnEndRead_r(vnp);
1443 #endif
1444     }
1445
1446     /* Do not look at disk portion of vnode after this point; it may
1447      * have been deleted above */
1448     vnp->delete = 0;
1449     VnUnlock(vnp, ((writeLocked) ? WRITE_LOCK : READ_LOCK));
1450     VnCancelReservation_r(vnp);
1451 }
1452
1453 /*
1454  * Make an attempt to convert a vnode lock from write to read.
1455  * Do nothing if the vnode isn't write locked or the vnode has
1456  * been deleted.
1457  */
1458 int
1459 VVnodeWriteToRead(Error * ec, Vnode * vnp)
1460 {
1461     int retVal;
1462     VOL_LOCK;
1463     retVal = VVnodeWriteToRead_r(ec, vnp);
1464     VOL_UNLOCK;
1465     return retVal;
1466 }
1467
1468 /**
1469  * convert vnode handle from mutually exclusive to shared access.
1470  *
1471  * @param[out] ec   client error code
1472  * @param[in]  vnp  vnode object pointer
1473  *
1474  * @return unspecified use (see out argument 'ec' for error code return)
1475  *
1476  * @pre VOL_LOCK held.
1477  *      ref held on vnode.
1478  *      write lock held on vnode.
1479  *
1480  * @post read lock held on vnode.
1481  *       if vnode was modified, it has been written to disk.
1482  *
1483  * @internal volume package internal use only
1484  */
1485 int
1486 VVnodeWriteToRead_r(Error * ec, Vnode * vnp)
1487 {
1488     int writeLocked;
1489     VnodeClass class;
1490     struct VnodeClassInfo *vcp;
1491 #ifdef AFS_PTHREAD_ENV
1492     pthread_t thisProcess;
1493 #else /* AFS_PTHREAD_ENV */
1494     PROCESS thisProcess;
1495 #endif /* AFS_PTHREAD_ENV */
1496
1497     *ec = 0;
1498     opr_Assert(Vn_refcount(vnp) != 0);
1499     class = vnodeIdToClass(Vn_id(vnp));
1500     vcp = &VnodeClassInfo[class];
1501     opr_Assert(vnp->disk.vnodeMagic == vcp->magic);
1502     VNLog(300, 2, Vn_id(vnp), (intptr_t) vnp, 0, 0);
1503
1504 #ifdef AFS_DEMAND_ATTACH_FS
1505     writeLocked = (Vn_state(vnp) == VN_STATE_EXCLUSIVE);
1506 #else
1507     writeLocked = WriteLocked(&vnp->lock);
1508 #endif
1509     if (!writeLocked) {
1510         return 0;
1511     }
1512
1513
1514     VNLog(301, 2, (intptr_t) vnp,
1515           ((vnp->changed_newTime) << 1) | ((vnp->
1516                                             changed_oldTime) << 1) | vnp->
1517           delete, 0, 0);
1518
1519     /* sanity checks */
1520 #ifdef AFS_PTHREAD_ENV
1521     thisProcess = pthread_self();
1522 #else /* AFS_PTHREAD_ENV */
1523     LWP_CurrentProcess(&thisProcess);
1524 #endif /* AFS_PTHREAD_ENV */
1525     if (thisProcess != vnp->writer)
1526         Abort("VPutVnode: Vnode at %"AFS_PTR_FMT
1527               " locked by another process!\n", vnp);
1528
1529     if (vnp->delete) {
1530         return 0;
1531     }
1532     if (vnp->changed_oldTime || vnp->changed_newTime) {
1533         Volume *vp = Vn_volume(vnp);
1534         afs_uint32 now = FT_ApproxTime();
1535         opr_Assert(Vn_cacheCheck(vnp) == vp->cacheCheck);
1536         if (vnp->changed_newTime)
1537             vnp->disk.serverModifyTime = now;
1538         if (vnp->changed_newTime)
1539             V_updateDate(vp) = vp->updateTime = now;
1540
1541         /* The inode has been changed.  Write it out to disk */
1542         if (!V_inUse(vp)) {
1543 #ifdef AFS_DEMAND_ATTACH_FS
1544             VRequestSalvage_r(ec, vp, SALVSYNC_ERROR, 0);
1545 #else
1546             opr_Assert(V_needsSalvaged(vp));
1547             *ec = VSALVAGE;
1548 #endif
1549         } else {
1550             VnStore(ec, vp, vnp, vcp, class);
1551         }
1552         vcp->writes++;
1553         vnp->changed_newTime = vnp->changed_oldTime = 0;
1554     }
1555
1556     vnp->writer = 0;
1557 #ifdef AFS_DEMAND_ATTACH_FS
1558     VnChangeState_r(vnp, VN_STATE_ONLINE);
1559     VnBeginRead_r(vnp);
1560 #else
1561     ConvertWriteToReadLock(&vnp->lock);
1562 #endif
1563     return 0;
1564 }
1565
1566 /**
1567  * initial size of ihandle pointer vector.
1568  *
1569  * @see VInvalidateVnodesByVolume_r
1570  */
1571 #define IH_VEC_BASE_SIZE 256
1572
1573 /**
1574  * increment amount for growing ihandle pointer vector.
1575  *
1576  * @see VInvalidateVnodesByVolume_r
1577  */
1578 #define IH_VEC_INCREMENT 256
1579
1580 /**
1581  * Compile list of ihandles to be released/reallyclosed at a later time.
1582  *
1583  * @param[in]   vp            volume object pointer
1584  * @param[out]  vec_out       vector of ihandle pointers to be released/reallyclosed
1585  * @param[out]  vec_len_out   number of valid elements in ihandle vector
1586  *
1587  * @pre - VOL_LOCK is held
1588  *      - volume is in appropriate exclusive state (e.g. VOL_STATE_VNODE_CLOSE,
1589  *        VOL_STATE_VNODE_RELEASE)
1590  *
1591  * @post - all vnodes on VVn list are invalidated
1592  *       - ih_vec is populated with all valid ihandles
1593  *
1594  * @return operation status
1595  *    @retval 0         success
1596  *    @retval ENOMEM    out of memory
1597  *
1598  * @todo we should handle out of memory conditions more gracefully.
1599  *
1600  * @internal vnode package internal use only
1601  */
1602 static int
1603 VInvalidateVnodesByVolume_r(Volume * vp,
1604                             IHandle_t *** vec_out,
1605                             size_t * vec_len_out)
1606 {
1607     int ret = 0;
1608     Vnode *vnp, *nvnp;
1609     size_t i = 0, vec_len;
1610     IHandle_t **ih_vec, **ih_vec_new;
1611
1612 #ifdef AFS_DEMAND_ATTACH_FS
1613     VOL_UNLOCK;
1614 #endif /* AFS_DEMAND_ATTACH_FS */
1615
1616     vec_len = IH_VEC_BASE_SIZE;
1617     ih_vec = malloc(sizeof(IHandle_t *) * vec_len);
1618 #ifdef AFS_DEMAND_ATTACH_FS
1619     VOL_LOCK;
1620 #endif
1621     if (ih_vec == NULL)
1622         return ENOMEM;
1623
1624     /*
1625      * Traverse the volume's vnode list.  Pull all the ihandles out into a
1626      * thread-private array for later asynchronous processing.
1627      */
1628 #ifdef AFS_DEMAND_ATTACH_FS
1629 restart_traversal:
1630 #endif
1631     for (queue_Scan(&vp->vnode_list, vnp, nvnp, Vnode)) {
1632         if (vnp->handle != NULL) {
1633             if (i == vec_len) {
1634 #ifdef AFS_DEMAND_ATTACH_FS
1635                 VOL_UNLOCK;
1636 #endif
1637                 vec_len += IH_VEC_INCREMENT;
1638                 ih_vec_new = realloc(ih_vec, sizeof(IHandle_t *) * vec_len);
1639 #ifdef AFS_DEMAND_ATTACH_FS
1640                 VOL_LOCK;
1641 #endif
1642                 if (ih_vec_new == NULL) {
1643                     ret = ENOMEM;
1644                     goto done;
1645                 }
1646                 ih_vec = ih_vec_new;
1647 #ifdef AFS_DEMAND_ATTACH_FS
1648                 /*
1649                  * Theoretically, the volume's VVn list should not change
1650                  * because the volume is in an exclusive state.  For the
1651                  * sake of safety, we will restart the traversal from the
1652                  * the beginning (which is not expensive because we're
1653                  * deleting the items from the list as we go).
1654                  */
1655                 goto restart_traversal;
1656 #endif
1657             }
1658             ih_vec[i++] = vnp->handle;
1659             vnp->handle = NULL;
1660         }
1661         DeleteFromVVnList(vnp);
1662         VInvalidateVnode_r(vnp);
1663     }
1664
1665  done:
1666     *vec_out = ih_vec;
1667     *vec_len_out = i;
1668
1669     return ret;
1670 }
1671
1672 /* VCloseVnodeFiles - called when a volume is going off line. All open
1673  * files for vnodes in that volume are closed. This might be excessive,
1674  * since we may only be taking one volume of a volume group offline.
1675  */
1676 void
1677 VCloseVnodeFiles_r(Volume * vp)
1678 {
1679 #ifdef AFS_DEMAND_ATTACH_FS
1680     VolState vol_state_save;
1681 #endif
1682     IHandle_t ** ih_vec;
1683     size_t i, vec_len;
1684
1685 #ifdef AFS_DEMAND_ATTACH_FS
1686     vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_CLOSE);
1687 #endif /* AFS_DEMAND_ATTACH_FS */
1688
1689     /* XXX need better error handling here */
1690     opr_Verify(VInvalidateVnodesByVolume_r(vp, &ih_vec,
1691                                            &vec_len) == 0);
1692
1693     /*
1694      * DAFS:
1695      * now we drop VOL_LOCK while we perform some potentially very
1696      * expensive operations in the background
1697      */
1698 #ifdef AFS_DEMAND_ATTACH_FS
1699     VOL_UNLOCK;
1700 #endif
1701
1702     for (i = 0; i < vec_len; i++) {
1703         IH_REALLYCLOSE(ih_vec[i]);
1704         IH_RELEASE(ih_vec[i]);
1705     }
1706
1707     free(ih_vec);
1708
1709 #ifdef AFS_DEMAND_ATTACH_FS
1710     VOL_LOCK;
1711     VChangeState_r(vp, vol_state_save);
1712 #endif /* AFS_DEMAND_ATTACH_FS */
1713 }
1714
1715
1716 /**
1717  * shut down all vnode cache state for a given volume.
1718  *
1719  * @param[in] vp  volume object pointer
1720  *
1721  * @pre VOL_LOCK is held
1722  *
1723  * @post all file descriptors closed.
1724  *       all inode handles released.
1725  *       all vnode cache objects disassociated from volume.
1726  *
1727  * @note for DAFS, these operations are performed outside the vol glock under
1728  *       volume exclusive state VOL_STATE_VNODE_RELEASE.  Please further note
1729  *       that it would be a bug to acquire and release a volume reservation
1730  *       during this exclusive operation.  This is due to the fact that we are
1731  *       generally called during the refcount 1->0 transition.
1732  *
1733  * @todo we should handle failures in VInvalidateVnodesByVolume_r more
1734  *       gracefully.
1735  *
1736  * @see VInvalidateVnodesByVolume_r
1737  *
1738  * @internal this routine is internal to the volume package
1739  */
1740 void
1741 VReleaseVnodeFiles_r(Volume * vp)
1742 {
1743 #ifdef AFS_DEMAND_ATTACH_FS
1744     VolState vol_state_save;
1745 #endif
1746     IHandle_t ** ih_vec;
1747     size_t i, vec_len;
1748
1749 #ifdef AFS_DEMAND_ATTACH_FS
1750     vol_state_save = VChangeState_r(vp, VOL_STATE_VNODE_RELEASE);
1751 #endif /* AFS_DEMAND_ATTACH_FS */
1752
1753     /* XXX need better error handling here */
1754     opr_Verify(VInvalidateVnodesByVolume_r(vp, &ih_vec,
1755                                            &vec_len) == 0);
1756
1757     /*
1758      * DAFS:
1759      * now we drop VOL_LOCK while we perform some potentially very
1760      * expensive operations in the background
1761      */
1762 #ifdef AFS_DEMAND_ATTACH_FS
1763     VOL_UNLOCK;
1764 #endif
1765
1766     for (i = 0; i < vec_len; i++) {
1767         IH_RELEASE(ih_vec[i]);
1768     }
1769
1770     free(ih_vec);
1771
1772 #ifdef AFS_DEMAND_ATTACH_FS
1773     VOL_LOCK;
1774     VChangeState_r(vp, vol_state_save);
1775 #endif /* AFS_DEMAND_ATTACH_FS */
1776 }