Ejemplo n.º 1
0
/*
 * Allocate an inode in the file system.
 *
 * we leave the actual allocation strategy to the (modified)
 * ext2_new_inode(), to make sure we get the policies right
 */
int
ext2_valloc(struct vnode *pvp, int mode, struct ucred *cred, struct vnode **vpp)
{
	struct inode *pip;
	struct ext2_sb_info *fs;
	struct inode *ip;
	ino_t ino;
	int i, error;

	*vpp = NULL;
	pip = VTOI(pvp);
	fs = pip->i_e2fs;
	if (fs->s_es->s_free_inodes_count == 0)
		goto noinodes;

	/* call the Linux routine - it returns the inode number only */
	ino = ext2_new_inode(pip, mode);

	if (ino == 0)
		goto noinodes;
	error = VFS_VGET(pvp->v_mount, NULL, ino, 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's allocating a
	  new one. I will set at least i_size & i_blocks the zero.
	*/
	ip->i_mode = 0;
	ip->i_size = 0;
	ip->i_blocks = 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 = krandom() / 2 + 1;
/*
kprintf("ext2_valloc: allocated inode %d\n", ino);
*/
	return (0);
noinodes:
	ext2_fserr(fs, cred->cr_uid, "out of inodes");
	uprintf("\n%s: create/symlink failed, no inodes free\n", fs->fs_fsmnt);
	return (ENOSPC);
}
Ejemplo n.º 2
0
/*
 * 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);
}
Ejemplo n.º 3
0
/*
 * 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);
}
Ejemplo n.º 4
0
/*
 *	inode to raw ext2 inode
 */
int
ext2_i2ei(struct inode *ip, struct ext2fs_dinode *ei)
{
	struct m_ext2fs *fs;

	fs = ip->i_e2fs;
	ei->e2di_mode = ip->i_mode;
	ei->e2di_nlink = ip->i_nlink;
	/*
	 * Godmar thinks: if dtime is nonzero, ext2 says this inode has been
	 * deleted, this would correspond to a zero link count
	 */
	ei->e2di_dtime = ei->e2di_nlink ? 0 : ip->i_mtime;
	ei->e2di_size = ip->i_size;
	if (S_ISREG(ip->i_mode))
		ei->e2di_size_high = ip->i_size >> 32;
	ei->e2di_atime = ip->i_atime;
	ei->e2di_mtime = ip->i_mtime;
	ei->e2di_ctime = ip->i_ctime;
	if (E2DI_HAS_XTIME(ip)) {
		ei->e2di_ctime_extra = NSEC_TO_XTIME(ip->i_ctimensec);
		ei->e2di_mtime_extra = NSEC_TO_XTIME(ip->i_mtimensec);
		ei->e2di_atime_extra = NSEC_TO_XTIME(ip->i_atimensec);
		ei->e2di_crtime = ip->i_birthtime;
		ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec);
	}
	ei->e2di_flags = 0;
	ei->e2di_flags |= (ip->i_flags & SF_APPEND) ? EXT2_APPEND : 0;
	ei->e2di_flags |= (ip->i_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE : 0;
	ei->e2di_flags |= (ip->i_flags & UF_NODUMP) ? EXT2_NODUMP : 0;
	ei->e2di_flags |= (ip->i_flag & IN_E3INDEX) ? EXT3_INDEX : 0;
	ei->e2di_flags |= (ip->i_flag & IN_E4EXTENTS) ? EXT4_EXTENTS : 0;
	if (ip->i_blocks > ~0U &&
	    !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE)) {
		ext2_fserr(fs, ip->i_uid, "i_blocks value is out of range");
		return (EIO);
	}
	if (ip->i_blocks <= 0xffffffffffffULL) {
		ei->e2di_nblock = ip->i_blocks & 0xffffffff;
		ei->e2di_nblock_high = ip->i_blocks >> 32 & 0xffff;
	} else {
Ejemplo n.º 5
0
/*
 * Allocate a block in the file system.
 *
 * this takes the framework from ffs_alloc. To implement the
 * actual allocation, it calls ext2_new_block, the ported version
 * of the same Linux routine.
 *
 * we note that this is always called in connection with ext2_blkpref
 *
 * preallocation is done as Linux does it
 */
int
ext2_alloc(struct inode *ip, daddr_t lbn, daddr_t bpref, int size,
	   struct ucred *cred, daddr_t *bnp)
{
	struct ext2_sb_info *fs;
	daddr_t bno;
#if QUOTA
	int error;
#endif

	*bnp = 0;
	fs = ip->i_e2fs;
#if DIAGNOSTIC
	if ((u_int)size > fs->s_blocksize || blkoff(fs, size) != 0) {
		kprintf("dev = %s, bsize = %lu, size = %d, fs = %s\n",
		    devtoname(ip->i_dev), fs->s_blocksize, size, fs->fs_fsmnt);
		panic("ext2_alloc: bad size");
	}
	if (cred == NOCRED)
		panic("ext2_alloc: missing credential");
#endif /* DIAGNOSTIC */
	if (size == fs->s_blocksize && fs->s_es->s_free_blocks_count == 0)
		goto nospace;
	if (cred->cr_uid != 0 &&
		fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count)
		goto nospace;
#if QUOTA
	if ((error = ext2_chkdq(ip, (long)btodb(size), cred, 0)) != 0)
		return (error);
#endif
	if (bpref >= fs->s_es->s_blocks_count)
		bpref = 0;
	/* call the Linux code */
#ifdef EXT2_PREALLOCATE
	/* To have a preallocation hit, we must
	 * - have at least one block preallocated
	 * - and our preferred block must have that block number or one below
	 */
        if (ip->i_prealloc_count &&
            (bpref == ip->i_prealloc_block ||
             bpref + 1 == ip->i_prealloc_block))
        {
                bno = ip->i_prealloc_block++;
                ip->i_prealloc_count--;
                /* ext2_debug ("preallocation hit (%lu/%lu).\n",
                            ++alloc_hits, ++alloc_attempts); */

		/* Linux gets, clears, and releases the buffer at this
		   point - we don't have to that; we leave it to the caller
		 */
        } else {
                ext2_discard_prealloc (ip);
                /* ext2_debug ("preallocation miss (%lu/%lu).\n",
                            alloc_hits, ++alloc_attempts); */
                if (S_ISREG(ip->i_mode))
                        bno = ext2_new_block
                                (ITOV(ip)->v_mount, bpref,
                                 &ip->i_prealloc_count,
                                 &ip->i_prealloc_block);
                else
			bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount,
					bpref, 0, 0);
        }
#else
	bno = (daddr_t)ext2_new_block(ITOV(ip)->v_mount, bpref, 0, 0);
#endif

	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(size);
		ip->i_flag |= IN_CHANGE | IN_UPDATE;
		*bnp = bno;
		return (0);
	}
#if QUOTA
	/*
	 * Restore user's disk quota because allocation failed.
	 */
	ext2_chkdq(ip, (long)-btodb(size), cred, FORCE);
#endif
nospace:
	ext2_fserr(fs, cred->cr_uid, "file system full");
	uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt);
	return (ENOSPC);
}
Ejemplo n.º 6
0
/*
 * 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);
}