コード例 #1
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Allocate a block in the filesystem.
 *
 * A preference may be optionally specified. If a preference is given
 * the following hierarchy is used to allocate a block:
 *   1) allocate the requested block.
 *   2) allocate a rotationally optimal block in the same cylinder.
 *   3) allocate a block in the same cylinder group.
 *   4) quadradically rehash into other cylinder groups, until an
 *        available block is located.
 * If no block preference is given the following hierarchy is used
 * to allocate a block:
 *   1) allocate a block in the cylinder group that contains the
 *        inode for the file.
 *   2) quadradically rehash into other cylinder groups, until an
 *        available block is located.
 */
int
ext2_alloc(struct inode *ip, daddr_t lbn, e4fs_daddr_t bpref, int size,
           struct ucred *cred, e4fs_daddr_t *bnp)
{
    struct m_ext2fs *fs;
    struct ext2mount *ump;
    int32_t bno;
    int cg;
    *bnp = 0;
    fs = ip->i_e2fs;
    ump = ip->i_ump;
    mtx_assert(EXT2_MTX(ump), MA_OWNED);
#ifdef INVARIANTS
    if ((u_int)size > fs->e2fs_bsize || blkoff(fs, size) != 0) {
        vn_printf(ip->i_devvp, "bsize = %lu, size = %d, fs = %s\n",
                  (long unsigned int)fs->e2fs_bsize, size, fs->e2fs_fsmnt);
        panic("ext2_alloc: bad size");
    }
    if (cred == NOCRED)
        panic("ext2_alloc: missing credential");
#endif /* INVARIANTS */
    if (size == fs->e2fs_bsize && fs->e2fs->e2fs_fbcount == 0)
        goto nospace;
    if (cred->cr_uid != 0 &&
            fs->e2fs->e2fs_fbcount < fs->e2fs->e2fs_rbcount)
        goto nospace;
    if (bpref >= fs->e2fs->e2fs_bcount)
        bpref = 0;
    if (bpref == 0)
        cg = ino_to_cg(fs, ip->i_number);
    else
        cg = dtog(fs, bpref);
    bno = (daddr_t)ext2_hashalloc(ip, cg, bpref, fs->e2fs_bsize,
                                  ext2_alloccg);
    if (bno > 0) {
        /* set next_alloc fields as done in block_getblk */
        ip->i_next_alloc_block = lbn;
        ip->i_next_alloc_goal = bno;

        ip->i_blocks += btodb(fs->e2fs_bsize);
        ip->i_flag |= IN_CHANGE | IN_UPDATE;
        *bnp = bno;
        return (0);
    }
nospace:
    EXT2_UNLOCK(ump);
    ext2_fserr(fs, cred->cr_uid, "filesystem full");
    uprintf("\n%s: write failed, filesystem is full\n", fs->e2fs_fsmnt);
    return (ENOSPC);
}
コード例 #2
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Free an inode.
 *
 */
int
ext2_vfree(struct vnode *pvp, ino_t ino, int mode)
{
    struct m_ext2fs *fs;
    struct inode *pip;
    struct buf *bp;
    struct ext2mount *ump;
    int error, cg;
    char * ibp;

    pip = VTOI(pvp);
    fs = pip->i_e2fs;
    ump = pip->i_ump;
    if ((u_int)ino > fs->e2fs_ipg * fs->e2fs_gcount)
        panic("ext2_vfree: range: devvp = %p, ino = %ju, fs = %s",
              pip->i_devvp, (uintmax_t)ino, fs->e2fs_fsmnt);

    cg = ino_to_cg(fs, ino);
    error = bread(pip->i_devvp,
                  fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_i_bitmap),
                  (int)fs->e2fs_bsize, NOCRED, &bp);
    if (error) {
        brelse(bp);
        return (0);
    }
    ibp = (char *)bp->b_data;
    ino = (ino - 1) % fs->e2fs->e2fs_ipg;
    if (isclr(ibp, ino)) {
        printf("ino = %llu, fs = %s\n",
               (unsigned long long)ino, fs->e2fs_fsmnt);
        if (fs->e2fs_ronly == 0)
            panic("ext2_vfree: freeing free inode");
    }
    clrbit(ibp, ino);
    EXT2_LOCK(ump);
    fs->e2fs->e2fs_ficount++;
    fs->e2fs_gd[cg].ext2bgd_nifree++;
    if ((mode & IFMT) == IFDIR) {
        fs->e2fs_gd[cg].ext2bgd_ndirs--;
        fs->e2fs_total_dir--;
    }
    fs->e2fs_fmod = 1;
    EXT2_UNLOCK(ump);
    bdwrite(bp);
    return (0);
}
コード例 #3
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Free a block or fragment.
 *
 */
void
ext2_blkfree(struct inode *ip, e4fs_daddr_t bno, long size)
{
    struct m_ext2fs *fs;
    struct buf *bp;
    struct ext2mount *ump;
    int cg, error;
    char *bbp;

    fs = ip->i_e2fs;
    ump = ip->i_ump;
    cg = dtog(fs, bno);
    if ((u_int)bno >= fs->e2fs->e2fs_bcount) {
        printf("bad block %lld, ino %llu\n", (long long)bno,
               (unsigned long long)ip->i_number);
        ext2_fserr(fs, ip->i_uid, "bad block");
        return;
    }
    error = bread(ip->i_devvp,
                  fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
                  (int)fs->e2fs_bsize, NOCRED, &bp);
    if (error) {
        brelse(bp);
        return;
    }
    bbp = (char *)bp->b_data;
    bno = dtogd(fs, bno);
    if (isclr(bbp, bno)) {
        printf("block = %lld, fs = %s\n",
               (long long)bno, fs->e2fs_fsmnt);
        panic("ext2_blkfree: freeing free block");
    }
    clrbit(bbp, bno);
    EXT2_LOCK(ump);
    ext2_clusteracct(fs, bbp, cg, bno, 1);
    fs->e2fs->e2fs_fbcount++;
    fs->e2fs_gd[cg].ext2bgd_nbfree++;
    fs->e2fs_fmod = 1;
    EXT2_UNLOCK(ump);
    bdwrite(bp);
}
コード例 #4
0
ファイル: ext2_balloc.c プロジェクト: kwitaszczyk/freebsd
/*
 * Balloc defines the structure of filesystem storage
 * by allocating the physical blocks on a device given
 * the inode and the logical block number in a file.
 */
int
ext2_balloc(struct inode *ip, e2fs_lbn_t lbn, int size, struct ucred *cred,
    struct buf **bpp, int flags)
{
	struct m_ext2fs *fs;
	struct ext2mount *ump;
	struct buf *bp, *nbp;
	struct vnode *vp = ITOV(ip);
	struct indir indirs[NIADDR + 2];
	e4fs_daddr_t nb, newb;
	e2fs_daddr_t *bap, pref;
	int osize, nsize, num, i, error;

	*bpp = NULL;
	if (lbn < 0)
		return (EFBIG);
	fs = ip->i_e2fs;
	ump = ip->i_ump;

	/*
	 * check if this is a sequential block allocation. 
	 * If so, increment next_alloc fields to allow ext2_blkpref 
	 * to make a good guess
	 */
	if (lbn == ip->i_next_alloc_block + 1) {
		ip->i_next_alloc_block++;
		ip->i_next_alloc_goal++;
	}

	/*
	 * The first NDADDR blocks are direct blocks
	 */
	if (lbn < NDADDR) {
		nb = ip->i_db[lbn];
		/* no new block is to be allocated, and no need to expand
		   the file */
		if (nb != 0 && ip->i_size >= (lbn + 1) * fs->e2fs_bsize) {
			error = bread(vp, lbn, fs->e2fs_bsize, NOCRED, &bp);
			if (error) {
				brelse(bp);
				return (error);
			}
			bp->b_blkno = fsbtodb(fs, nb);
			*bpp = bp;
			return (0);
		}
		if (nb != 0) {
			/*
			 * Consider need to reallocate a fragment.
			 */
			osize = fragroundup(fs, blkoff(fs, ip->i_size));
			nsize = fragroundup(fs, size);
			if (nsize <= osize) {
				error = bread(vp, lbn, osize, NOCRED, &bp);
				if (error) {
					brelse(bp);
					return (error);
				}
				bp->b_blkno = fsbtodb(fs, nb);
			} else {
			/* Godmar thinks: this shouldn't happen w/o fragments */
				printf("nsize %d(%d) > osize %d(%d) nb %d\n", 
					(int)nsize, (int)size, (int)osize, 
					(int)ip->i_size, (int)nb);
				panic(
				    "ext2_balloc: Something is terribly wrong");
/*
 * please note there haven't been any changes from here on -
 * FFS seems to work.
 */
			}
		} else {
			if (ip->i_size < (lbn + 1) * fs->e2fs_bsize)
				nsize = fragroundup(fs, size);
			else
				nsize = fs->e2fs_bsize;
			EXT2_LOCK(ump);
			error = ext2_alloc(ip, lbn,
			    ext2_blkpref(ip, lbn, (int)lbn, &ip->i_db[0], 0),
			    nsize, cred, &newb);
			if (error)
				return (error);
			bp = getblk(vp, lbn, nsize, 0, 0, 0);
			bp->b_blkno = fsbtodb(fs, newb);
			if (flags & BA_CLRBUF)
				vfs_bio_clrbuf(bp);
		}
		ip->i_db[lbn] = dbtofsb(fs, bp->b_blkno);
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
		*bpp = bp;
		return (0);
	}
	/*
	 * Determine the number of levels of indirection.
	 */
	pref = 0;
	if ((error = ext2_getlbns(vp, lbn, indirs, &num)) != 0)
		return (error);
#ifdef INVARIANTS
	if (num < 1)
		panic ("ext2_balloc: ext2_getlbns returned indirect block");
#endif
	/*
	 * Fetch the first indirect block allocating if necessary.
	 */
	--num;
	nb = ip->i_ib[indirs[0].in_off];
	if (nb == 0) {
		EXT2_LOCK(ump);
		pref = ext2_blkpref(ip, lbn, indirs[0].in_off + 
					     EXT2_NDIR_BLOCKS, &ip->i_db[0], 0);
		if ((error = ext2_alloc(ip, lbn, pref, fs->e2fs_bsize, cred,
			&newb)))
			return (error);
		nb = newb;
		bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0, 0);
		bp->b_blkno = fsbtodb(fs, newb);
		vfs_bio_clrbuf(bp);
		/*
		 * Write synchronously so that indirect blocks
		 * never point at garbage.
		 */
		if ((error = bwrite(bp)) != 0) {
			ext2_blkfree(ip, nb, fs->e2fs_bsize);
			return (error);
		}
		ip->i_ib[indirs[0].in_off] = newb;
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
	}
	/*
	 * Fetch through the indirect blocks, allocating as necessary.
	 */
	for (i = 1;;) {
		error = bread(vp,
		    indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, &bp);
		if (error) {
			brelse(bp);
			return (error);
		}
		bap = (e2fs_daddr_t *)bp->b_data;
		nb = bap[indirs[i].in_off];
		if (i == num)
			break;
		i += 1;
		if (nb != 0) {
			bqrelse(bp);
			continue;
		}
		EXT2_LOCK(ump);
		if (pref == 0)
			pref = ext2_blkpref(ip, lbn, indirs[i].in_off, bap,
						bp->b_lblkno);
		error =  ext2_alloc(ip, lbn, pref, (int)fs->e2fs_bsize, cred, &newb);
		if (error) {
			brelse(bp);
			return (error);
		}
		nb = newb;
		nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0, 0);
		nbp->b_blkno = fsbtodb(fs, nb);
		vfs_bio_clrbuf(nbp);
		/*
		 * Write synchronously so that indirect blocks
		 * never point at garbage.
		 */
		if ((error = bwrite(nbp)) != 0) {
			ext2_blkfree(ip, nb, fs->e2fs_bsize);
			EXT2_UNLOCK(ump);
			brelse(bp);
			return (error);
		}
		bap[indirs[i - 1].in_off] = nb;
		/*
		 * If required, write synchronously, otherwise use
		 * delayed write.
		 */
		if (flags & IO_SYNC) {
			bwrite(bp);
		} else {
			if (bp->b_bufsize == fs->e2fs_bsize)
				bp->b_flags |= B_CLUSTEROK;
			bdwrite(bp);
		}
	}
	/*
	 * Get the data block, allocating if necessary.
	 */
	if (nb == 0) {
		EXT2_LOCK(ump);
		pref = ext2_blkpref(ip, lbn, indirs[i].in_off, &bap[0], 
				bp->b_lblkno);
		if ((error = ext2_alloc(ip,
		    lbn, pref, (int)fs->e2fs_bsize, cred, &newb)) != 0) {
			brelse(bp);
			return (error);
		}
		nb = newb;
		nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0, 0);
		nbp->b_blkno = fsbtodb(fs, nb);
		if (flags & BA_CLRBUF)
			vfs_bio_clrbuf(nbp);
		bap[indirs[i].in_off] = nb;
		/*
		 * If required, write synchronously, otherwise use
		 * delayed write.
		 */
		if (flags & IO_SYNC) {
			bwrite(bp);
		} else {
		if (bp->b_bufsize == fs->e2fs_bsize)
				bp->b_flags |= B_CLUSTEROK;
			bdwrite(bp);
		}
		*bpp = nbp;
		return (0);
	}
	brelse(bp);
	if (flags & BA_CLRBUF) {
		int seqcount = (flags & BA_SEQMASK) >> BA_SEQSHIFT;
		if (seqcount && (vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
			error = cluster_read(vp, ip->i_size, lbn,
			    (int)fs->e2fs_bsize, NOCRED,
			    MAXBSIZE, seqcount, 0, &nbp);
		} else {
			error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, &nbp);
		}
		if (error) {
			brelse(nbp);
			return (error);
		}
	} else {
コード例 #5
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Determine whether an inode can be allocated.
 *
 * Check to see if an inode is available, and if it is,
 * allocate it using tode in the specified cylinder group.
 */
static daddr_t
ext2_nodealloccg(struct inode *ip, int cg, daddr_t ipref, int mode)
{
    struct m_ext2fs *fs;
    struct buf *bp;
    struct ext2mount *ump;
    int error, start, len;
    char *ibp, *loc;
    ipref--; /* to avoid a lot of (ipref -1) */
    if (ipref == -1)
        ipref = 0;
    fs = ip->i_e2fs;
    ump = ip->i_ump;
    if (fs->e2fs_gd[cg].ext2bgd_nifree == 0)
        return (0);
    EXT2_UNLOCK(ump);
    error = bread(ip->i_devvp, fsbtodb(fs,
                                       fs->e2fs_gd[cg].ext2bgd_i_bitmap),
                  (int)fs->e2fs_bsize, NOCRED, &bp);
    if (error) {
        brelse(bp);
        EXT2_LOCK(ump);
        return (0);
    }
    if (fs->e2fs_gd[cg].ext2bgd_nifree == 0) {
        /*
         * Another thread allocated the last i-node in this
         * group while we were waiting for the buffer.
         */
        brelse(bp);
        EXT2_LOCK(ump);
        return (0);
    }
    ibp = (char *)bp->b_data;
    if (ipref) {
        ipref %= fs->e2fs->e2fs_ipg;
        if (isclr(ibp, ipref))
            goto gotit;
    }
    start = ipref / NBBY;
    len = howmany(fs->e2fs->e2fs_ipg - ipref, NBBY);
    loc = memcchr(&ibp[start], 0xff, len);
    if (loc == NULL) {
        len = start + 1;
        start = 0;
        loc = memcchr(&ibp[start], 0xff, len);
        if (loc == NULL) {
            printf("cg = %d, ipref = %lld, fs = %s\n",
                   cg, (long long)ipref, fs->e2fs_fsmnt);
            panic("ext2fs_nodealloccg: map corrupted");
            /* NOTREACHED */
        }
    }
    ipref = (loc - ibp) * NBBY + ffs(~*loc) - 1;
gotit:
    setbit(ibp, ipref);
    EXT2_LOCK(ump);
    fs->e2fs_gd[cg].ext2bgd_nifree--;
    fs->e2fs->e2fs_ficount--;
    fs->e2fs_fmod = 1;
    if ((mode & IFMT) == IFDIR) {
        fs->e2fs_gd[cg].ext2bgd_ndirs++;
        fs->e2fs_total_dir++;
    }
    EXT2_UNLOCK(ump);
    bdwrite(bp);
    return (cg * fs->e2fs->e2fs_ipg + ipref +1);
}
コード例 #6
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Determine whether a cluster can be allocated.
 */
static daddr_t
ext2_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len)
{
    struct m_ext2fs *fs;
    struct ext2mount *ump;
    struct buf *bp;
    char *bbp;
    int bit, error, got, i, loc, run;
    int32_t *lp;
    daddr_t bno;

    fs = ip->i_e2fs;
    ump = ip->i_ump;

    if (fs->e2fs_maxcluster[cg] < len)
        return (0);

    EXT2_UNLOCK(ump);
    error = bread(ip->i_devvp,
                  fsbtodb(fs, fs->e2fs_gd[cg].ext2bgd_b_bitmap),
                  (int)fs->e2fs_bsize, NOCRED, &bp);
    if (error)
        goto fail_lock;

    bbp = (char *)bp->b_data;
    EXT2_LOCK(ump);
    /*
     * Check to see if a cluster of the needed size (or bigger) is
     * available in this cylinder group.
     */
    lp = &fs->e2fs_clustersum[cg].cs_sum[len];
    for (i = len; i <= fs->e2fs_contigsumsize; i++)
        if (*lp++ > 0)
            break;
    if (i > fs->e2fs_contigsumsize) {
        /*
         * Update the cluster summary information to reflect
         * the true maximum-sized cluster so that future cluster
         * allocation requests can avoid reading the bitmap only
         * to find no cluster.
         */
        lp = &fs->e2fs_clustersum[cg].cs_sum[len - 1];
        for (i = len - 1; i > 0; i--)
            if (*lp-- > 0)
                break;
        fs->e2fs_maxcluster[cg] = i;
        goto fail;
    }
    EXT2_UNLOCK(ump);

    /* Search the bitmap to find a big enough cluster like in FFS. */
    if (dtog(fs, bpref) != cg)
        bpref = 0;
    if (bpref != 0)
        bpref = dtogd(fs, bpref);
    loc = bpref / NBBY;
    bit = 1 << (bpref % NBBY);
    for (run = 0, got = bpref; got < fs->e2fs->e2fs_fpg; got++) {
        if ((bbp[loc] & bit) != 0)
            run = 0;
        else {
            run++;
            if (run == len)
                break;
        }
        if ((got & (NBBY - 1)) != (NBBY - 1))
            bit <<= 1;
        else {
            loc++;
            bit = 1;
        }
    }

    if (got >= fs->e2fs->e2fs_fpg)
        goto fail_lock;

    /* Allocate the cluster that we found. */
    for (i = 1; i < len; i++)
        if (!isclr(bbp, got - run + i))
            panic("ext2_clusteralloc: map mismatch");

    bno = got - run + 1;
    if (bno >= fs->e2fs->e2fs_fpg)
        panic("ext2_clusteralloc: allocated out of group");

    EXT2_LOCK(ump);
    for (i = 0; i < len; i += fs->e2fs_fpb) {
        setbit(bbp, bno + i);
        ext2_clusteracct(fs, bbp, cg, bno + i, -1);
        fs->e2fs->e2fs_fbcount--;
        fs->e2fs_gd[cg].ext2bgd_nbfree--;
    }
    fs->e2fs_fmod = 1;
    EXT2_UNLOCK(ump);

    bdwrite(bp);
    return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno);

fail_lock:
    EXT2_LOCK(ump);
fail:
    brelse(bp);
    return (0);
}
コード例 #7
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Determine whether a block can be allocated.
 *
 * Check to see if a block of the appropriate size is available,
 * and if it is, allocate it.
 */
static daddr_t
ext2_alloccg(struct inode *ip, int cg, daddr_t bpref, int size)
{
    struct m_ext2fs *fs;
    struct buf *bp;
    struct ext2mount *ump;
    daddr_t bno, runstart, runlen;
    int bit, loc, end, error, start;
    char *bbp;
    /* XXX ondisk32 */
    fs = ip->i_e2fs;
    ump = ip->i_ump;
    if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0)
        return (0);
    EXT2_UNLOCK(ump);
    error = bread(ip->i_devvp, fsbtodb(fs,
                                       fs->e2fs_gd[cg].ext2bgd_b_bitmap),
                  (int)fs->e2fs_bsize, NOCRED, &bp);
    if (error) {
        brelse(bp);
        EXT2_LOCK(ump);
        return (0);
    }
    if (fs->e2fs_gd[cg].ext2bgd_nbfree == 0) {
        /*
         * Another thread allocated the last block in this
         * group while we were waiting for the buffer.
         */
        brelse(bp);
        EXT2_LOCK(ump);
        return (0);
    }
    bbp = (char *)bp->b_data;

    if (dtog(fs, bpref) != cg)
        bpref = 0;
    if (bpref != 0) {
        bpref = dtogd(fs, bpref);
        /*
         * if the requested block is available, use it
         */
        if (isclr(bbp, bpref)) {
            bno = bpref;
            goto gotit;
        }
    }
    /*
     * no blocks in the requested cylinder, so take next
     * available one in this cylinder group.
     * first try to get 8 contigous blocks, then fall back to a single
     * block.
     */
    if (bpref)
        start = dtogd(fs, bpref) / NBBY;
    else
        start = 0;
    end = howmany(fs->e2fs->e2fs_fpg, NBBY) - start;
retry:
    runlen = 0;
    runstart = 0;
    for (loc = start; loc < end; loc++) {
        if (bbp[loc] == (char)0xff) {
            runlen = 0;
            continue;
        }

        /* Start of a run, find the number of high clear bits. */
        if (runlen == 0) {
            bit = fls(bbp[loc]);
            runlen = NBBY - bit;
            runstart = loc * NBBY + bit;
        } else if (bbp[loc] == 0) {
            /* Continue a run. */
            runlen += NBBY;
        } else {
            /*
             * Finish the current run.  If it isn't long
             * enough, start a new one.
             */
            bit = ffs(bbp[loc]) - 1;
            runlen += bit;
            if (runlen >= 8) {
                bno = runstart;
                goto gotit;
            }

            /* Run was too short, start a new one. */
            bit = fls(bbp[loc]);
            runlen = NBBY - bit;
            runstart = loc * NBBY + bit;
        }

        /* If the current run is long enough, use it. */
        if (runlen >= 8) {
            bno = runstart;
            goto gotit;
        }
    }
    if (start != 0) {
        end = start;
        start = 0;
        goto retry;
    }

    bno = ext2_mapsearch(fs, bbp, bpref);
    if (bno < 0) {
        brelse(bp);
        EXT2_LOCK(ump);
        return (0);
    }
gotit:
#ifdef INVARIANTS
    if (isset(bbp, bno)) {
        printf("ext2fs_alloccgblk: cg=%d bno=%jd fs=%s\n",
               cg, (intmax_t)bno, fs->e2fs_fsmnt);
        panic("ext2fs_alloccg: dup alloc");
    }
#endif
    setbit(bbp, bno);
    EXT2_LOCK(ump);
    ext2_clusteracct(fs, bbp, cg, bno, -1);
    fs->e2fs->e2fs_fbcount--;
    fs->e2fs_gd[cg].ext2bgd_nbfree--;
    fs->e2fs_fmod = 1;
    EXT2_UNLOCK(ump);
    bdwrite(bp);
    return (cg * fs->e2fs->e2fs_fpg + fs->e2fs->e2fs_first_dblock + bno);
}
コード例 #8
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
/*
 * Allocate an inode in the filesystem.
 *
 */
int
ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp)
{
    struct timespec ts;
    struct inode *pip;
    struct m_ext2fs *fs;
    struct inode *ip;
    struct ext2mount *ump;
    ino_t ino, ipref;
    int i, error, cg;

    *vpp = NULL;
    pip = VTOI(pvp);
    fs = pip->i_e2fs;
    ump = pip->i_ump;

    EXT2_LOCK(ump);
    if (fs->e2fs->e2fs_ficount == 0)
        goto noinodes;
    /*
     * If it is a directory then obtain a cylinder group based on
     * ext2_dirpref else obtain it using ino_to_cg. The preferred inode is
     * always the next inode.
     */
    if ((mode & IFMT) == IFDIR) {
        cg = ext2_dirpref(pip);
        if (fs->e2fs_contigdirs[cg] < 255)
            fs->e2fs_contigdirs[cg]++;
    } else {
        cg = ino_to_cg(fs, pip->i_number);
        if (fs->e2fs_contigdirs[cg] > 0)
            fs->e2fs_contigdirs[cg]--;
    }
    ipref = cg * fs->e2fs->e2fs_ipg + 1;
    ino = (ino_t)ext2_hashalloc(pip, cg, (long)ipref, mode, ext2_nodealloccg);

    if (ino == 0)
        goto noinodes;
    error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp);
    if (error) {
        ext2_vfree(pvp, ino, mode);
        return (error);
    }
    ip = VTOI(*vpp);

    /*
     * The question is whether using VGET was such good idea at all:
     * Linux doesn't read the old inode in when it is allocating a
     * new one. I will set at least i_size and i_blocks to zero.
     */
    ip->i_size = 0;
    ip->i_blocks = 0;
    ip->i_mode = 0;
    ip->i_flags = 0;
    /* now we want to make sure that the block pointers are zeroed out */
    for (i = 0; i < NDADDR; i++)
        ip->i_db[i] = 0;
    for (i = 0; i < NIADDR; i++)
        ip->i_ib[i] = 0;

    /*
     * Set up a new generation number for this inode.
     * XXX check if this makes sense in ext2
     */
    if (ip->i_gen == 0 || ++ip->i_gen == 0)
        ip->i_gen = random() / 2 + 1;

    vfs_timestamp(&ts);
    ip->i_birthtime = ts.tv_sec;
    ip->i_birthnsec = ts.tv_nsec;

    /*
    printf("ext2_valloc: allocated inode %d\n", ino);
    */
    return (0);
noinodes:
    EXT2_UNLOCK(ump);
    ext2_fserr(fs, cred->cr_uid, "out of inodes");
    uprintf("\n%s: create/symlink failed, no inodes free\n", fs->e2fs_fsmnt);
    return (ENOSPC);
}
コード例 #9
0
ファイル: ext2_alloc.c プロジェクト: jamesbjackson/src
int
ext2_reallocblks(struct vop_reallocblks_args *ap)
{
    struct m_ext2fs *fs;
    struct inode *ip;
    struct vnode *vp;
    struct buf *sbp, *ebp;
    uint32_t *bap, *sbap, *ebap = 0;
    struct ext2mount *ump;
    struct cluster_save *buflist;
    struct indir start_ap[NIADDR + 1], end_ap[NIADDR + 1], *idp;
    e2fs_lbn_t start_lbn, end_lbn;
    int soff;
    e2fs_daddr_t newblk, blkno;
    int i, len, start_lvl, end_lvl, pref, ssize;

    if (doreallocblks == 0)
        return (ENOSPC);

    vp = ap->a_vp;
    ip = VTOI(vp);
    fs = ip->i_e2fs;
    ump = ip->i_ump;

    if (fs->e2fs_contigsumsize <= 0)
        return (ENOSPC);

    buflist = ap->a_buflist;
    len = buflist->bs_nchildren;
    start_lbn = buflist->bs_children[0]->b_lblkno;
    end_lbn = start_lbn + len - 1;
#ifdef INVARIANTS
    for (i = 1; i < len; i++)
        if (buflist->bs_children[i]->b_lblkno != start_lbn + i)
            panic("ext2_reallocblks: non-cluster");
#endif
    /*
     * If the cluster crosses the boundary for the first indirect
     * block, leave space for the indirect block. Indirect blocks
     * are initially laid out in a position after the last direct
     * block. Block reallocation would usually destroy locality by
     * moving the indirect block out of the way to make room for
     * data blocks if we didn't compensate here. We should also do
     * this for other indirect block boundaries, but it is only
     * important for the first one.
     */
    if (start_lbn < NDADDR && end_lbn >= NDADDR)
        return (ENOSPC);
    /*
     * If the latest allocation is in a new cylinder group, assume that
     * the filesystem has decided to move and do not force it back to
     * the previous cylinder group.
     */
    if (dtog(fs, dbtofsb(fs, buflist->bs_children[0]->b_blkno)) !=
            dtog(fs, dbtofsb(fs, buflist->bs_children[len - 1]->b_blkno)))
        return (ENOSPC);
    if (ext2_getlbns(vp, start_lbn, start_ap, &start_lvl) ||
            ext2_getlbns(vp, end_lbn, end_ap, &end_lvl))
        return (ENOSPC);
    /*
     * Get the starting offset and block map for the first block.
     */
    if (start_lvl == 0) {
        sbap = &ip->i_db[0];
        soff = start_lbn;
    } else {
        idp = &start_ap[start_lvl - 1];
        if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &sbp)) {
            brelse(sbp);
            return (ENOSPC);
        }
        sbap = (u_int *)sbp->b_data;
        soff = idp->in_off;
    }
    /*
     * If the block range spans two block maps, get the second map.
     */
    if (end_lvl == 0 || (idp = &end_ap[end_lvl - 1])->in_off + 1 >= len) {
        ssize = len;
    } else {
#ifdef INVARIANTS
        if (start_ap[start_lvl-1].in_lbn == idp->in_lbn)
            panic("ext2_reallocblks: start == end");
#endif
        ssize = len - (idp->in_off + 1);
        if (bread(vp, idp->in_lbn, (int)fs->e2fs_bsize, NOCRED, &ebp))
            goto fail;
        ebap = (u_int *)ebp->b_data;
    }
    /*
     * Find the preferred location for the cluster.
     */
    EXT2_LOCK(ump);
    pref = ext2_blkpref(ip, start_lbn, soff, sbap, 0);
    /*
     * Search the block map looking for an allocation of the desired size.
     */
    if ((newblk = (e2fs_daddr_t)ext2_hashalloc(ip, dtog(fs, pref), pref,
                  len, ext2_clusteralloc)) == 0) {
        EXT2_UNLOCK(ump);
        goto fail;
    }
    /*
     * We have found a new contiguous block.
     *
     * First we have to replace the old block pointers with the new
     * block pointers in the inode and indirect blocks associated
     * with the file.
     */
#ifdef DEBUG
    printf("realloc: ino %d, lbns %jd-%jd\n\told:", ip->i_number,
           (intmax_t)start_lbn, (intmax_t)end_lbn);
#endif /* DEBUG */
    blkno = newblk;
    for (bap = &sbap[soff], i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
        if (i == ssize) {
            bap = ebap;
            soff = -i;
        }
#ifdef INVARIANTS
        if (buflist->bs_children[i]->b_blkno != fsbtodb(fs, *bap))
            panic("ext2_reallocblks: alloc mismatch");
#endif
#ifdef DEBUG
        printf(" %d,", *bap);
#endif /* DEBUG */
        *bap++ = blkno;
    }
    /*
     * Next we must write out the modified inode and indirect blocks.
     * For strict correctness, the writes should be synchronous since
     * the old block values may have been written to disk. In practise
     * they are almost never written, but if we are concerned about
     * strict correctness, the `doasyncfree' flag should be set to zero.
     *
     * The test on `doasyncfree' should be changed to test a flag
     * that shows whether the associated buffers and inodes have
     * been written. The flag should be set when the cluster is
     * started and cleared whenever the buffer or inode is flushed.
     * We can then check below to see if it is set, and do the
     * synchronous write only when it has been cleared.
     */
    if (sbap != &ip->i_db[0]) {
        if (doasyncfree)
            bdwrite(sbp);
        else
            bwrite(sbp);
    } else {
        ip->i_flag |= IN_CHANGE | IN_UPDATE;
        if (!doasyncfree)
            ext2_update(vp, 1);
    }
    if (ssize < len) {
        if (doasyncfree)
            bdwrite(ebp);
        else
            bwrite(ebp);
    }
    /*
     * Last, free the old blocks and assign the new blocks to the buffers.
     */
#ifdef DEBUG
    printf("\n\tnew:");
#endif /* DEBUG */
    for (blkno = newblk, i = 0; i < len; i++, blkno += fs->e2fs_fpb) {
        ext2_blkfree(ip, dbtofsb(fs, buflist->bs_children[i]->b_blkno),
                     fs->e2fs_bsize);
        buflist->bs_children[i]->b_blkno = fsbtodb(fs, blkno);
#ifdef DEBUG
        printf(" %d,", blkno);
#endif /* DEBUG */
    }
#ifdef DEBUG
    printf("\n");
#endif /* DEBUG */
    return (0);

fail:
    if (ssize < len)
        brelse(ebp);
    if (sbap != &ip->i_db[0])
        brelse(sbp);
    return (ENOSPC);
}