[BACK]Return to ext2fs_alloc.c CVS log [TXT][DIR] Up to [local] / sys / ufs / ext2fs

Annotation of sys/ufs/ext2fs/ext2fs_alloc.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: ext2fs_alloc.c,v 1.24 2007/06/22 09:55:17 jasper Exp $        */
        !             2: /*     $NetBSD: ext2fs_alloc.c,v 1.10 2001/07/05 08:38:27 toshii Exp $ */
        !             3:
        !             4: /*
        !             5:  * Copyright (c) 1997 Manuel Bouyer.
        !             6:  * Copyright (c) 1982, 1986, 1989, 1993
        !             7:  *     The Regents of the University of California.  All rights reserved.
        !             8:  *
        !             9:  * Redistribution and use in source and binary forms, with or without
        !            10:  * modification, are permitted provided that the following conditions
        !            11:  * are met:
        !            12:  * 1. Redistributions of source code must retain the above copyright
        !            13:  *    notice, this list of conditions and the following disclaimer.
        !            14:  * 2. Redistributions in binary form must reproduce the above copyright
        !            15:  *    notice, this list of conditions and the following disclaimer in the
        !            16:  *    documentation and/or other materials provided with the distribution.
        !            17:  * 3. Neither the name of the University nor the names of its contributors
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            31:  * SUCH DAMAGE.
        !            32:  *
        !            33:  *     @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94
        !            34:  *  Modified for ext2fs by Manuel Bouyer.
        !            35:  */
        !            36:
        !            37: #include <sys/param.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/buf.h>
        !            40: #include <sys/proc.h>
        !            41: #include <sys/vnode.h>
        !            42: #include <sys/mount.h>
        !            43: #include <sys/kernel.h>
        !            44: #include <sys/syslog.h>
        !            45:
        !            46: #include <ufs/ufs/quota.h>
        !            47: #include <ufs/ufs/inode.h>
        !            48: #include <ufs/ufs/ufsmount.h>
        !            49: #include <ufs/ufs/ufs_extern.h>
        !            50:
        !            51: #include <ufs/ext2fs/ext2fs.h>
        !            52: #include <ufs/ext2fs/ext2fs_extern.h>
        !            53:
        !            54: u_long ext2gennumber;
        !            55:
        !            56: static int32_t ext2fs_alloccg(struct inode *, int, int32_t, int);
        !            57: static u_long  ext2fs_dirpref(struct m_ext2fs *);
        !            58: static void    ext2fs_fserr(struct m_ext2fs *, uid_t, char *);
        !            59: static u_long  ext2fs_hashalloc(struct inode *, int, long, int,
        !            60:                    int32_t (*)(struct inode *, int, int32_t, int));
        !            61: static int32_t ext2fs_nodealloccg(struct inode *, int, int32_t, int);
        !            62: static int32_t ext2fs_mapsearch(struct m_ext2fs *, char *, int32_t);
        !            63:
        !            64: /*
        !            65:  * Allocate a block in the file system.
        !            66:  *
        !            67:  * A preference may be optionally specified. If a preference is given
        !            68:  * the following hierarchy is used to allocate a block:
        !            69:  *   1) allocate the requested block.
        !            70:  *   2) allocate a rotationally optimal block in the same cylinder.
        !            71:  *   3) allocate a block in the same cylinder group.
        !            72:  *   4) quadratically rehash into other cylinder groups, until an
        !            73:  *       available block is located.
        !            74:  * If no block preference is given the following hierarchy is used
        !            75:  * to allocate a block:
        !            76:  *   1) allocate a block in the cylinder group that contains the
        !            77:  *       inode for the file.
        !            78:  *   2) quadratically rehash into other cylinder groups, until an
        !            79:  *       available block is located.
        !            80:  */
        !            81: int
        !            82: ext2fs_alloc(struct inode *ip, int32_t lbn, int32_t bpref,
        !            83:     struct ucred *cred, int32_t *bnp)
        !            84: {
        !            85:        struct m_ext2fs *fs;
        !            86:        int32_t bno;
        !            87:        int cg;
        !            88:
        !            89:        *bnp = 0;
        !            90:        fs = ip->i_e2fs;
        !            91: #ifdef DIAGNOSTIC
        !            92:        if (cred == NOCRED)
        !            93:                panic("ext2fs_alloc: missing credential");
        !            94: #endif /* DIAGNOSTIC */
        !            95:        if (fs->e2fs.e2fs_fbcount == 0)
        !            96:                goto nospace;
        !            97:        if (cred->cr_uid != 0 && freespace(fs) <= 0)
        !            98:                goto nospace;
        !            99:        if (bpref >= fs->e2fs.e2fs_bcount)
        !           100:                bpref = 0;
        !           101:        if (bpref == 0)
        !           102:                cg = ino_to_cg(fs, ip->i_number);
        !           103:        else
        !           104:                cg = dtog(fs, bpref);
        !           105:        bno = (int32_t)ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
        !           106:                                                 ext2fs_alloccg);
        !           107:        if (bno > 0) {
        !           108:                ip->i_e2fs_nblock += btodb(fs->e2fs_bsize);
        !           109:                ip->i_flag |= IN_CHANGE | IN_UPDATE;
        !           110:                *bnp = bno;
        !           111:                return (0);
        !           112:        }
        !           113: nospace:
        !           114:        ext2fs_fserr(fs, cred->cr_uid, "file system full");
        !           115:        uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
        !           116:        return (ENOSPC);
        !           117: }
        !           118:
        !           119: /*
        !           120:  * Allocate an inode in the file system.
        !           121:  *
        !           122:  * If allocating a directory, use ext2fs_dirpref to select the inode.
        !           123:  * If allocating in a directory, the following hierarchy is followed:
        !           124:  *   1) allocate the preferred inode.
        !           125:  *   2) allocate an inode in the same cylinder group.
        !           126:  *   3) quadratically rehash into other cylinder groups, until an
        !           127:  *       available inode is located.
        !           128:  * If no inode preference is given the following hierarchy is used
        !           129:  * to allocate an inode:
        !           130:  *   1) allocate an inode in cylinder group 0.
        !           131:  *   2) quadratically rehash into other cylinder groups, until an
        !           132:  *       available inode is located.
        !           133:  */
        !           134: int
        !           135: ext2fs_inode_alloc(struct inode *pip, mode_t mode, struct ucred *cred,
        !           136:     struct vnode **vpp)
        !           137: {
        !           138:        struct vnode *pvp;
        !           139:        struct m_ext2fs *fs;
        !           140:        struct inode *ip;
        !           141:        ino_t ino, ipref;
        !           142:        int cg, error;
        !           143:
        !           144:        *vpp = NULL;
        !           145:        pvp = ITOV(pip);
        !           146:        fs = pip->i_e2fs;
        !           147:        if (fs->e2fs.e2fs_ficount == 0)
        !           148:                goto noinodes;
        !           149:
        !           150:        if ((mode & IFMT) == IFDIR)
        !           151:                cg = ext2fs_dirpref(fs);
        !           152:        else
        !           153:                cg = ino_to_cg(fs, pip->i_number);
        !           154:        ipref = cg * fs->e2fs.e2fs_ipg + 1;
        !           155:        ino = (ino_t)ext2fs_hashalloc(pip, cg, (long)ipref, mode, ext2fs_nodealloccg);
        !           156:        if (ino == 0)
        !           157:                goto noinodes;
        !           158:        error = VFS_VGET(pvp->v_mount, ino, vpp);
        !           159:        if (error) {
        !           160:                ext2fs_inode_free(pip, ino, mode);
        !           161:                return (error);
        !           162:        }
        !           163:        ip = VTOI(*vpp);
        !           164:        if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 0) {
        !           165:                printf("mode = 0%o, nlinks %d, inum = %d, fs = %s\n",
        !           166:                        ip->i_e2fs_mode, ip->i_e2fs_nlink, ip->i_number, fs->e2fs_fsmnt);
        !           167:                panic("ext2fs_valloc: dup alloc");
        !           168:        }
        !           169:
        !           170:        bzero(ip->i_e2din, sizeof(struct ext2fs_dinode));
        !           171:
        !           172:        /*
        !           173:         * Set up a new generation number for this inode.
        !           174:         */
        !           175:        if (++ext2gennumber < (u_long)time_second)
        !           176:                ext2gennumber = time_second;
        !           177:        ip->i_e2fs_gen = ext2gennumber;
        !           178:        return (0);
        !           179: noinodes:
        !           180:        ext2fs_fserr(fs, cred->cr_uid, "out of inodes");
        !           181:        uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
        !           182:        return (ENOSPC);
        !           183: }
        !           184:
        !           185: /*
        !           186:  * Find a cylinder to place a directory.
        !           187:  *
        !           188:  * The policy implemented by this algorithm is to select from
        !           189:  * among those cylinder groups with above the average number of
        !           190:  * free inodes, the one with the smallest number of directories.
        !           191:  */
        !           192: static u_long
        !           193: ext2fs_dirpref(struct m_ext2fs *fs)
        !           194: {
        !           195:        int cg, maxspace, mincg, avgifree;
        !           196:
        !           197:        avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg;
        !           198:        maxspace = 0;
        !           199:        mincg = -1;
        !           200:        for (cg = 0; cg < fs->e2fs_ncg; cg++)
        !           201:                if ( fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) {
        !           202:                        if (mincg == -1 || fs->e2fs_gd[cg].ext2bgd_nbfree > maxspace) {
        !           203:                                mincg = cg;
        !           204:                                maxspace = fs->e2fs_gd[cg].ext2bgd_nbfree;
        !           205:                        }
        !           206:                }
        !           207:        return mincg;
        !           208: }
        !           209:
        !           210: /*
        !           211:  * Select the desired position for the next block in a file.  The file is
        !           212:  * logically divided into sections. The first section is composed of the
        !           213:  * direct blocks. Each additional section contains fs_maxbpg blocks.
        !           214:  *
        !           215:  * If no blocks have been allocated in the first section, the policy is to
        !           216:  * request a block in the same cylinder group as the inode that describes
        !           217:  * the file. Otherwise, the policy is to try to allocate the blocks
        !           218:  * contigously. The two fields of the ext2 inode extension (see
        !           219:  * ufs/ufs/inode.h) help this.
        !           220:  */
        !           221: int32_t
        !           222: ext2fs_blkpref(struct inode *ip, int32_t lbn, int indx, int32_t *bap)
        !           223: {
        !           224:        struct m_ext2fs *fs;
        !           225:        int cg, i;
        !           226:
        !           227:        fs = ip->i_e2fs;
        !           228:        /*
        !           229:         * if we are doing contigous lbn allocation, try to alloc blocks
        !           230:         * contigously on disk
        !           231:         */
        !           232:
        !           233:        if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) {
        !           234:                return ip->i_e2fs_last_blk + 1;
        !           235:        }
        !           236:
        !           237:        /*
        !           238:         * bap, if provided, gives us a list of blocks to which we want to
        !           239:         * stay close
        !           240:         */
        !           241:
        !           242:        if (bap) {
        !           243:                for (i = indx; i >= 0 ; i--) {
        !           244:                        if (bap[i]) {
        !           245:                                return fs2h32(bap[i]) + 1;
        !           246:                        }
        !           247:                }
        !           248:        }
        !           249:
        !           250:        /* fall back to the first block of the cylinder containing the inode */
        !           251:
        !           252:        cg = ino_to_cg(fs, ip->i_number);
        !           253:        return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1;
        !           254: }
        !           255:
        !           256: /*
        !           257:  * Implement the cylinder overflow algorithm.
        !           258:  *
        !           259:  * The policy implemented by this algorithm is:
        !           260:  *   1) allocate the block in its requested cylinder group.
        !           261:  *   2) quadratically rehash on the cylinder group number.
        !           262:  *   3) brute force search for a free block.
        !           263:  */
        !           264: static u_long
        !           265: ext2fs_hashalloc(struct inode *ip, int cg, long pref, int size,
        !           266:     int32_t (*allocator)(struct inode *, int, int32_t, int))
        !           267: {
        !           268:        struct m_ext2fs *fs;
        !           269:        long result;
        !           270:        int i, icg = cg;
        !           271:
        !           272:        fs = ip->i_e2fs;
        !           273:        /*
        !           274:         * 1: preferred cylinder group
        !           275:         */
        !           276:        result = (*allocator)(ip, cg, pref, size);
        !           277:        if (result)
        !           278:                return (result);
        !           279:        /*
        !           280:         * 2: quadratic rehash
        !           281:         */
        !           282:        for (i = 1; i < fs->e2fs_ncg; i *= 2) {
        !           283:                cg += i;
        !           284:                if (cg >= fs->e2fs_ncg)
        !           285:                        cg -= fs->e2fs_ncg;
        !           286:                result = (*allocator)(ip, cg, 0, size);
        !           287:                if (result)
        !           288:                        return (result);
        !           289:        }
        !           290:        /*
        !           291:         * 3: brute force search
        !           292:         * Note that we start at i == 2, since 0 was checked initially,
        !           293:         * and 1 is always checked in the quadratic rehash.
        !           294:         */
        !           295:        cg = (icg + 2) % fs->e2fs_ncg;
        !           296:        for (i = 2; i < fs->e2fs_ncg; i++) {
        !           297:                result = (*allocator)(ip, cg, 0, size);
        !           298:                if (result)
        !           299:                        return (result);
        !           300:                cg++;
        !           301:                if (cg == fs->e2fs_ncg)
        !           302:                        cg = 0;
        !           303:        }
        !           304:        return (0);
        !           305: }
        !           306:
        !           307: /*
        !           308:  * Determine whether a block can be allocated.
        !           309:  *
        !           310:  * Check to see if a block of the appropriate size is available,
        !           311:  * and if it is, allocate it.
        !           312:  */
        !           313:
        !           314: static int32_t
        !           315: ext2fs_alloccg(struct inode *ip, int cg, int32_t bpref, int size)
        !           316: {
        !           317:        struct m_ext2fs *fs;
        !           318:        char *bbp;
        !           319:        struct buf *bp;
        !           320:        int error, bno, start, end, loc;
        !           321:
        !           322:        fs = ip->i_e2fs;
        !           323:        if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
        !           324:                return (0);
        !           325:        error = bread(ip->i_devvp, fsbtodb(fs,
        !           326:                fs->e2fs_gd[cg].ext2bgd_b_bitmap),
        !           327:                (int)fs->e2fs_bsize, NOCRED, &bp);
        !           328:        if (error || fs->e2fs_gd[cg].ext2bgd_nbfree == 0) {
        !           329:                brelse(bp);
        !           330:                return (0);
        !           331:        }
        !           332:        bbp = (char *)bp->b_data;
        !           333:
        !           334:        if (dtog(fs, bpref) != cg)
        !           335:                bpref = 0;
        !           336:        if (bpref != 0) {
        !           337:                bpref = dtogd(fs, bpref);
        !           338:                /*
        !           339:                 * if the requested block is available, use it
        !           340:                 */
        !           341:                if (isclr(bbp, bpref)) {
        !           342:                        bno = bpref;
        !           343:                        goto gotit;
        !           344:                }
        !           345:        }
        !           346:        /*
        !           347:         * no blocks in the requested cylinder, so take next
        !           348:         * available one in this cylinder group.
        !           349:         * first try to get 8 contigous blocks, then fall back to a single
        !           350:         * block.
        !           351:         */
        !           352:        if (bpref)
        !           353:                start = dtogd(fs, bpref) / NBBY;
        !           354:        else
        !           355:                start = 0;
        !           356:        end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
        !           357:        for (loc = start; loc < end; loc++) {
        !           358:                if (bbp[loc] == 0) {
        !           359:                        bno = loc * NBBY;
        !           360:                        goto gotit;
        !           361:                }
        !           362:        }
        !           363:        for (loc = 0; loc < start; loc++) {
        !           364:                if (bbp[loc] == 0) {
        !           365:                        bno = loc * NBBY;
        !           366:                        goto gotit;
        !           367:                }
        !           368:        }
        !           369:
        !           370:        bno = ext2fs_mapsearch(fs, bbp, bpref);
        !           371:        if (bno < 0)
        !           372:                return (0);
        !           373: gotit:
        !           374: #ifdef DIAGNOSTIC
        !           375:        if (isset(bbp, (long)bno)) {
        !           376:                printf("ext2fs_alloccgblk: cg=%d bno=%d fs=%s\n",
        !           377:                        cg, bno, fs->e2fs_fsmnt);
        !           378:                panic("ext2fs_alloccg: dup alloc");
        !           379:        }
        !           380: #endif
        !           381:        setbit(bbp, (long)bno);
        !           382:        fs->e2fs.e2fs_fbcount--;
        !           383:        fs->e2fs_gd[cg].ext2bgd_nbfree--;
        !           384:        fs->e2fs_fmod = 1;
        !           385:        bdwrite(bp);
        !           386:        return (cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno);
        !           387: }
        !           388:
        !           389: /*
        !           390:  * Determine whether an inode can be allocated.
        !           391:  *
        !           392:  * Check to see if an inode is available, and if it is,
        !           393:  * allocate it using the following policy:
        !           394:  *   1) allocate the requested inode.
        !           395:  *   2) allocate the next available inode after the requested
        !           396:  *       inode in the specified cylinder group.
        !           397:  */
        !           398: static int32_t
        !           399: ext2fs_nodealloccg(struct inode *ip, int cg, int32_t ipref, int mode)
        !           400: {
        !           401:        struct m_ext2fs *fs;
        !           402:        char *ibp;
        !           403:        struct buf *bp;
        !           404:        int error, start, len, loc, map, i;
        !           405:
        !           406:        ipref--; /* to avoid a lot of (ipref -1) */
        !           407:        fs = ip->i_e2fs;
        !           408:        if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
        !           409:                return (0);
        !           410:        error = bread(ip->i_devvp, fsbtodb(fs,
        !           411:                fs->e2fs_gd[cg].ext2bgd_i_bitmap),
        !           412:                (int)fs->e2fs_bsize, NOCRED, &bp);
        !           413:        if (error) {
        !           414:                brelse(bp);
        !           415:                return (0);
        !           416:        }
        !           417:        ibp = (char *)bp->b_data;
        !           418:        if (ipref) {
        !           419:                ipref %= fs->e2fs.e2fs_ipg;
        !           420:                if (isclr(ibp, ipref))
        !           421:                        goto gotit;
        !           422:        }
        !           423:        start = ipref / NBBY;
        !           424:        len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY);
        !           425:        loc = skpc(0xff, len, &ibp[start]);
        !           426:        if (loc == 0) {
        !           427:                len = start + 1;
        !           428:                start = 0;
        !           429:                loc = skpc(0xff, len, &ibp[0]);
        !           430:                if (loc == 0) {
        !           431:                        printf("cg = %d, ipref = %d, fs = %s\n",
        !           432:                                cg, ipref, fs->e2fs_fsmnt);
        !           433:                        panic("ext2fs_nodealloccg: map corrupted");
        !           434:                        /* NOTREACHED */
        !           435:                }
        !           436:        }
        !           437:        i = start + len - loc;
        !           438:        map = ibp[i];
        !           439:        ipref = i * NBBY;
        !           440:        for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
        !           441:                if ((map & i) == 0) {
        !           442:                        goto gotit;
        !           443:                }
        !           444:        }
        !           445:        printf("fs = %s\n", fs->e2fs_fsmnt);
        !           446:        panic("ext2fs_nodealloccg: block not in map");
        !           447:        /* NOTREACHED */
        !           448: gotit:
        !           449:        setbit(ibp, ipref);
        !           450:        fs->e2fs.e2fs_ficount--;
        !           451:        fs->e2fs_gd[cg].ext2bgd_nifree--;
        !           452:        fs->e2fs_fmod = 1;
        !           453:        if ((mode & IFMT) == IFDIR) {
        !           454:                fs->e2fs_gd[cg].ext2bgd_ndirs++;
        !           455:        }
        !           456:        bdwrite(bp);
        !           457:        return (cg * fs->e2fs.e2fs_ipg + ipref +1);
        !           458: }
        !           459:
        !           460: /*
        !           461:  * Free a block.
        !           462:  *
        !           463:  * The specified block is placed back in the
        !           464:  * free map.
        !           465:  */
        !           466: void
        !           467: ext2fs_blkfree(struct inode *ip, int32_t bno)
        !           468: {
        !           469:        struct m_ext2fs *fs;
        !           470:        char *bbp;
        !           471:        struct buf *bp;
        !           472:        int error, cg;
        !           473:
        !           474:        fs = ip->i_e2fs;
        !           475:        cg = dtog(fs, bno);
        !           476:        if ((u_int)bno >= fs->e2fs.e2fs_bcount) {
        !           477:                printf("bad block %d, ino %d\n", bno, ip->i_number);
        !           478:                ext2fs_fserr(fs, ip->i_e2fs_uid, "bad block");
        !           479:                return;
        !           480:        }
        !           481:        error = bread(ip->i_devvp,
        !           482:                fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
        !           483:                (int)fs->e2fs_bsize, NOCRED, &bp);
        !           484:        if (error) {
        !           485:                brelse(bp);
        !           486:                return;
        !           487:        }
        !           488:        bbp = (char *)bp->b_data;
        !           489:        bno = dtogd(fs, bno);
        !           490:        if (isclr(bbp, bno)) {
        !           491:                printf("dev = 0x%x, block = %d, fs = %s\n",
        !           492:                        ip->i_dev, bno, fs->e2fs_fsmnt);
        !           493:                panic("blkfree: freeing free block");
        !           494:        }
        !           495:        clrbit(bbp, bno);
        !           496:        fs->e2fs.e2fs_fbcount++;
        !           497:        fs->e2fs_gd[cg].ext2bgd_nbfree++;
        !           498:
        !           499:        fs->e2fs_fmod = 1;
        !           500:        bdwrite(bp);
        !           501: }
        !           502:
        !           503: /*
        !           504:  * Free an inode.
        !           505:  *
        !           506:  * The specified inode is placed back in the free map.
        !           507:  */
        !           508: int
        !           509: ext2fs_inode_free(struct inode *pip, ino_t ino, mode_t mode)
        !           510: {
        !           511:        struct m_ext2fs *fs;
        !           512:        char *ibp;
        !           513:        struct buf *bp;
        !           514:        int error, cg;
        !           515:
        !           516:        fs = pip->i_e2fs;
        !           517:        if ((u_int)ino > fs->e2fs.e2fs_icount || (u_int)ino < EXT2_FIRSTINO)
        !           518:                panic("ifree: range: dev = 0x%x, ino = %d, fs = %s",
        !           519:                        pip->i_dev, ino, fs->e2fs_fsmnt);
        !           520:        cg = ino_to_cg(fs, ino);
        !           521:        error = bread(pip->i_devvp,
        !           522:                fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
        !           523:                (int)fs->e2fs_bsize, NOCRED, &bp);
        !           524:        if (error) {
        !           525:                brelse(bp);
        !           526:                return (0);
        !           527:        }
        !           528:        ibp = (char *)bp->b_data;
        !           529:        ino = (ino - 1) % fs->e2fs.e2fs_ipg;
        !           530:        if (isclr(ibp, ino)) {
        !           531:                printf("dev = 0x%x, ino = %d, fs = %s\n",
        !           532:                        pip->i_dev, ino, fs->e2fs_fsmnt);
        !           533:                if (fs->e2fs_ronly == 0)
        !           534:                        panic("ifree: freeing free inode");
        !           535:        }
        !           536:        clrbit(ibp, ino);
        !           537:        fs->e2fs.e2fs_ficount++;
        !           538:        fs->e2fs_gd[cg].ext2bgd_nifree++;
        !           539:        if ((mode & IFMT) == IFDIR) {
        !           540:                fs->e2fs_gd[cg].ext2bgd_ndirs--;
        !           541:        }
        !           542:        fs->e2fs_fmod = 1;
        !           543:        bdwrite(bp);
        !           544:        return (0);
        !           545: }
        !           546:
        !           547: /*
        !           548:  * Find a block in the specified cylinder group.
        !           549:  *
        !           550:  * It is a panic if a request is made to find a block if none are
        !           551:  * available.
        !           552:  */
        !           553:
        !           554: static int32_t
        !           555: ext2fs_mapsearch(struct m_ext2fs *fs, char *bbp, int32_t bpref)
        !           556: {
        !           557:        int32_t bno;
        !           558:        int start, len, loc, i, map;
        !           559:
        !           560:        /*
        !           561:         * find the fragment by searching through the free block
        !           562:         * map for an appropriate bit pattern
        !           563:         */
        !           564:        if (bpref)
        !           565:                start = dtogd(fs, bpref) / NBBY;
        !           566:        else
        !           567:                start = 0;
        !           568:        len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
        !           569:        loc = skpc(0xff, len, &bbp[start]);
        !           570:        if (loc == 0) {
        !           571:                len = start + 1;
        !           572:                start = 0;
        !           573:                loc = skpc(0xff, len, &bbp[start]);
        !           574:                if (loc == 0) {
        !           575:                        printf("start = %d, len = %d, fs = %s\n",
        !           576:                                start, len, fs->e2fs_fsmnt);
        !           577:                        panic("ext2fs_alloccg: map corrupted");
        !           578:                        /* NOTREACHED */
        !           579:                }
        !           580:        }
        !           581:        i = start + len - loc;
        !           582:        map = bbp[i];
        !           583:        bno = i * NBBY;
        !           584:        for (i = 1; i < (1 << NBBY); i <<= 1, bno++) {
        !           585:                if ((map & i) == 0)
        !           586:                        return (bno);
        !           587:        }
        !           588:        printf("fs = %s\n", fs->e2fs_fsmnt);
        !           589:        panic("ext2fs_mapsearch: block not in map");
        !           590:        /* NOTREACHED */
        !           591: }
        !           592:
        !           593: /*
        !           594:  * Fserr prints the name of a file system with an error diagnostic.
        !           595:  *
        !           596:  * The form of the error message is:
        !           597:  *     fs: error message
        !           598:  */
        !           599: static void
        !           600: ext2fs_fserr(struct m_ext2fs *fs, uid_t uid, char *cp)
        !           601: {
        !           602:
        !           603:        log(LOG_ERR, "uid %u on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
        !           604: }

CVSweb