Annotation of XNU/bsd/hfs/hfs_vhash.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: 
        !            23: /* Copyright (c) 1998 Apple Computer, Inc. All Rights Reserved */
        !            24: /*
        !            25:  * Copyright (c) 1982, 1986, 1989, 1991, 1993, 1995
        !            26:  *     The Regents of the University of California.  All rights reserved.
        !            27:  *
        !            28:  * Redistribution and use in source and binary forms, with or without
        !            29:  * modification, are permitted provided that the following conditions
        !            30:  * are met:
        !            31:  * 1. Redistributions of source code must retain the above copyright
        !            32:  *       notice, this list of conditions and the following disclaimer.
        !            33:  * 2. Redistributions in binary form must reproduce the above copyright
        !            34:  *       notice, this list of conditions and the following disclaimer in the
        !            35:  *       documentation and/or other materials provided with the distribution.
        !            36:  * 3. All advertising materials mentioning features or use of this software
        !            37:  *       must display the following acknowledgement:
        !            38:  *     This product includes software developed by the University of
        !            39:  *     California, Berkeley and its contributors.
        !            40:  * 4. Neither the name of the University nor the names of its contributors
        !            41:  *       may be used to endorse or promote products derived from this software
        !            42:  *       without specific prior written permission.
        !            43:  *
        !            44:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            45:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            46:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            47:  * ARE DISCLAIMED.     IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            48:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            49:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            50:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            51:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            52:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            53:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            54:  * SUCH DAMAGE.
        !            55:  *
        !            56:  *     @(#)hfs_vhash.c
        !            57:  *     derived from @(#)ufs_ihash.c    8.7 (Berkeley) 5/17/95
        !            58:  */
        !            59: 
        !            60: #include <sys/param.h>
        !            61: #include <sys/systm.h>
        !            62: #include <sys/vnode.h>
        !            63: #include <sys/malloc.h>
        !            64: #include <sys/proc.h>
        !            65: #include <sys/queue.h>
        !            66: 
        !            67: #include "hfs.h"
        !            68: #include "hfs_dbg.h"
        !            69: 
        !            70: 
        !            71: /*
        !            72:  * Structures associated with hfsnode cacheing.
        !            73:  */
        !            74: LIST_HEAD(vhashhead, hfsnode) *vhashtbl;
        !            75: u_long vhash;          /* size of hash table - 1 */
        !            76: #define HFSNODEHASH(device, nodeID) (&vhashtbl[((device) + (nodeID)) & vhash])
        !            77: struct slock hfs_vhash_slock;
        !            78: 
        !            79: /*
        !            80:  * Initialize hfsnode hash table.
        !            81:  */
        !            82: void
        !            83: hfs_vhashinit()
        !            84: {
        !            85: 
        !            86:        vhashtbl = hashinit(desiredvnodes, M_HFSMNT, &vhash);
        !            87:        simple_lock_init(&hfs_vhash_slock);
        !            88: }
        !            89: 
        !            90: /*
        !            91:  * Use the device/dirID/forkType tuple to find the incore hfsnode, and return a pointer
        !            92:  * to it. If it is in core, but locked, wait for it.
        !            93:  * 
        !            94:  * Acceptable forkTypes are kData, kRsrcFork, kDirectory, or kDefault which translates to either
        !            95:  * kDataFork or kDirectory
        !            96:  *
        !            97:  * While traversing the hash, expext that a hfsnode is in the midst of being allocated, if so, 
        !            98:  * then sleep and try again
        !            99:  */
        !           100: struct vnode *
        !           101: hfs_vhashget(dev, nodeID, forkType)
        !           102:        dev_t dev;
        !           103:        UInt32 nodeID;
        !           104:        UInt8   forkType;
        !           105: {
        !           106:        struct proc *p = current_proc();        /* XXX */
        !           107:        struct hfsnode *hp;
        !           108:        struct vnode *vp;
        !           109: 
        !           110:        DBG_ASSERT(forkType!=kUndefinedFork);
        !           111:        /* 
        !           112:         * Go through the hash list
        !           113:         * If a vnode is in the process of being cleaned out or being
        !           114:         * allocated, wait for it to be finished and then try again
        !           115:         */
        !           116: loop:
        !           117:        simple_lock(&hfs_vhash_slock);
        !           118:        for (hp = HFSNODEHASH(dev, nodeID)->lh_first; hp; hp = hp->h_hash.le_next) {
        !           119:                /* The vnode might be in an incomplete state, so sleep until its ready */
        !           120:                if (hp->h_nodeflags & IN_ALLOCATING) {
        !           121:                        simple_unlock(&hfs_vhash_slock);
        !           122:                        tsleep((caddr_t)hp, PINOD, "hfs_vhashlookup", 0);
        !           123:                        goto loop;
        !           124:                };
        !           125:                        
        !           126:                DBG_ASSERT(hp->h_meta != NULL);
        !           127:                if ((H_FILEID(hp) == nodeID) && (H_DEV(hp) == dev)) {
        !           128:                        /* SER XXX kDefault of meta data (ksysfile) is not assumed here */
        !           129:                        if ((H_FORKTYPE(hp) == forkType) || 
        !           130:                                        (forkType == kAnyFork) ||
        !           131:                                        ((forkType == kDefault) && ((H_FORKTYPE(hp) == kDirectory)
        !           132:                                                        || (H_FORKTYPE(hp) == kDataFork)))) {
        !           133:                                vp = HTOV(hp);
        !           134:                                simple_lock(&vp->v_interlock);
        !           135:                                simple_unlock(&hfs_vhash_slock);
        !           136:                                if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, p))
        !           137:                                        goto loop;
        !           138:                                return (vp);
        !           139:                        };
        !           140:                };
        !           141:        };
        !           142:        simple_unlock(&hfs_vhash_slock);
        !           143:        return (NULL);
        !           144: }
        !           145: 
        !           146: 
        !           147: 
        !           148: 
        !           149: /*
        !           150:  * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked.
        !           151:  * Returns the sibling meta data if it exists, elses return NULL
        !           152:  */
        !           153: void
        !           154: hfs_vhashins_sibling(dev, nodeID, hp, fm)
        !           155:        dev_t dev;
        !           156:        UInt32 nodeID;
        !           157:        struct hfsnode *hp;
        !           158:        struct hfsfilemeta **fm;
        !           159: {
        !           160:        struct vhashhead *ipp;
        !           161:        struct hfsnode *thp;
        !           162:        struct hfsfilemeta *tfm;
        !           163: 
        !           164:        DBG_ASSERT(fm != NULL);
        !           165:        DBG_ASSERT(hp != NULL);
        !           166:        DBG_ASSERT(hp->h_meta == NULL);
        !           167:        DBG_ASSERT(H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork);
        !           168: 
        !           169:        tfm = NULL;
        !           170:        lockmgr(&hp->h_lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
        !           171: 
        !           172: 
        !           173:        /* 
        !           174:         * Go through the hash list to see if a sibling exists
        !           175:         * If it does, store it to return
        !           176:         * If a vnode is in the process of being cleaned out or being
        !           177:         * allocated, wait for it to be finished and then try again
        !           178:         */
        !           179: 
        !           180:        ipp = HFSNODEHASH(dev, nodeID);
        !           181: 
        !           182: loop:
        !           183:        simple_lock(&hfs_vhash_slock);
        !           184:        for (thp = ipp->lh_first; thp; thp = thp->h_hash.le_next)       {
        !           185:                if (thp->h_nodeflags & IN_ALLOCATING) {         /* Its in the process of being allocated */
        !           186:                        simple_unlock(&hfs_vhash_slock);
        !           187:                        tsleep((caddr_t)thp, PINOD, "hfs_vhash_ins_meta", 0);
        !           188:                        goto loop;
        !           189:                };
        !           190:                        
        !           191:                DBG_ASSERT(thp->h_meta != NULL);
        !           192:                if ((H_FILEID(thp) == nodeID) && (H_DEV(thp) == dev)) {
        !           193:                        tfm = hp->h_meta = thp->h_meta;
        !           194:                        break;
        !           195:                };
        !           196:        };
        !           197:        
        !           198:        /* Add to sibling list..if it can have them */
        !           199:        if (tfm && (H_FORKTYPE(hp)==kDataFork || H_FORKTYPE(hp)==kRsrcFork)) {
        !           200:                DBG_ASSERT(tfm->h_siblinghead.cqh_first != NULL && tfm->h_siblinghead.cqh_last != NULL);
        !           201:                simple_lock(&tfm->h_siblinglock);
        !           202:                CIRCLEQ_INSERT_HEAD(&tfm->h_siblinghead, hp, h_sibling);
        !           203:                simple_unlock(&tfm->h_siblinglock);
        !           204:        };
        !           205: 
        !           206:        LIST_INSERT_HEAD(ipp, hp, h_hash);
        !           207:        simple_unlock(&hfs_vhash_slock);
        !           208:        *fm = tfm;
        !           209: }
        !           210: 
        !           211: 
        !           212: 
        !           213: /*
        !           214: * Lock the hfsnode and insert the hfsnode into the hash table, and return it locked.
        !           215:  */
        !           216: void
        !           217: hfs_vhashins(dev, nodeID, hp)
        !           218:        dev_t dev;
        !           219:        UInt32 nodeID;
        !           220:      struct hfsnode *hp;
        !           221: {
        !           222:     struct vhashhead *ipp;
        !           223: 
        !           224:     DBG_ASSERT(hp != NULL);
        !           225:     DBG_ASSERT(nodeID != 0);
        !           226: 
        !           227:     lockmgr(&hp->h_lock, LK_EXCLUSIVE, (struct slock *)0, current_proc());
        !           228: 
        !           229:     simple_lock(&hfs_vhash_slock);
        !           230:     ipp = HFSNODEHASH(dev, nodeID);
        !           231:     LIST_INSERT_HEAD(ipp, hp, h_hash);
        !           232:     simple_unlock(&hfs_vhash_slock);
        !           233: }
        !           234: 
        !           235: 
        !           236: /*
        !           237:  * Remove the hfsnode from the hash table and then checks to see if another forks exists.
        !           238:  */
        !           239: void
        !           240: hfs_vhashrem(hp)
        !           241:        struct hfsnode *hp;
        !           242: {
        !           243: 
        !           244:        DBG_ASSERT(hp != NULL);
        !           245:        DBG_ASSERT(hp->h_meta != NULL);
        !           246:        
        !           247:        simple_lock(&hfs_vhash_slock);
        !           248:        
        !           249:        /* Test to see if there are siblings, should only apply to forks */
        !           250:        if (hp->h_meta->h_siblinghead.cqh_first != NULL) {
        !           251:                simple_lock(&hp->h_meta->h_siblinglock);
        !           252:                CIRCLEQ_REMOVE(&hp->h_meta->h_siblinghead, hp, h_sibling);
        !           253:                simple_unlock(&hp->h_meta->h_siblinglock);
        !           254:        };
        !           255:        
        !           256:        LIST_REMOVE(hp, h_hash);
        !           257: 
        !           258: #if HFS_DIAGNOSTIC
        !           259:        hp->h_hash.le_next = NULL;
        !           260:        hp->h_hash.le_prev = NULL;
        !           261: #endif
        !           262: 
        !           263:        
        !           264:        simple_unlock(&hfs_vhash_slock);
        !           265: 
        !           266: 
        !           267: }
        !           268: 
        !           269: 
        !           270: /*
        !           271:  * Moves the entries from one bucket to another
        !           272:  * nodeID is the old bucket id
        !           273:  */
        !           274: void
        !           275: hfs_vhashmove(hp, oldNodeID)
        !           276:        struct hfsnode *hp;
        !           277:        UInt32 oldNodeID;
        !           278: {
        !           279:        struct vhashhead *oldHeadIndex, *newHeadIndex;
        !           280:        struct hfsnode *thp, *nextNode;
        !           281:        UInt32 newNodeID;
        !           282: 
        !           283:        DBG_ASSERT(hp != NULL);
        !           284:        DBG_ASSERT(hp->h_meta != NULL);
        !           285:        
        !           286:     newNodeID = H_FILEID(hp);
        !           287: 
        !           288:     oldHeadIndex = HFSNODEHASH(H_DEV(hp), oldNodeID);
        !           289:     newHeadIndex = HFSNODEHASH(H_DEV(hp), newNodeID);
        !           290:        
        !           291:        /* If it is moving to the same bucket...then we are done */
        !           292:     if (oldHeadIndex == newHeadIndex)
        !           293:                return;
        !           294: 
        !           295: loop:
        !           296:        
        !           297:        /* 
        !           298:         * Go through the old hash list
        !           299:         * If there is a nodeid mismatch, or the nodeid doesnt match the current bucket
        !           300:         * remove it and add it to the right bucket.
        !           301:         * If a vnode is in the process of being cleaned out or being
        !           302:         * allocated, wait for it to be finished and then try again
        !           303:         */
        !           304:        simple_lock(&hfs_vhash_slock);
        !           305:     for (nextNode = oldHeadIndex->lh_first; nextNode; )        {
        !           306:         if (nextNode->h_nodeflags & IN_ALLOCATING) {           /* Its in the process of being allocated */
        !           307:                        simple_unlock(&hfs_vhash_slock);
        !           308:             tsleep((caddr_t)nextNode, PINOD, "hfs_vhashmove", 0);
        !           309:                        goto loop;
        !           310:                        };
        !           311:                        
        !           312:         DBG_ASSERT(nextNode->h_meta != NULL);
        !           313:                thp = nextNode;
        !           314:         nextNode = nextNode->h_hash.le_next;
        !           315:                if (newNodeID == H_FILEID(thp)) {
        !           316:                        LIST_REMOVE(thp, h_hash);
        !           317:             thp->h_hash.le_next = NULL;
        !           318:             thp->h_hash.le_next = NULL;
        !           319:             LIST_INSERT_HEAD(newHeadIndex, thp, h_hash);
        !           320:                        };
        !           321:                };
        !           322:        
        !           323:        simple_unlock(&hfs_vhash_slock);
        !           324: }
        !           325: 
        !           326: #if HFS_DIAGNOSTIC
        !           327: /*
        !           328:  * This will test the hash entry for a given hfsnode
        !           329:  * It will test:
        !           330:  *             1. The uniqei existance of the node
        !           331:  *             2. All other nodes, proper membership to the hash
        !           332:  *             3. Proper termination of the hash
        !           333:  *             4. All members have a non-null h_meta
        !           334:  */
        !           335: void hfs_vhash_dbg(hp)
        !           336:        struct hfsnode *hp;
        !           337: {
        !           338:        struct proc *p = current_proc();        /* XXX */
        !           339:        struct vnode *vp;
        !           340:        struct hfsnode *thp, *tthp;
        !           341:        int                     maxsiblings = 1;
        !           342:        int                     wasFound = false;
        !           343:        struct vhashhead *ipp, *jpp;
        !           344:        dev_t           dev = H_DEV(hp);
        !           345:        UInt32          nodeID = H_FILEID(hp);
        !           346:        UInt8           forkType = H_FORKTYPE(hp);
        !           347:        u_long          forksfound = 0;
        !           348:        
        !           349:        if (forkType==kDataFork || forkType==kRsrcFork)
        !           350:                maxsiblings++;
        !           351:                
        !           352:        if (hp == NULL)
        !           353:        DEBUG_BREAK_MSG(("hash_dgh: Null hfsnode"));
        !           354:        /* 
        !           355:         * Go through the hash list
        !           356:         * If a vnode is in the process of being cleaned out or being
        !           357:         * allocated, wait for it to be finished and then try again
        !           358:         */
        !           359:        ipp = HFSNODEHASH(dev, nodeID);
        !           360: 
        !           361: loop:
        !           362:        simple_lock(&hfs_vhash_slock);
        !           363:        for (thp = ipp->lh_first; thp; thp = thp->h_hash.le_next)       {
        !           364:                if (thp->h_nodeflags & IN_ALLOCATING) {         /* Its in the process of being allocated */
        !           365:                        simple_unlock(&hfs_vhash_slock);
        !           366:                        tsleep((caddr_t)thp, PINOD, "hfs_vhash_ins_meta", 0);
        !           367:                        goto loop;
        !           368:                };
        !           369:                        
        !           370:                if (thp->h_meta == NULL)
        !           371:                DEBUG_BREAK_MSG(("hash_dgh: Null hfs_meta"));
        !           372:            jpp = (HFSNODEHASH(H_DEV(thp), H_FILEID(thp)));
        !           373:            if (ipp != jpp)
        !           374:                DEBUG_BREAK_MSG(("hash_dgh: Member on wrong hash"));
        !           375: 
        !           376:                if ((H_FILEID(thp) == nodeID) && (H_DEV(thp) == dev)) {
        !           377:                        maxsiblings--;
        !           378:                        if (maxsiblings < 0)
        !           379:                        DEBUG_BREAK_MSG(("hash_dgh: Too many siblings"));
        !           380:                    if ((1<<H_FORKTYPE(thp)) & forksfound)
        !           381:                        DEBUG_BREAK_MSG(("hash_dgh: Fork already found"));
        !           382:                    forksfound |= (1<<H_FORKTYPE(thp));
        !           383:                    
        !           384:                    if (H_FORKTYPE(thp) == forkType) {
        !           385:                                if (wasFound == true)
        !           386:                                DEBUG_BREAK_MSG(("hash_dgh: Already found"));
        !           387:                        wasFound = true;
        !           388:                    };
        !           389:                };
        !           390:        };
        !           391:        simple_unlock(&hfs_vhash_slock);
        !           392: 
        !           393:        if (! wasFound)
        !           394:        DEBUG_BREAK_MSG(("hash_dgh: Not found"));
        !           395: 
        !           396: }
        !           397: 
        !           398: #endif /* HFS_DIAGNOSTIC */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.