1*4123b6a7Sderaadt /* $OpenBSD: ext2fs_alloc.c,v 1.39 2021/05/16 15:10:20 deraadt Exp $ */
2f5ff774dSart /* $NetBSD: ext2fs_alloc.c,v 1.10 2001/07/05 08:38:27 toshii Exp $ */
35ac2d602Sdownsj
45ac2d602Sdownsj /*
51f3ff51cSdownsj * Copyright (c) 1997 Manuel Bouyer.
65ac2d602Sdownsj * Copyright (c) 1982, 1986, 1989, 1993
75ac2d602Sdownsj * The Regents of the University of California. All rights reserved.
85ac2d602Sdownsj *
95ac2d602Sdownsj * Redistribution and use in source and binary forms, with or without
105ac2d602Sdownsj * modification, are permitted provided that the following conditions
115ac2d602Sdownsj * are met:
125ac2d602Sdownsj * 1. Redistributions of source code must retain the above copyright
135ac2d602Sdownsj * notice, this list of conditions and the following disclaimer.
145ac2d602Sdownsj * 2. Redistributions in binary form must reproduce the above copyright
155ac2d602Sdownsj * notice, this list of conditions and the following disclaimer in the
165ac2d602Sdownsj * documentation and/or other materials provided with the distribution.
1729295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
185ac2d602Sdownsj * may be used to endorse or promote products derived from this software
195ac2d602Sdownsj * without specific prior written permission.
205ac2d602Sdownsj *
215ac2d602Sdownsj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
225ac2d602Sdownsj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
235ac2d602Sdownsj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
245ac2d602Sdownsj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
255ac2d602Sdownsj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
265ac2d602Sdownsj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
275ac2d602Sdownsj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
285ac2d602Sdownsj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
295ac2d602Sdownsj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
305ac2d602Sdownsj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315ac2d602Sdownsj * SUCH DAMAGE.
325ac2d602Sdownsj *
335ac2d602Sdownsj * @(#)ffs_alloc.c 8.11 (Berkeley) 10/27/94
341f3ff51cSdownsj * Modified for ext2fs by Manuel Bouyer.
355ac2d602Sdownsj */
365ac2d602Sdownsj
375ac2d602Sdownsj #include <sys/param.h>
385ac2d602Sdownsj #include <sys/systm.h>
395ac2d602Sdownsj #include <sys/buf.h>
405ac2d602Sdownsj #include <sys/vnode.h>
415ac2d602Sdownsj #include <sys/mount.h>
425ac2d602Sdownsj #include <sys/syslog.h>
435ac2d602Sdownsj
445ac2d602Sdownsj #include <ufs/ufs/quota.h>
455ac2d602Sdownsj #include <ufs/ufs/inode.h>
46895e8cacStedu #include <ufs/ufs/ufsmount.h>
475ac2d602Sdownsj #include <ufs/ufs/ufs_extern.h>
485ac2d602Sdownsj
495ac2d602Sdownsj #include <ufs/ext2fs/ext2fs.h>
505ac2d602Sdownsj #include <ufs/ext2fs/ext2fs_extern.h>
515ac2d602Sdownsj
525ac2d602Sdownsj u_long ext2gennumber;
535ac2d602Sdownsj
545970a65fSpelikan static u_int32_t ext2fs_alloccg(struct inode *, int, u_int32_t, int);
555970a65fSpelikan static int ext2fs_dirpref(struct m_ext2fs *);
565087ce21Sjasper static void ext2fs_fserr(struct m_ext2fs *, uid_t, char *);
575970a65fSpelikan static u_int32_t ext2fs_hashalloc(struct inode *, int, u_int32_t, int,
585970a65fSpelikan u_int32_t (*)(struct inode *, int, u_int32_t, int));
595970a65fSpelikan static ufsino_t ext2fs_nodealloccg(struct inode *, int, ufsino_t, int);
605970a65fSpelikan static u_int32_t ext2fs_mapsearch(struct m_ext2fs *, char *, u_int32_t);
615ac2d602Sdownsj
625ac2d602Sdownsj /*
635ac2d602Sdownsj * Allocate a block in the file system.
645ac2d602Sdownsj *
655ac2d602Sdownsj * A preference may be optionally specified. If a preference is given
665ac2d602Sdownsj * the following hierarchy is used to allocate a block:
675ac2d602Sdownsj * 1) allocate the requested block.
685ac2d602Sdownsj * 2) allocate a rotationally optimal block in the same cylinder.
695ac2d602Sdownsj * 3) allocate a block in the same cylinder group.
70ae3260bcSpedro * 4) quadratically rehash into other cylinder groups, until an
715ac2d602Sdownsj * available block is located.
722f4b598dStedu * If no block preference is given the following hierarchy is used
735ac2d602Sdownsj * to allocate a block:
745ac2d602Sdownsj * 1) allocate a block in the cylinder group that contains the
755ac2d602Sdownsj * inode for the file.
76ae3260bcSpedro * 2) quadratically rehash into other cylinder groups, until an
775ac2d602Sdownsj * available block is located.
785ac2d602Sdownsj */
795ac2d602Sdownsj int
ext2fs_alloc(struct inode * ip,u_int32_t lbn,u_int32_t bpref,struct ucred * cred,u_int32_t * bnp)805970a65fSpelikan ext2fs_alloc(struct inode *ip, u_int32_t lbn, u_int32_t bpref,
815970a65fSpelikan struct ucred *cred, u_int32_t *bnp)
825ac2d602Sdownsj {
83f5ff774dSart struct m_ext2fs *fs;
845970a65fSpelikan u_int32_t bno;
855ac2d602Sdownsj int cg;
865ac2d602Sdownsj
875ac2d602Sdownsj *bnp = 0;
885ac2d602Sdownsj fs = ip->i_e2fs;
895ac2d602Sdownsj #ifdef DIAGNOSTIC
905ac2d602Sdownsj if (cred == NOCRED)
9130ada397Smillert panic("ext2fs_alloc: missing credential");
925ac2d602Sdownsj #endif /* DIAGNOSTIC */
935ac2d602Sdownsj if (fs->e2fs.e2fs_fbcount == 0)
945ac2d602Sdownsj goto nospace;
955ac2d602Sdownsj if (cred->cr_uid != 0 && freespace(fs) <= 0)
965ac2d602Sdownsj goto nospace;
975ac2d602Sdownsj if (bpref >= fs->e2fs.e2fs_bcount)
985ac2d602Sdownsj bpref = 0;
995ac2d602Sdownsj if (bpref == 0)
1005ac2d602Sdownsj cg = ino_to_cg(fs, ip->i_number);
1015ac2d602Sdownsj else
1025ac2d602Sdownsj cg = dtog(fs, bpref);
1035970a65fSpelikan bno = ext2fs_hashalloc(ip, cg, bpref, fs->e2fs_bsize, ext2fs_alloccg);
1045ac2d602Sdownsj if (bno > 0) {
1055ac2d602Sdownsj ip->i_e2fs_nblock += btodb(fs->e2fs_bsize);
1065ac2d602Sdownsj ip->i_flag |= IN_CHANGE | IN_UPDATE;
1075ac2d602Sdownsj *bnp = bno;
1085ac2d602Sdownsj return (0);
1095ac2d602Sdownsj }
1105ac2d602Sdownsj nospace:
1115ac2d602Sdownsj ext2fs_fserr(fs, cred->cr_uid, "file system full");
1125ac2d602Sdownsj uprintf("\n%s: write failed, file system is full\n", fs->e2fs_fsmnt);
1135ac2d602Sdownsj return (ENOSPC);
1145ac2d602Sdownsj }
1155ac2d602Sdownsj
1165ac2d602Sdownsj /*
1175ac2d602Sdownsj * Allocate an inode in the file system.
1185ac2d602Sdownsj *
1195ac2d602Sdownsj * If allocating a directory, use ext2fs_dirpref to select the inode.
1205ac2d602Sdownsj * If allocating in a directory, the following hierarchy is followed:
1215ac2d602Sdownsj * 1) allocate the preferred inode.
1225ac2d602Sdownsj * 2) allocate an inode in the same cylinder group.
123ae3260bcSpedro * 3) quadratically rehash into other cylinder groups, until an
1245ac2d602Sdownsj * available inode is located.
1252f4b598dStedu * If no inode preference is given the following hierarchy is used
1265ac2d602Sdownsj * to allocate an inode:
1275ac2d602Sdownsj * 1) allocate an inode in cylinder group 0.
128ae3260bcSpedro * 2) quadratically rehash into other cylinder groups, until an
1295ac2d602Sdownsj * available inode is located.
1305ac2d602Sdownsj */
1315ac2d602Sdownsj int
ext2fs_inode_alloc(struct inode * pip,mode_t mode,struct ucred * cred,struct vnode ** vpp)132cc2fc615Smillert ext2fs_inode_alloc(struct inode *pip, mode_t mode, struct ucred *cred,
133b080ad39Scsapuntz struct vnode **vpp)
1345ac2d602Sdownsj {
135b080ad39Scsapuntz struct vnode *pvp;
136b080ad39Scsapuntz struct m_ext2fs *fs;
137b080ad39Scsapuntz struct inode *ip;
138e012d6d3Sguenther ufsino_t ino, ipref;
1395ac2d602Sdownsj int cg, error;
1405ac2d602Sdownsj
141b080ad39Scsapuntz *vpp = NULL;
142b080ad39Scsapuntz pvp = ITOV(pip);
1435ac2d602Sdownsj fs = pip->i_e2fs;
1445ac2d602Sdownsj if (fs->e2fs.e2fs_ficount == 0)
1455ac2d602Sdownsj goto noinodes;
1465ac2d602Sdownsj
1475ac2d602Sdownsj if ((mode & IFMT) == IFDIR)
1485ac2d602Sdownsj cg = ext2fs_dirpref(fs);
1495ac2d602Sdownsj else
1505ac2d602Sdownsj cg = ino_to_cg(fs, pip->i_number);
1511f3ff51cSdownsj ipref = cg * fs->e2fs.e2fs_ipg + 1;
1525970a65fSpelikan ino = ext2fs_hashalloc(pip, cg, ipref, mode, ext2fs_nodealloccg);
1535ac2d602Sdownsj if (ino == 0)
1545ac2d602Sdownsj goto noinodes;
155b080ad39Scsapuntz error = VFS_VGET(pvp->v_mount, ino, vpp);
1565ac2d602Sdownsj if (error) {
157b080ad39Scsapuntz ext2fs_inode_free(pip, ino, mode);
1585ac2d602Sdownsj return (error);
1595ac2d602Sdownsj }
160b080ad39Scsapuntz ip = VTOI(*vpp);
1615ac2d602Sdownsj if (ip->i_e2fs_mode && ip->i_e2fs_nlink != 0) {
162428694f5Sbluhm printf("mode = 0%o, nlinks %u, inum = %u, fs = %s\n",
163f7dbefaaSpelikan ip->i_e2fs_mode, ip->i_e2fs_nlink, ip->i_number,
164f7dbefaaSpelikan fs->e2fs_fsmnt);
1655ac2d602Sdownsj panic("ext2fs_valloc: dup alloc");
1665ac2d602Sdownsj }
1675ac2d602Sdownsj
1680f5c6c8bStedu memset(ip->i_e2din, 0, sizeof(struct ext2fs_dinode));
1695ac2d602Sdownsj
1705ac2d602Sdownsj /*
1715ac2d602Sdownsj * Set up a new generation number for this inode.
1725ac2d602Sdownsj */
1733209772dScheloha if (++ext2gennumber < (u_long)gettime())
1743209772dScheloha ext2gennumber = gettime();
1755ac2d602Sdownsj ip->i_e2fs_gen = ext2gennumber;
1765ac2d602Sdownsj return (0);
1775ac2d602Sdownsj noinodes:
178b080ad39Scsapuntz ext2fs_fserr(fs, cred->cr_uid, "out of inodes");
1795ac2d602Sdownsj uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
1805ac2d602Sdownsj return (ENOSPC);
1815ac2d602Sdownsj }
1825ac2d602Sdownsj
1835ac2d602Sdownsj /*
1845ac2d602Sdownsj * Find a cylinder to place a directory.
1855ac2d602Sdownsj *
1865ac2d602Sdownsj * The policy implemented by this algorithm is to select from
1875ac2d602Sdownsj * among those cylinder groups with above the average number of
1885ac2d602Sdownsj * free inodes, the one with the smallest number of directories.
1895ac2d602Sdownsj */
1905970a65fSpelikan static int
ext2fs_dirpref(struct m_ext2fs * fs)1915f64cd9cSjasper ext2fs_dirpref(struct m_ext2fs *fs)
1925ac2d602Sdownsj {
1935ac2d602Sdownsj int cg, maxspace, mincg, avgifree;
1945ac2d602Sdownsj
1955ac2d602Sdownsj avgifree = fs->e2fs.e2fs_ficount / fs->e2fs_ncg;
1965ac2d602Sdownsj maxspace = 0;
1975ac2d602Sdownsj mincg = -1;
1985ac2d602Sdownsj for (cg = 0; cg < fs->e2fs_ncg; cg++)
1995ac2d602Sdownsj if ( fs->e2fs_gd[cg].ext2bgd_nifree >= avgifree) {
2005ac2d602Sdownsj if (mincg == -1 || fs->e2fs_gd[cg].ext2bgd_nbfree > maxspace) {
2015ac2d602Sdownsj mincg = cg;
2025ac2d602Sdownsj maxspace = fs->e2fs_gd[cg].ext2bgd_nbfree;
2035ac2d602Sdownsj }
2045ac2d602Sdownsj }
2055ac2d602Sdownsj return mincg;
2065ac2d602Sdownsj }
2075ac2d602Sdownsj
2085ac2d602Sdownsj /*
2095ac2d602Sdownsj * Select the desired position for the next block in a file. The file is
2105ac2d602Sdownsj * logically divided into sections. The first section is composed of the
2115ac2d602Sdownsj * direct blocks. Each additional section contains fs_maxbpg blocks.
2125ac2d602Sdownsj *
2135ac2d602Sdownsj * If no blocks have been allocated in the first section, the policy is to
2145ac2d602Sdownsj * request a block in the same cylinder group as the inode that describes
2155ac2d602Sdownsj * the file. Otherwise, the policy is to try to allocate the blocks
216b66b9ef8Sjsg * contiguously. The two fields of the ext2 inode extension (see
2175ac2d602Sdownsj * ufs/ufs/inode.h) help this.
2185ac2d602Sdownsj */
2191abdbfdeSderaadt daddr_t
ext2fs_blkpref(struct inode * ip,u_int32_t lbn,int baps,u_int32_t * bap)2205970a65fSpelikan ext2fs_blkpref(struct inode *ip, u_int32_t lbn, int baps, u_int32_t *bap)
2215ac2d602Sdownsj {
222f5ff774dSart struct m_ext2fs *fs;
223f5ff774dSart int cg, i;
2245ac2d602Sdownsj
2255ac2d602Sdownsj fs = ip->i_e2fs;
2265ac2d602Sdownsj /*
227b66b9ef8Sjsg * if we are doing contiguous lbn allocation, try to alloc blocks
228b66b9ef8Sjsg * contiguously on disk
2295ac2d602Sdownsj */
2305ac2d602Sdownsj
2315ac2d602Sdownsj if ( ip->i_e2fs_last_blk && lbn == ip->i_e2fs_last_lblk + 1) {
2325ac2d602Sdownsj return ip->i_e2fs_last_blk + 1;
2335ac2d602Sdownsj }
2345ac2d602Sdownsj
2355ac2d602Sdownsj /*
2365ac2d602Sdownsj * bap, if provided, gives us a list of blocks to which we want to
2375ac2d602Sdownsj * stay close
2385ac2d602Sdownsj */
2395ac2d602Sdownsj
2405ac2d602Sdownsj if (bap) {
2415970a65fSpelikan for (i = baps; i >= 0 ; i--) {
2425ac2d602Sdownsj if (bap[i]) {
243f7dbefaaSpelikan return letoh32(bap[i]) + 1;
2445ac2d602Sdownsj }
2455ac2d602Sdownsj }
2465ac2d602Sdownsj }
2475ac2d602Sdownsj
2485ac2d602Sdownsj /* fall back to the first block of the cylinder containing the inode */
2495ac2d602Sdownsj
2505ac2d602Sdownsj cg = ino_to_cg(fs, ip->i_number);
2515ac2d602Sdownsj return fs->e2fs.e2fs_bpg * cg + fs->e2fs.e2fs_first_dblock + 1;
2525ac2d602Sdownsj }
2535ac2d602Sdownsj
2545ac2d602Sdownsj /*
2555ac2d602Sdownsj * Implement the cylinder overflow algorithm.
2565ac2d602Sdownsj *
2575ac2d602Sdownsj * The policy implemented by this algorithm is:
2585ac2d602Sdownsj * 1) allocate the block in its requested cylinder group.
259ae3260bcSpedro * 2) quadratically rehash on the cylinder group number.
2605ac2d602Sdownsj * 3) brute force search for a free block.
2615ac2d602Sdownsj */
2625970a65fSpelikan static u_int32_t
ext2fs_hashalloc(struct inode * ip,int cg,u_int32_t pref,int size,u_int32_t (* allocator)(struct inode *,int,u_int32_t,int))2635970a65fSpelikan ext2fs_hashalloc(struct inode *ip, int cg, u_int32_t pref, int size,
2645970a65fSpelikan u_int32_t (*allocator)(struct inode *, int, u_int32_t, int))
2655ac2d602Sdownsj {
266f5ff774dSart struct m_ext2fs *fs;
2675ac2d602Sdownsj long result;
2685ac2d602Sdownsj int i, icg = cg;
2695ac2d602Sdownsj
2705ac2d602Sdownsj fs = ip->i_e2fs;
2715ac2d602Sdownsj /*
2725ac2d602Sdownsj * 1: preferred cylinder group
2735ac2d602Sdownsj */
2745ac2d602Sdownsj result = (*allocator)(ip, cg, pref, size);
2755ac2d602Sdownsj if (result)
2765ac2d602Sdownsj return (result);
2775ac2d602Sdownsj /*
2785ac2d602Sdownsj * 2: quadratic rehash
2795ac2d602Sdownsj */
2805ac2d602Sdownsj for (i = 1; i < fs->e2fs_ncg; i *= 2) {
2815ac2d602Sdownsj cg += i;
2825ac2d602Sdownsj if (cg >= fs->e2fs_ncg)
2835ac2d602Sdownsj cg -= fs->e2fs_ncg;
2845ac2d602Sdownsj result = (*allocator)(ip, cg, 0, size);
2855ac2d602Sdownsj if (result)
2865ac2d602Sdownsj return (result);
2875ac2d602Sdownsj }
2885ac2d602Sdownsj /*
2895ac2d602Sdownsj * 3: brute force search
2905ac2d602Sdownsj * Note that we start at i == 2, since 0 was checked initially,
2915ac2d602Sdownsj * and 1 is always checked in the quadratic rehash.
2925ac2d602Sdownsj */
2935ac2d602Sdownsj cg = (icg + 2) % fs->e2fs_ncg;
2945ac2d602Sdownsj for (i = 2; i < fs->e2fs_ncg; i++) {
2955ac2d602Sdownsj result = (*allocator)(ip, cg, 0, size);
2965ac2d602Sdownsj if (result)
2975ac2d602Sdownsj return (result);
2985ac2d602Sdownsj cg++;
2995ac2d602Sdownsj if (cg == fs->e2fs_ncg)
3005ac2d602Sdownsj cg = 0;
3015ac2d602Sdownsj }
302f5ff774dSart return (0);
3035ac2d602Sdownsj }
3045ac2d602Sdownsj
3055ac2d602Sdownsj /*
3065ac2d602Sdownsj * Determine whether a block can be allocated.
3075ac2d602Sdownsj *
3085ac2d602Sdownsj * Check to see if a block of the appropriate size is available,
3095ac2d602Sdownsj * and if it is, allocate it.
3105ac2d602Sdownsj */
3115970a65fSpelikan static u_int32_t
ext2fs_alloccg(struct inode * ip,int cg,u_int32_t bpref,int size)3125970a65fSpelikan ext2fs_alloccg(struct inode *ip, int cg, u_int32_t bpref, int size)
3135ac2d602Sdownsj {
314f5ff774dSart struct m_ext2fs *fs;
315f5ff774dSart char *bbp;
3165ac2d602Sdownsj struct buf *bp;
3175970a65fSpelikan u_int32_t bno;
3185970a65fSpelikan int error, start, end, loc;
3195ac2d602Sdownsj
3205ac2d602Sdownsj fs = ip->i_e2fs;
3215ac2d602Sdownsj if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
322f5ff774dSart return (0);
323f5ee6277Sjasoni error = bread(ip->i_devvp, fsbtodb(fs,
324f7dbefaaSpelikan fs->e2fs_gd[cg].ext2bgd_b_bitmap), (int)fs->e2fs_bsize, &bp);
32572a2b703Spedro if (error || fs->e2fs_gd[cg].ext2bgd_nbfree == 0) {
3265ac2d602Sdownsj brelse(bp);
327f5ff774dSart return (0);
3285ac2d602Sdownsj }
3295ac2d602Sdownsj bbp = (char *)bp->b_data;
3305ac2d602Sdownsj
3315ac2d602Sdownsj if (dtog(fs, bpref) != cg)
3325ac2d602Sdownsj bpref = 0;
3335ac2d602Sdownsj if (bpref != 0) {
3345ac2d602Sdownsj bpref = dtogd(fs, bpref);
3355ac2d602Sdownsj /*
3365ac2d602Sdownsj * if the requested block is available, use it
3375ac2d602Sdownsj */
3385ac2d602Sdownsj if (isclr(bbp, bpref)) {
3395ac2d602Sdownsj bno = bpref;
3405ac2d602Sdownsj goto gotit;
3415ac2d602Sdownsj }
3425ac2d602Sdownsj }
3435ac2d602Sdownsj /*
3445ac2d602Sdownsj * no blocks in the requested cylinder, so take next
3455ac2d602Sdownsj * available one in this cylinder group.
346b66b9ef8Sjsg * first try to get 8 contiguous blocks, then fall back to a single
3475ac2d602Sdownsj * block.
3485ac2d602Sdownsj */
3495ac2d602Sdownsj if (bpref)
3505ac2d602Sdownsj start = dtogd(fs, bpref) / NBBY;
3515ac2d602Sdownsj else
3525ac2d602Sdownsj start = 0;
3535ac2d602Sdownsj end = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
3545ac2d602Sdownsj for (loc = start; loc < end; loc++) {
3555ac2d602Sdownsj if (bbp[loc] == 0) {
3565ac2d602Sdownsj bno = loc * NBBY;
3575ac2d602Sdownsj goto gotit;
3585ac2d602Sdownsj }
3595ac2d602Sdownsj }
3605ac2d602Sdownsj for (loc = 0; loc < start; loc++) {
3615ac2d602Sdownsj if (bbp[loc] == 0) {
3625ac2d602Sdownsj bno = loc * NBBY;
3635ac2d602Sdownsj goto gotit;
3645ac2d602Sdownsj }
3655ac2d602Sdownsj }
3665ac2d602Sdownsj
3675ac2d602Sdownsj bno = ext2fs_mapsearch(fs, bbp, bpref);
3685ac2d602Sdownsj gotit:
3695ac2d602Sdownsj #ifdef DIAGNOSTIC
3705970a65fSpelikan if (isset(bbp, bno)) {
371*4123b6a7Sderaadt panic("%s: dup alloc: cg=%d bno=%u fs=%s",
3725970a65fSpelikan __func__, cg, bno, fs->e2fs_fsmnt);
3735ac2d602Sdownsj }
3745ac2d602Sdownsj #endif
3755970a65fSpelikan setbit(bbp, bno);
3765ac2d602Sdownsj fs->e2fs.e2fs_fbcount--;
3775ac2d602Sdownsj fs->e2fs_gd[cg].ext2bgd_nbfree--;
3785ac2d602Sdownsj fs->e2fs_fmod = 1;
3795ac2d602Sdownsj bdwrite(bp);
3805ac2d602Sdownsj return (cg * fs->e2fs.e2fs_fpg + fs->e2fs.e2fs_first_dblock + bno);
3815ac2d602Sdownsj }
3825ac2d602Sdownsj
3835ac2d602Sdownsj /*
3845ac2d602Sdownsj * Determine whether an inode can be allocated.
3855ac2d602Sdownsj *
3865ac2d602Sdownsj * Check to see if an inode is available, and if it is,
3875ac2d602Sdownsj * allocate it using the following policy:
3885ac2d602Sdownsj * 1) allocate the requested inode.
3895ac2d602Sdownsj * 2) allocate the next available inode after the requested
3905ac2d602Sdownsj * inode in the specified cylinder group.
3915ac2d602Sdownsj */
3925970a65fSpelikan static ufsino_t
ext2fs_nodealloccg(struct inode * ip,int cg,ufsino_t ipref,int mode)3935970a65fSpelikan ext2fs_nodealloccg(struct inode *ip, int cg, ufsino_t ipref, int mode)
3945ac2d602Sdownsj {
395f5ff774dSart struct m_ext2fs *fs;
396f5ff774dSart char *ibp;
3975ac2d602Sdownsj struct buf *bp;
3985ac2d602Sdownsj int error, start, len, loc, map, i;
3995ac2d602Sdownsj
4005ac2d602Sdownsj ipref--; /* to avoid a lot of (ipref -1) */
4015ac2d602Sdownsj fs = ip->i_e2fs;
4025ac2d602Sdownsj if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
403f5ff774dSart return (0);
404f5ee6277Sjasoni error = bread(ip->i_devvp, fsbtodb(fs,
405f7dbefaaSpelikan fs->e2fs_gd[cg].ext2bgd_i_bitmap), (int)fs->e2fs_bsize, &bp);
4065ac2d602Sdownsj if (error) {
4075ac2d602Sdownsj brelse(bp);
408f5ff774dSart return (0);
4095ac2d602Sdownsj }
4105ac2d602Sdownsj ibp = (char *)bp->b_data;
4115ac2d602Sdownsj if (ipref) {
4125ac2d602Sdownsj ipref %= fs->e2fs.e2fs_ipg;
4135ac2d602Sdownsj if (isclr(ibp, ipref))
4145ac2d602Sdownsj goto gotit;
4155ac2d602Sdownsj }
4165ac2d602Sdownsj start = ipref / NBBY;
4175ac2d602Sdownsj len = howmany(fs->e2fs.e2fs_ipg - ipref, NBBY);
4185ac2d602Sdownsj loc = skpc(0xff, len, &ibp[start]);
4195ac2d602Sdownsj if (loc == 0) {
4205ac2d602Sdownsj len = start + 1;
4215ac2d602Sdownsj start = 0;
4225ac2d602Sdownsj loc = skpc(0xff, len, &ibp[0]);
4235ac2d602Sdownsj if (loc == 0) {
4245970a65fSpelikan printf("cg = %d, ipref = %u, fs = %s\n",
4255ac2d602Sdownsj cg, ipref, fs->e2fs_fsmnt);
4265ac2d602Sdownsj panic("ext2fs_nodealloccg: map corrupted");
4275ac2d602Sdownsj /* NOTREACHED */
4285ac2d602Sdownsj }
4295ac2d602Sdownsj }
4305ac2d602Sdownsj i = start + len - loc;
4315ac2d602Sdownsj map = ibp[i];
4325ac2d602Sdownsj ipref = i * NBBY;
4335ac2d602Sdownsj for (i = 1; i < (1 << NBBY); i <<= 1, ipref++) {
4345ac2d602Sdownsj if ((map & i) == 0) {
4355ac2d602Sdownsj goto gotit;
4365ac2d602Sdownsj }
4375ac2d602Sdownsj }
4385ac2d602Sdownsj printf("fs = %s\n", fs->e2fs_fsmnt);
4395ac2d602Sdownsj panic("ext2fs_nodealloccg: block not in map");
4405ac2d602Sdownsj /* NOTREACHED */
4415ac2d602Sdownsj gotit:
4425ac2d602Sdownsj setbit(ibp, ipref);
4435ac2d602Sdownsj fs->e2fs.e2fs_ficount--;
4445ac2d602Sdownsj fs->e2fs_gd[cg].ext2bgd_nifree--;
4455ac2d602Sdownsj fs->e2fs_fmod = 1;
4465ac2d602Sdownsj if ((mode & IFMT) == IFDIR) {
4475ac2d602Sdownsj fs->e2fs_gd[cg].ext2bgd_ndirs++;
4485ac2d602Sdownsj }
4495ac2d602Sdownsj bdwrite(bp);
4505ac2d602Sdownsj return (cg * fs->e2fs.e2fs_ipg + ipref + 1);
4515ac2d602Sdownsj }
4525ac2d602Sdownsj
4535ac2d602Sdownsj /*
4545ac2d602Sdownsj * Free a block.
4555ac2d602Sdownsj *
4565ac2d602Sdownsj * The specified block is placed back in the
4575ac2d602Sdownsj * free map.
4585ac2d602Sdownsj */
4595ac2d602Sdownsj void
ext2fs_blkfree(struct inode * ip,u_int32_t bno)4605970a65fSpelikan ext2fs_blkfree(struct inode *ip, u_int32_t bno)
4615ac2d602Sdownsj {
462f5ff774dSart struct m_ext2fs *fs;
463f5ff774dSart char *bbp;
4645ac2d602Sdownsj struct buf *bp;
4655ac2d602Sdownsj int error, cg;
4665ac2d602Sdownsj
4675ac2d602Sdownsj fs = ip->i_e2fs;
4685ac2d602Sdownsj cg = dtog(fs, bno);
4695970a65fSpelikan if (bno >= fs->e2fs.e2fs_bcount) {
4705970a65fSpelikan printf("bad block %u, ino %u\n", bno, ip->i_number);
4715ac2d602Sdownsj ext2fs_fserr(fs, ip->i_e2fs_uid, "bad block");
4725ac2d602Sdownsj return;
4735ac2d602Sdownsj }
474f5ff774dSart error = bread(ip->i_devvp,
475f5ff774dSart fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
47693f62a9eStedu (int)fs->e2fs_bsize, &bp);
4775ac2d602Sdownsj if (error) {
4785ac2d602Sdownsj brelse(bp);
4795ac2d602Sdownsj return;
4805ac2d602Sdownsj }
4815ac2d602Sdownsj bbp = (char *)bp->b_data;
4825ac2d602Sdownsj bno = dtogd(fs, bno);
4835970a65fSpelikan if (isclr(bbp, bno))
484*4123b6a7Sderaadt panic("%s: freeing free block: dev = 0x%x, block = %u, fs = %s",
4855970a65fSpelikan __func__, ip->i_dev, bno, fs->e2fs_fsmnt);
4865970a65fSpelikan
4875ac2d602Sdownsj clrbit(bbp, bno);
4885ac2d602Sdownsj fs->e2fs.e2fs_fbcount++;
4895ac2d602Sdownsj fs->e2fs_gd[cg].ext2bgd_nbfree++;
4905ac2d602Sdownsj
4915ac2d602Sdownsj fs->e2fs_fmod = 1;
4925ac2d602Sdownsj bdwrite(bp);
4935ac2d602Sdownsj }
4945ac2d602Sdownsj
4955ac2d602Sdownsj /*
4965ac2d602Sdownsj * Free an inode.
4975ac2d602Sdownsj *
4985ac2d602Sdownsj * The specified inode is placed back in the free map.
4995ac2d602Sdownsj */
5005970a65fSpelikan void
ext2fs_inode_free(struct inode * pip,ufsino_t ino,mode_t mode)501e012d6d3Sguenther ext2fs_inode_free(struct inode *pip, ufsino_t ino, mode_t mode)
5025ac2d602Sdownsj {
5035f64cd9cSjasper struct m_ext2fs *fs;
5045f64cd9cSjasper char *ibp;
5055ac2d602Sdownsj struct buf *bp;
5065ac2d602Sdownsj int error, cg;
5075ac2d602Sdownsj
5085ac2d602Sdownsj fs = pip->i_e2fs;
5095970a65fSpelikan if (ino > fs->e2fs.e2fs_icount || ino < EXT2_FIRSTINO)
5105970a65fSpelikan panic("ifree: range: dev = 0x%x, ino = %u, fs = %s",
5115ac2d602Sdownsj pip->i_dev, ino, fs->e2fs_fsmnt);
5125ac2d602Sdownsj cg = ino_to_cg(fs, ino);
513f5ee6277Sjasoni error = bread(pip->i_devvp,
514f5ee6277Sjasoni fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
51593f62a9eStedu (int)fs->e2fs_bsize, &bp);
5165ac2d602Sdownsj if (error) {
5175ac2d602Sdownsj brelse(bp);
5185970a65fSpelikan return;
5195ac2d602Sdownsj }
5205ac2d602Sdownsj ibp = (char *)bp->b_data;
5215ac2d602Sdownsj ino = (ino - 1) % fs->e2fs.e2fs_ipg;
5225ac2d602Sdownsj if (isclr(ibp, ino)) {
5235ac2d602Sdownsj printf("dev = 0x%x, ino = %d, fs = %s\n",
5245ac2d602Sdownsj pip->i_dev, ino, fs->e2fs_fsmnt);
5255ac2d602Sdownsj if (fs->e2fs_ronly == 0)
5265ac2d602Sdownsj panic("ifree: freeing free inode");
5275ac2d602Sdownsj }
5285ac2d602Sdownsj clrbit(ibp, ino);
5295ac2d602Sdownsj fs->e2fs.e2fs_ficount++;
5305ac2d602Sdownsj fs->e2fs_gd[cg].ext2bgd_nifree++;
531b080ad39Scsapuntz if ((mode & IFMT) == IFDIR) {
5325ac2d602Sdownsj fs->e2fs_gd[cg].ext2bgd_ndirs--;
5335ac2d602Sdownsj }
5345ac2d602Sdownsj fs->e2fs_fmod = 1;
5355ac2d602Sdownsj bdwrite(bp);
5365ac2d602Sdownsj }
5375ac2d602Sdownsj
5385ac2d602Sdownsj /*
5395ac2d602Sdownsj * Find a block in the specified cylinder group.
5405ac2d602Sdownsj *
5415ac2d602Sdownsj * It is a panic if a request is made to find a block if none are
5425ac2d602Sdownsj * available.
5435ac2d602Sdownsj */
5445ac2d602Sdownsj
5455970a65fSpelikan static u_int32_t
ext2fs_mapsearch(struct m_ext2fs * fs,char * bbp,u_int32_t bpref)5465970a65fSpelikan ext2fs_mapsearch(struct m_ext2fs *fs, char *bbp, u_int32_t bpref)
5475ac2d602Sdownsj {
5485970a65fSpelikan u_int32_t bno;
5495ac2d602Sdownsj int start, len, loc, i, map;
5505ac2d602Sdownsj
5515ac2d602Sdownsj /*
5525ac2d602Sdownsj * find the fragment by searching through the free block
5535ac2d602Sdownsj * map for an appropriate bit pattern
5545ac2d602Sdownsj */
5555ac2d602Sdownsj if (bpref)
5565ac2d602Sdownsj start = dtogd(fs, bpref) / NBBY;
5575ac2d602Sdownsj else
5585ac2d602Sdownsj start = 0;
5595ac2d602Sdownsj len = howmany(fs->e2fs.e2fs_fpg, NBBY) - start;
5605ac2d602Sdownsj loc = skpc(0xff, len, &bbp[start]);
5615ac2d602Sdownsj if (loc == 0) {
5625ac2d602Sdownsj len = start + 1;
5635ac2d602Sdownsj start = 0;
5645ac2d602Sdownsj loc = skpc(0xff, len, &bbp[start]);
5655ac2d602Sdownsj if (loc == 0) {
5665ac2d602Sdownsj printf("start = %d, len = %d, fs = %s\n",
5675ac2d602Sdownsj start, len, fs->e2fs_fsmnt);
5685ac2d602Sdownsj panic("ext2fs_alloccg: map corrupted");
5695ac2d602Sdownsj /* NOTREACHED */
5705ac2d602Sdownsj }
5715ac2d602Sdownsj }
5725ac2d602Sdownsj i = start + len - loc;
5735ac2d602Sdownsj map = bbp[i];
5745ac2d602Sdownsj bno = i * NBBY;
5755ac2d602Sdownsj for (i = 1; i < (1 << NBBY); i <<= 1, bno++) {
5765ac2d602Sdownsj if ((map & i) == 0)
5775ac2d602Sdownsj return (bno);
5785ac2d602Sdownsj }
5795ac2d602Sdownsj printf("fs = %s\n", fs->e2fs_fsmnt);
5805ac2d602Sdownsj panic("ext2fs_mapsearch: block not in map");
5815ac2d602Sdownsj /* NOTREACHED */
5825ac2d602Sdownsj }
5835ac2d602Sdownsj
5845ac2d602Sdownsj /*
5855ac2d602Sdownsj * Fserr prints the name of a file system with an error diagnostic.
5865ac2d602Sdownsj *
5875ac2d602Sdownsj * The form of the error message is:
5885ac2d602Sdownsj * fs: error message
5895ac2d602Sdownsj */
5905ac2d602Sdownsj static void
ext2fs_fserr(struct m_ext2fs * fs,uid_t uid,char * cp)5915087ce21Sjasper ext2fs_fserr(struct m_ext2fs *fs, uid_t uid, char *cp)
5925ac2d602Sdownsj {
5935087ce21Sjasper log(LOG_ERR, "uid %u on %s: %s\n", uid, fs->e2fs_fsmnt, cp);
5945ac2d602Sdownsj }
595