Пример #1
0
static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
{
#ifdef EXT2FS_DEBUG
	static unsigned long alloc_hits = 0, alloc_attempts = 0;
#endif
	unsigned long result;


#ifdef EXT2_PREALLOCATE
	/* Writer: ->i_prealloc* */
	if (inode->u.ext2_i.i_prealloc_count &&
	    (goal == inode->u.ext2_i.i_prealloc_block ||
	     goal + 1 == inode->u.ext2_i.i_prealloc_block))
	{		
		result = inode->u.ext2_i.i_prealloc_block++;
		inode->u.ext2_i.i_prealloc_count--;
		/* Writer: end */
		ext2_debug ("preallocation hit (%lu/%lu).\n",
			    ++alloc_hits, ++alloc_attempts);
	} else {
		ext2_discard_prealloc (inode);
		ext2_debug ("preallocation miss (%lu/%lu).\n",
			    alloc_hits, ++alloc_attempts);
		if (S_ISREG(inode->i_mode))
			result = ext2_new_block (inode, goal, 
				 &inode->u.ext2_i.i_prealloc_count,
				 &inode->u.ext2_i.i_prealloc_block, err);
		else
			result = ext2_new_block (inode, goal, 0, 0, err);
	}
#else
	result = ext2_new_block (inode, goal, 0, 0, err);
#endif
	return result;
}
Пример #2
0
/*
 * Free an inode.
 *
 * the maintenance of the actual bitmaps is again up to the linux code
 */
int
ext2_vfree(struct vnode *pvp, ino_t ino, int mode)
{
	struct ext2_sb_info *fs;
	struct inode *pip;
	mode_t save_i_mode;

	pip = VTOI(pvp);
	fs = pip->i_e2fs;
	if ((u_int)ino > fs->s_inodes_per_group * fs->s_groups_count)
		panic("ext2_vfree: range: dev = (%d, %d), ino = %"PRId64", fs = %s",
		    major(pip->i_dev), minor(pip->i_dev), ino, fs->fs_fsmnt);

/* ext2_debug("ext2_vfree (%d, %d) called\n", pip->i_number, mode);
 */
	ext2_discard_prealloc(pip);

	/* we need to make sure that ext2_free_inode can adjust the
	   used_dir_counts in the group summary information - I'd
	   really like to know what the rationale behind this
	   'set i_mode to zero to denote an unused inode' is
	 */
	save_i_mode = pip->i_mode;
	pip->i_mode = mode;
	ext2_free_inode(pip);
	pip->i_mode = save_i_mode;
	return (0);
}
Пример #3
0
/* Writes everything from NP's inode to the disk image, and returns a pointer
   to it, or NULL if nothing need be done.  */
static struct ext2_inode *
write_node (struct node *np)
{
  error_t err;
  struct stat *st = &np->dn_stat;
  struct ext2_inode *di;

  ext2_debug ("(%llu)", np->cache_id);

  if (diskfs_node_disknode (np)->info.i_prealloc_count)
    ext2_discard_prealloc (np);

  if (np->dn_stat_dirty)
    {
      struct ext2_inode_info *info = &diskfs_node_disknode (np)->info;

      assert (!diskfs_readonly);

      ext2_debug ("writing inode %d to disk", np->cache_id);

      err = diskfs_catch_exception ();
      if (err)
	return NULL;

      di = dino_ref (np->cache_id);

      di->i_generation = st->st_gen;

      /* We happen to know that the stat mode bits are the same
	 as the ext2fs mode bits. */
      /* XXX? */

      /* Only the low 16 bits of these fields are standard across all ext2
	 implementations.  */
      di->i_mode = st->st_mode & 0xFFFF & ~S_ITRANS;
      di->i_uid = st->st_uid & 0xFFFF;
      di->i_gid = st->st_gid & 0xFFFF;

      if (sblock->s_creator_os == EXT2_OS_HURD)
	/* If this is a hurd-compatible filesystem, write the high bits too. */
	{
	  di->i_mode_high = (st->st_mode >> 16) & 0xffff & ~S_ITRANS;
	  di->i_uid_high = st->st_uid >> 16;
	  di->i_gid_high = st->st_gid >> 16;
	  di->i_author = st->st_author;
	}
      else
	/* No hurd extensions should be turned on.  */
	{
Пример #4
0
static void ext2_clear_inode(struct inode *inode)
{
#ifdef CONFIG_EXT2_FS_POSIX_ACL
	struct ext2_inode_info *ei = EXT2_I(inode);

	if (ei->i_acl && ei->i_acl != EXT2_ACL_NOT_CACHED) {
		posix_acl_release(ei->i_acl);
		ei->i_acl = EXT2_ACL_NOT_CACHED;
	}
	if (ei->i_default_acl && ei->i_default_acl != EXT2_ACL_NOT_CACHED) {
		posix_acl_release(ei->i_default_acl);
		ei->i_default_acl = EXT2_ACL_NOT_CACHED;
	}
#endif
	if (!is_bad_inode(inode))
		ext2_discard_prealloc(inode);
}
Пример #5
0
/*
 * Last reference to an inode.  If necessary, write or delete it.
 *
 * ext2_inactive(struct vnode *a_vp)
 */
int
ext2_inactive(struct vop_inactive_args *ap)
{
    struct vnode *vp = ap->a_vp;
    struct inode *ip = VTOI(vp);
    int mode, error = 0;

    ext2_discard_prealloc(ip);
    if (prtactive && vp->v_sysref.refcnt > 1)
        vprint("ext2_inactive: pushing active", vp);

    /*
     * Ignore inodes related to stale file handles.
     */
    if (ip == NULL || ip->i_mode == 0)
        goto out;
    if (ip->i_nlink <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
#ifdef QUOTA
        if (!ext2_getinoquota(ip))
            (void)ext2_chkiq(ip, -1, NOCRED, FORCE);
#endif
        error = EXT2_TRUNCATE(vp, (off_t)0, 0, NOCRED);
        ip->i_rdev = 0;
        mode = ip->i_mode;
        ip->i_mode = 0;
        ip->i_flag |= IN_CHANGE | IN_UPDATE;
        EXT2_VFREE(vp, ip->i_number, mode);
    }
    if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE))
        EXT2_UPDATE(vp, 0);
out:
    /*
     * If we are done with the inode, reclaim it
     * so that it can be reused immediately.
     */
    if (ip == NULL || ip->i_mode == 0)
        vrecycle(vp);
    return (error);
}
Пример #6
0
static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
{
#ifdef EXT2FS_DEBUG
    static unsigned long alloc_hits, alloc_attempts;
#endif
    unsigned long result;


#ifdef EXT2_PREALLOCATE
    struct ext2_inode_info *ei = EXT2_I(inode);
    write_lock(&ei->i_meta_lock);
    if (ei->i_prealloc_count &&
            (goal == ei->i_prealloc_block || goal + 1 == ei->i_prealloc_block))
    {
        result = ei->i_prealloc_block++;
        ei->i_prealloc_count--;
        write_unlock(&ei->i_meta_lock);
        ext2_debug ("preallocation hit (%lu/%lu).\n",
                    ++alloc_hits, ++alloc_attempts);
    } else {
        write_unlock(&ei->i_meta_lock);
        ext2_discard_prealloc (inode);
        ext2_debug ("preallocation miss (%lu/%lu).\n",
                    alloc_hits, ++alloc_attempts);
        if (S_ISREG(inode->i_mode))
            result = ext2_new_block (inode, goal,
                                     &ei->i_prealloc_count,
                                     &ei->i_prealloc_block, err);
        else
            result = ext2_new_block(inode, goal, NULL, NULL, err);
    }
#else
    result = ext2_new_block (inode, goal, 0, 0, err);
#endif
    return result;
}
Пример #7
0
/*
 * Called at each iput().
 *
 * The inode may be "bad" if ext2_read_inode() saw an error from
 * ext2_get_inode(), so we need to check that to avoid freeing random disk
 * blocks.
 */
void ext2_put_inode(struct inode *inode)
{
    if (!is_bad_inode(inode))
        ext2_discard_prealloc(inode);
}
Пример #8
0
/*
 * Called at each iput()
 */
void ext2_put_inode (struct inode * inode)
{
	ext2_discard_prealloc (inode);
}
Пример #9
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);
}
Пример #10
0
/*
 * Truncate the inode oip to at most length size, freeing the
 * disk blocks.
 */
int
ext2_truncate(struct vnode *vp, off_t length, int flags, struct ucred *cred)
{
    struct vnode *ovp = vp;
    daddr_t lastblock;
    struct inode *oip;
    daddr_t bn, lbn, lastiblock[NIADDR], indir_lbn[NIADDR];
    daddr_t oldblks[NDADDR + NIADDR], newblks[NDADDR + NIADDR];
    struct ext2_sb_info *fs;
    struct buf *bp;
    int offset, size, level;
    long count, nblocks, blocksreleased = 0;
    int i;
    int aflags, error, allerror;
    off_t osize;
    /*
    kprintf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length);
    */	/*
	 * negative file sizes will totally break the code below and
	 * are not meaningful anyways.
	 */
    if (length < 0)
        return EFBIG;

    oip = VTOI(ovp);
    if (ovp->v_type == VLNK &&
            oip->i_size < ovp->v_mount->mnt_maxsymlinklen) {
#if DIAGNOSTIC
        if (length != 0)
            panic("ext2_truncate: partial truncate of symlink");
#endif
        bzero((char *)&oip->i_shortlink, (u_int)oip->i_size);
        oip->i_size = 0;
        oip->i_flag |= IN_CHANGE | IN_UPDATE;
        return (EXT2_UPDATE(ovp, 1));
    }
    if (oip->i_size == length) {
        oip->i_flag |= IN_CHANGE | IN_UPDATE;
        return (EXT2_UPDATE(ovp, 0));
    }
#if QUOTA
    if ((error = ext2_getinoquota(oip)) != 0)
        return (error);
#endif
    fs = oip->i_e2fs;
    osize = oip->i_size;
    ext2_discard_prealloc(oip);
    /*
     * Lengthen the size of the file. We must ensure that the
     * last byte of the file is allocated. Since the smallest
     * value of osize is 0, length will be at least 1.
     */
    if (osize < length) {
        offset = blkoff(fs, length - 1);
        lbn = lblkno(fs, length - 1);
        aflags = B_CLRBUF;
        if (flags & IO_SYNC)
            aflags |= B_SYNC;
        vnode_pager_setsize(ovp, length);
        error = ext2_balloc(oip, lbn, offset + 1, cred, &bp, aflags);
        if (error) {
            vnode_pager_setsize(ovp, osize);
            return (error);
        }
        oip->i_size = length;
        if (aflags & IO_SYNC)
            bwrite(bp);
        else
            bawrite(bp);
        oip->i_flag |= IN_CHANGE | IN_UPDATE;
        return (EXT2_UPDATE(ovp, 1));
    }
    /*
     * Shorten the size of the file. If the file is not being
     * truncated to a block boundry, the contents of the
     * partial block following the end of the file must be
     * zero'ed in case it ever become accessable again because
     * of subsequent file growth.
     */
    /* I don't understand the comment above */
    offset = blkoff(fs, length);
    if (offset == 0) {
        oip->i_size = length;
    } else {
        lbn = lblkno(fs, length);
        aflags = B_CLRBUF;
        if (flags & IO_SYNC)
            aflags |= B_SYNC;
        error = ext2_balloc(oip, lbn, offset, cred, &bp, aflags);
        if (error)
            return (error);
        oip->i_size = length;
        size = blksize(fs, oip, lbn);
        bzero((char *)bp->b_data + offset, (u_int)(size - offset));
        allocbuf(bp, size);
        if (aflags & IO_SYNC)
            bwrite(bp);
        else
            bawrite(bp);
    }
    /*
     * Calculate index into inode's block list of
     * last direct and indirect blocks (if any)
     * which we want to keep.  Lastblock is -1 when
     * the file is truncated to 0.
     */
    lastblock = lblkno(fs, length + fs->s_blocksize - 1) - 1;
    lastiblock[SINGLE] = lastblock - NDADDR;
    lastiblock[DOUBLE] = lastiblock[SINGLE] - NINDIR(fs);
    lastiblock[TRIPLE] = lastiblock[DOUBLE] - NINDIR(fs) * NINDIR(fs);
    nblocks = btodb(fs->s_blocksize);
    /*
     * Update file and block pointers on disk before we start freeing
     * blocks.  If we crash before free'ing blocks below, the blocks
     * will be returned to the free list.  lastiblock values are also
     * normalized to -1 for calls to ext2_indirtrunc below.
     */
    bcopy((caddr_t)&oip->i_db[0], (caddr_t)oldblks, sizeof oldblks);
    for (level = TRIPLE; level >= SINGLE; level--)
        if (lastiblock[level] < 0) {
            oip->i_ib[level] = 0;
            lastiblock[level] = -1;
        }
    for (i = NDADDR - 1; i > lastblock; i--)
        oip->i_db[i] = 0;
    oip->i_flag |= IN_CHANGE | IN_UPDATE;
    allerror = EXT2_UPDATE(ovp, 1);

    /*
     * Having written the new inode to disk, save its new configuration
     * and put back the old block pointers long enough to process them.
     * Note that we save the new block configuration so we can check it
     * when we are done.
     */
    bcopy((caddr_t)&oip->i_db[0], (caddr_t)newblks, sizeof newblks);
    bcopy((caddr_t)oldblks, (caddr_t)&oip->i_db[0], sizeof oldblks);
    oip->i_size = osize;
    error = vtruncbuf(ovp, length, (int)fs->s_blocksize);
    if (error && (allerror == 0))
        allerror = error;

    /*
     * Indirect blocks first.
     */
    indir_lbn[SINGLE] = -NDADDR;
    indir_lbn[DOUBLE] = indir_lbn[SINGLE] - NINDIR(fs) - 1;
    indir_lbn[TRIPLE] = indir_lbn[DOUBLE] - NINDIR(fs) * NINDIR(fs) - 1;
    for (level = TRIPLE; level >= SINGLE; level--) {
        bn = oip->i_ib[level];
        if (bn != 0) {
            error = ext2_indirtrunc(oip, indir_lbn[level],
                                    fsbtodoff(fs, bn), lastiblock[level], level, &count);
            if (error)
                allerror = error;
            blocksreleased += count;
            if (lastiblock[level] < 0) {
                oip->i_ib[level] = 0;
                ext2_blkfree(oip, bn, fs->s_frag_size);
                blocksreleased += nblocks;
            }
        }
        if (lastiblock[level] >= 0)
            goto done;
    }

    /*
     * All whole direct blocks or frags.
     */
    for (i = NDADDR - 1; i > lastblock; i--) {
        long bsize;

        bn = oip->i_db[i];
        if (bn == 0)
            continue;
        oip->i_db[i] = 0;
        bsize = blksize(fs, oip, i);
        ext2_blkfree(oip, bn, bsize);
        blocksreleased += btodb(bsize);
    }
    if (lastblock < 0)
        goto done;

    /*
     * Finally, look for a change in size of the
     * last direct block; release any frags.
     */
    bn = oip->i_db[lastblock];
    if (bn != 0) {
        long oldspace, newspace;

        /*
         * Calculate amount of space we're giving
         * back as old block size minus new block size.
         */
        oldspace = blksize(fs, oip, lastblock);
        oip->i_size = length;
        newspace = blksize(fs, oip, lastblock);
        if (newspace == 0)
            panic("itrunc: newspace");
        if (oldspace - newspace > 0) {
            /*
             * Block number of space to be free'd is
             * the old block # plus the number of frags
             * required for the storage we're keeping.
             */
            bn += numfrags(fs, newspace);
            ext2_blkfree(oip, bn, oldspace - newspace);
            blocksreleased += btodb(oldspace - newspace);
        }
    }
done:
#if DIAGNOSTIC
    for (level = SINGLE; level <= TRIPLE; level++)
        if (newblks[NDADDR + level] != oip->i_ib[level])
            panic("itrunc1");
    for (i = 0; i < NDADDR; i++)
        if (newblks[i] != oip->i_db[i])
            panic("itrunc2");
    if (length == 0 && (!RB_EMPTY(&ovp->v_rbdirty_tree) ||
                        !RB_EMPTY(&ovp->v_rbclean_tree)))
        panic("itrunc3");
#endif /* DIAGNOSTIC */
    /*
     * Put back the real size.
     */
    oip->i_size = length;
    oip->i_blocks -= blocksreleased;
    if (oip->i_blocks < 0)			/* sanity */
        oip->i_blocks = 0;
    oip->i_flag |= IN_CHANGE;
    vnode_pager_setsize(ovp, length);
#if QUOTA
    ext2_chkdq(oip, -blocksreleased, NOCRED, 0);
#endif
    return (allerror);
}
/*
 * Called when an inode is released. Note that this is different
 * from ext2_open_file: open gets called at every open, but release
 * gets called only when /all/ the files are closed.
 */
static int ext2_release_file (struct inode * inode, struct file * filp)
{
	if (filp->f_mode & FMODE_WRITE)
		ext2_discard_prealloc (inode);
	return 0;
}
Пример #12
0
/*
 * Called when an inode is released. Note that this is different
 * from ext2_open_file: open gets called at every open, but release
 * gets called only when /all/ the files are closed.
 */
static int ext2_release_file (struct _inode * inode, struct file * filp)
{
	if (tx_cache_get_file_ro(filp)->f_mode & FMODE_WRITE)
		ext2_discard_prealloc (parent(inode));
	return 0;
}