Esempio n. 1
0
static void
xfs_bmbt_to_iomap(
	struct xfs_inode	*ip,
	struct iomap		*iomap,
	struct xfs_bmbt_irec	*imap)
{
	struct xfs_mount	*mp = ip->i_mount;

	if (imap->br_startblock == HOLESTARTBLOCK) {
		iomap->blkno = IOMAP_NULL_BLOCK;
		iomap->type = IOMAP_HOLE;
	} else if (imap->br_startblock == DELAYSTARTBLOCK) {
		iomap->blkno = IOMAP_NULL_BLOCK;
		iomap->type = IOMAP_DELALLOC;
	} else {
		iomap->blkno =
			XFS_FSB_TO_DADDR(ip->i_mount, imap->br_startblock);
		if (imap->br_state == XFS_EXT_UNWRITTEN)
			iomap->type = IOMAP_UNWRITTEN;
		else
			iomap->type = IOMAP_MAPPED;
	}
	iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff);
	iomap->length = XFS_FSB_TO_B(mp, imap->br_blockcount);
}
Esempio n. 2
0
/*
 * Inode btree record insertion/removal modifies the inode btree and free space
 * btrees (since the inobt does not use the agfl). This requires the following
 * reservation:
 *
 * the inode btree: max depth * blocksize
 * the allocation btrees: 2 trees * (max depth - 1) * block size
 *
 * The caller must account for SB and AG header modifications, etc.
 */
STATIC uint
xfs_calc_inobt_res(
	struct xfs_mount	*mp)
{
	return xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
				 XFS_FSB_TO_B(mp, 1));
}
static int
_xfs_bmap(
	struct vop_bmap_args /* {
		struct vnode *a_vp;
		daddr_t  a_bn;
		struct bufobj **a_bop;
		daddr_t *a_bnp;
		int *a_runp;
		int *a_runb;
	} */ *ap)
{
	xfs_iomap_t iomap;
	xfs_off_t offset;
	ssize_t   size;
	struct mount *mp;
	struct xfs_mount *xmp;
	struct xfs_vnode *xvp;
	int error, maxrun, retbm;

	mp  = ap->a_vp->v_mount;
	xmp = XFS_VFSTOM(MNTTOVFS(mp));
	if (ap->a_bop != NULL)
		*ap->a_bop = &xmp->m_ddev_targp->specvp->v_bufobj;
	if (ap->a_bnp == NULL)
		return (0);

	xvp = VPTOXFSVP(ap->a_vp);
	retbm = 1;

	offset = XFS_FSB_TO_B(xmp, ap->a_bn);
	size = XFS_FSB_TO_B(xmp, 1);
	XVOP_BMAP(xvp, offset, size, BMAPI_READ, &iomap, &retbm, error);
	if (error)
		return (error);
	if (retbm == 0 || iomap.iomap_bn == IOMAP_DADDR_NULL) {
		*ap->a_bnp = (daddr_t)-1;
		if (ap->a_runb)
			*ap->a_runb = 0;
		if (ap->a_runp)
			*ap->a_runp = 0;
	} else {
		*ap->a_bnp = iomap.iomap_bn + btodb(iomap.iomap_delta);
		maxrun = mp->mnt_iosize_max / mp->mnt_stat.f_iosize - 1;
		if (ap->a_runb) {
			*ap->a_runb = XFS_B_TO_FSB(xmp, iomap.iomap_delta);
			if (*ap->a_runb > maxrun)
				*ap->a_runb  = maxrun;
		}
		if (ap->a_runp) {
			*ap->a_runp =
			    XFS_B_TO_FSB(xmp, iomap.iomap_bsize
				- iomap.iomap_delta - size);
			if (*ap->a_runp > maxrun)
				*ap->a_runp  = maxrun;
		}
	}
	return (0);
}
Esempio n. 4
0
/*
 * trim a range of the filesystem.
 *
 * Note: the parameters passed from userspace are byte ranges into the
 * filesystem which does not match to the format we use for filesystem block
 * addressing. FSB addressing is sparse (AGNO|AGBNO), while the incoming format
 * is a linear address range. Hence we need to use DADDR based conversions and
 * comparisons for determining the correct offset and regions to trim.
 */
int
xfs_ioc_trim(
	struct xfs_mount		*mp,
	struct fstrim_range __user	*urange)
{
	struct request_queue	*q = bdev_get_queue(mp->m_ddev_targp->bt_bdev);
	unsigned int		granularity = q->limits.discard_granularity;
	struct fstrim_range	range;
	xfs_daddr_t		start, end, minlen;
	xfs_agnumber_t		start_agno, end_agno, agno;
	__uint64_t		blocks_trimmed = 0;
	int			error, last_error = 0;

	if (!capable(CAP_SYS_ADMIN))
		return -XFS_ERROR(EPERM);
	if (!blk_queue_discard(q))
		return -XFS_ERROR(EOPNOTSUPP);
	if (copy_from_user(&range, urange, sizeof(range)))
		return -XFS_ERROR(EFAULT);

	/*
	 * Truncating down the len isn't actually quite correct, but using
	 * BBTOB would mean we trivially get overflows for values
	 * of ULLONG_MAX or slightly lower.  And ULLONG_MAX is the default
	 * used by the fstrim application.  In the end it really doesn't
	 * matter as trimming blocks is an advisory interface.
	 */
	if (range.start >= XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks) ||
	    range.minlen > XFS_FSB_TO_B(mp, XFS_ALLOC_AG_MAX_USABLE(mp)) ||
	    range.len < mp->m_sb.sb_blocksize)
		return -XFS_ERROR(EINVAL);

	start = BTOBB(range.start);
	end = start + BTOBBT(range.len) - 1;
	minlen = BTOBB(max_t(u64, granularity, range.minlen));

	if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1)
		end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1;

	start_agno = xfs_daddr_to_agno(mp, start);
	end_agno = xfs_daddr_to_agno(mp, end);

	for (agno = start_agno; agno <= end_agno; agno++) {
		error = -xfs_trim_extents(mp, agno, start, end, minlen,
					  &blocks_trimmed);
		if (error)
			last_error = error;
	}

	if (last_error)
		return last_error;

	range.len = XFS_FSB_TO_B(mp, blocks_trimmed);
	if (copy_to_user(urange, &range, sizeof(range)))
		return -XFS_ERROR(EFAULT);
	return 0;
}
Esempio n. 5
0
/*
 * For create we can modify:
 *    the parent directory inode: inode size
 *    the new inode: inode size
 *    the inode btree entry: block size
 *    the superblock for the nlink flag: sector size
 *    the directory btree: (max depth + v2) * dir block size
 *    the directory inode's bmap btree: (max depth + v2) * block size
 *    the finobt (record modification and allocation btrees)
 */
STATIC uint
xfs_calc_create_resv_modify(
	struct xfs_mount	*mp)
{
	return xfs_calc_inode_res(mp, 2) +
		xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
		(uint)XFS_FSB_TO_B(mp, 1) +
		xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_finobt_res(mp, 1, 1);
}
Esempio n. 6
0
int extent_overlaps_buffer(xfs_mount_t *mp, xfs_bmbt_irec_t rec, off_t offset, size_t len) {
    size_t extent_size = XFS_FSB_TO_B(mp, rec.br_blockcount);
    size_t extent_start = XFS_FSB_TO_B(mp, rec.br_startoff);
    
    /* check that the extent overlaps the intended read area */
    /* First: the offset lies in the extent */
    if ((extent_start <= offset) && (offset < extent_start + extent_size)) return 1;
    /* Second: the extent start lies in the buffer */
    if ((offset <= extent_start) && (extent_start < offset + len)) return 1;
    return 0;
}
Esempio n. 7
0
int copy_extent_to_buffer(xfs_mount_t *mp, xfs_bmbt_irec_t rec, void *buffer, off_t offset, size_t len) {
    xfs_buf_t *block_buffer;
    int64_t copylen, copy_start;
    xfs_daddr_t block, start, end;
    char *src;
    off_t cofs = offset;
    
    xfs_off_t block_start;
    xfs_daddr_t block_size = XFS_FSB_TO_B(mp, 1);
    //xfs_daddr_t extent_size = XFS_FSB_TO_B(mp, rec.br_blockcount);
    xfs_daddr_t extent_start = XFS_FSB_TO_B(mp, rec.br_startoff);

    /* compute a block to start reading from */
    if (offset >= extent_start) {
        start = XFS_B_TO_FSBT(mp, offset - extent_start);
    } else {
        buffer = buffer + extent_start - offset;
        cofs += extent_start - offset;
        start = 0;
    }

    end = min(rec.br_blockcount, XFS_B_TO_FSBT(mp, offset + len - extent_start - 1) + 1);

    for (block=start; block<end; block++) {
        block_start = XFS_FSB_TO_B(mp, (rec.br_startoff + block));        
        block_buffer = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, (rec.br_startblock + block)), 
                                      XFS_FSB_TO_BB(mp, 1), 0);
        if (block_buffer == NULL) {
            printf("Buffer error\n");
            return XFS_ERROR(EIO);
        }

        src = block_buffer->b_addr;
        copy_start = block_start;
        copylen = block_size;
        if (block_start < offset) {
            copylen = block_size + block_start - offset;
            copy_start = (block_size - copylen) + block_start;
            src = block_buffer->b_addr + (block_size - copylen);
        }
        if ((block_start + block_size) > (offset + len)) {
            copylen = offset + len - copy_start;
        }

        if (copylen > 0) {
            memcpy(buffer, src, copylen);
            buffer += copylen;
            cofs += copylen;
        }
        libxfs_putbuf(block_buffer);
    }
    
    return 0;
}
Esempio n. 8
0
/*
 * Removing the attribute fork of a file
 *    the inode being truncated: inode size
 *    the inode's bmap btree: max depth * block size
 * And the bmap_finish transaction can free the blocks and bmap blocks:
 *    the agf for each of the ags: 4 * sector size
 *    the agfl for each of the ags: 4 * sector size
 *    the super block to reflect the freed blocks: sector size
 *    worst case split in allocation btrees per extent assuming 4 extents:
 *		4 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_attrinval_reservation(
	struct xfs_mount	*mp)
{
	return max((xfs_calc_inode_res(mp, 1) +
		    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
				     XFS_FSB_TO_B(mp, 1))),
		   (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
		    xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4),
				     XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 9
0
/*
 * For icreate we can allocate some inodes giving:
 *    the agi and agf of the ag getting the new inodes: 2 * sectorsize
 *    the superblock for the nlink flag: sector size
 *    the inode btree: max depth * blocksize
 *    the allocation btrees: 2 trees * (max depth - 1) * block size
 *    the finobt (record insertion)
 */
STATIC uint
xfs_calc_icreate_resv_alloc(
	struct xfs_mount	*mp)
{
	return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
		mp->m_sb.sb_sectsize +
		xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
				 XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_finobt_res(mp, 0, 0);
}
Esempio n. 10
0
/*
 * Removing the attribute fork of a file
 *    the inode being truncated: inode size
 *    the inode's bmap btree: max depth * block size
 * And the bmap_finish transaction can free the blocks and bmap blocks:
 *    the agf for each of the ags: 4 * sector size
 *    the agfl for each of the ags: 4 * sector size
 *    the super block to reflect the freed blocks: sector size
 *    worst case split in allocation btrees per extent assuming 4 extents:
 *		4 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_attrinval_reservation(
	struct xfs_mount	*mp)
{
	return MAX((xfs_calc_inode_res(mp, 1) +
		    xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
				     XFS_FSB_TO_B(mp, 1))),
		   (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
		    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
				     XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 11
0
/*
 * Growing the rt section of the filesystem.
 * In the first set of transactions (ALLOC) we allocate space to the
 * bitmap or summary files.
 *	superblock: sector size
 *	agf of the ag from which the extent is allocated: sector size
 *	bmap btree for bitmap/summary inode: max depth * blocksize
 *	bitmap/summary inode: inode size
 *	allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize
 */
STATIC uint
xfs_calc_growrtalloc_reservation(
	struct xfs_mount	*mp)
{
	return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK),
				 XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_inode_res(mp, 1) +
		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
				 XFS_FSB_TO_B(mp, 1));
}
Esempio n. 12
0
/*
 * In renaming a files we can modify:
 *    the four inodes involved: 4 * inode size
 *    the two directory btrees: 2 * (max depth + v2) * dir block size
 *    the two directory bmap btrees: 2 * max depth * block size
 * And the bmap_finish transaction can free dir and bmap blocks (two sets
 *	of bmap blocks) giving:
 *    the agf for the ags in which the blocks live: 3 * sector size
 *    the agfl for the ags in which the blocks live: 3 * sector size
 *    the superblock for the free block count: sector size
 *    the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_rename_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		MAX((xfs_calc_inode_res(mp, 4) +
		     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
				      XFS_FSB_TO_B(mp, 1))),
		    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 3),
				      XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 13
0
/*
 * In truncating a file we free up to two extents at once.  We can modify:
 *    the inode being truncated: inode size
 *    the inode's bmap btree: (max depth + 1) * block size
 * And the bmap_finish transaction can free the blocks and bmap blocks:
 *    the agf for each of the ags: 4 * sector size
 *    the agfl for each of the ags: 4 * sector size
 *    the super block to reflect the freed blocks: sector size
 *    worst case split in allocation btrees per extent assuming 4 extents:
 *		4 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_itruncate_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		max((xfs_calc_inode_res(mp, 1) +
		     xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1,
				      XFS_FSB_TO_B(mp, 1))),
		    (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4),
				      XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 14
0
/*
 * In renaming a files we can modify:
 *    the four inodes involved: 4 * inode size
 *    the two directory btrees: 2 * (max depth + v2) * dir block size
 *    the two directory bmap btrees: 2 * max depth * block size
 * And the bmap_finish transaction can free dir and bmap blocks (two sets
 *	of bmap blocks) giving:
 *    the agf for the ags in which the blocks live: 3 * sector size
 *    the agfl for the ags in which the blocks live: 3 * sector size
 *    the superblock for the free block count: sector size
 *    the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_rename_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		max((xfs_calc_inode_res(mp, 4) +
		     xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp),
				      XFS_FSB_TO_B(mp, 1))),
		    (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(xfs_allocfree_log_count(mp, 3),
				      XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 15
0
STATIC int
xfs_imap_to_bmap(
	xfs_iocore_t	*io,
	xfs_off_t	offset,
	xfs_bmbt_irec_t *imap,
	xfs_iomap_t	*iomapp,
	int		imaps,			/* Number of imap entries */
	int		iomaps,			/* Number of iomap entries */
	int		flags)
{
	xfs_mount_t	*mp;
	xfs_fsize_t	nisize;
	int		pbm;
	xfs_fsblock_t	start_block;

	mp = io->io_mount;
	nisize = XFS_SIZE(mp, io);
	if (io->io_new_size > nisize)
		nisize = io->io_new_size;

	for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) {
		iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
		iomapp->iomap_delta = offset - iomapp->iomap_offset;
		iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
		iomapp->iomap_flags = flags;

		if (io->io_flags & XFS_IOCORE_RT) {
			iomapp->iomap_flags |= IOMAP_REALTIME;
			iomapp->iomap_target = mp->m_rtdev_targp;
		} else {
			iomapp->iomap_target = mp->m_ddev_targp;
		}
		start_block = imap->br_startblock;
		if (start_block == HOLESTARTBLOCK) {
			iomapp->iomap_bn = IOMAP_DADDR_NULL;
			iomapp->iomap_flags |= IOMAP_HOLE;
		} else if (start_block == DELAYSTARTBLOCK) {
			iomapp->iomap_bn = IOMAP_DADDR_NULL;
			iomapp->iomap_flags |= IOMAP_DELAY;
		} else {
			iomapp->iomap_bn = XFS_FSB_TO_DB_IO(io, start_block);
			if (ISUNWRITTEN(imap))
				iomapp->iomap_flags |= IOMAP_UNWRITTEN;
		}

		if ((iomapp->iomap_offset + iomapp->iomap_bsize) >= nisize) {
			iomapp->iomap_flags |= IOMAP_EOF;
		}

		offset += iomapp->iomap_bsize - iomapp->iomap_delta;
	}
	return pbm;	/* Return the number filled */
}
Esempio n. 16
0
/*
 * Converting the inode from non-attributed to attributed.
 *	the inode being converted: inode size
 *	agf block and superblock (for block allocation)
 *	the new block (directory sized)
 *	bmap blocks for the new directory block
 *	allocation btrees
 */
STATIC uint
xfs_calc_addafork_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		xfs_calc_inode_res(mp, 1) +
		xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(1, mp->m_dir_geo->blksize) +
		xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1,
				 XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
				 XFS_FSB_TO_B(mp, 1));
}
Esempio n. 17
0
/*
 * For creating a link to an inode:
 *    the parent directory inode: inode size
 *    the linked inode: inode size
 *    the directory btree could split: (max depth + v2) * dir block size
 *    the directory bmap btree could join or split: (max depth + v2) * blocksize
 * And the bmap_finish transaction can free some bmap blocks giving:
 *    the agf for the ag in which the blocks live: sector size
 *    the agfl for the ag in which the blocks live: sector size
 *    the superblock for the free block count: sector size
 *    the allocation btrees: 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_link_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		xfs_calc_iunlink_remove_reservation(mp) +
		max((xfs_calc_inode_res(mp, 2) +
		     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
				      XFS_FSB_TO_B(mp, 1))),
		    (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
				      XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 18
0
/*
 * For removing a directory entry we can modify:
 *    the parent directory inode: inode size
 *    the removed inode: inode size
 *    the directory btree could join: (max depth + v2) * dir block size
 *    the directory bmap btree could join or split: (max depth + v2) * blocksize
 * And the bmap_finish transaction can free the dir and bmap blocks giving:
 *    the agf for the ag in which the blocks live: 2 * sector size
 *    the agfl for the ag in which the blocks live: 2 * sector size
 *    the superblock for the free block count: sector size
 *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_remove_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		xfs_calc_iunlink_add_reservation(mp) +
		MAX((xfs_calc_inode_res(mp, 1) +
		     xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp),
				      XFS_FSB_TO_B(mp, 1))),
		    (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
				      XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 19
0
STATIC int
xfs_iomap_eof_align_last_fsb(
	xfs_mount_t	*mp,
	xfs_iocore_t	*io,
	xfs_fsize_t	isize,
	xfs_extlen_t	extsize,
	xfs_fileoff_t	*last_fsb)
{
	xfs_fileoff_t	new_last_fsb = 0;
	xfs_extlen_t	align;
	int		eof, error;

	if (io->io_flags & XFS_IOCORE_RT)
		;
	/*
	 * If mounted with the "-o swalloc" option, roundup the allocation
	 * request to a stripe width boundary if the file size is >=
	 * stripe width and we are allocating past the allocation eof.
	 */
	else if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC) &&
	        (isize >= XFS_FSB_TO_B(mp, mp->m_swidth)))
		new_last_fsb = roundup_64(*last_fsb, mp->m_swidth);
	/*
	 * Roundup the allocation request to a stripe unit (m_dalign) boundary
	 * if the file size is >= stripe unit size, and we are allocating past
	 * the allocation eof.
	 */
	else if (mp->m_dalign && (isize >= XFS_FSB_TO_B(mp, mp->m_dalign)))
		new_last_fsb = roundup_64(*last_fsb, mp->m_dalign);

	/*
	 * Always round up the allocation request to an extent boundary
	 * (when file on a real-time subvolume or has di_extsize hint).
	 */
	if (extsize) {
		if (new_last_fsb)
			align = roundup_64(new_last_fsb, extsize);
		else
			align = extsize;
		new_last_fsb = roundup_64(*last_fsb, align);
	}

	if (new_last_fsb) {
		error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
		if (error)
			return error;
		if (eof)
			*last_fsb = new_last_fsb;
	}
	return 0;
}
Esempio n. 20
0
/*
 * Removing an attribute.
 *    the inode: inode size
 *    the attribute btree could join: max depth * block size
 *    the inode bmap btree could join or split: max depth * block size
 * And the bmap_finish transaction can free the attr blocks freed giving:
 *    the agf for the ag in which the blocks live: 2 * sector size
 *    the agfl for the ag in which the blocks live: 2 * sector size
 *    the superblock for the free block count: sector size
 *    the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size
 */
STATIC uint
xfs_calc_attrrm_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		MAX((xfs_calc_inode_res(mp, 1) +
		     xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH,
				      XFS_FSB_TO_B(mp, 1)) +
		     (uint)XFS_FSB_TO_B(mp,
					XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) +
		     xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)),
		    (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 2),
				      XFS_FSB_TO_B(mp, 1))));
}
Esempio n. 21
0
/*
 * In freeing an inode we can modify:
 *    the inode being freed: inode size
 *    the super block free inode counter: sector size
 *    the agi hash list and counters: sector size
 *    the inode btree entry: block size
 *    the on disk inode before ours in the agi hash list: inode cluster size
 *    the inode btree: max depth * blocksize
 *    the allocation btrees: 2 trees * (max depth - 1) * block size
 *    the finobt (record insertion, removal or modification)
 */
STATIC uint
xfs_calc_ifree_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		xfs_calc_inode_res(mp, 1) +
		xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_iunlink_remove_reservation(mp) +
		xfs_calc_buf_res(1, 0) +
		xfs_calc_buf_res(2 + mp->m_ialloc_blks +
				 mp->m_in_maxlevels, 0) +
		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
				 XFS_FSB_TO_B(mp, 1)) +
		xfs_calc_finobt_res(mp, 0, 1);
}
Esempio n. 22
0
/*
 * For removing an inode from unlinked list at first, we can modify:
 *    the agi hash list and counters: sector size
 *    the on disk inode before ours in the agi hash list: inode cluster size
 */
STATIC uint
xfs_calc_iunlink_remove_reservation(
	struct xfs_mount        *mp)
{
	return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
	       max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size);
}
Esempio n. 23
0
/*
 * This routine is called to handle zeroing any space in the last
 * block of the file that is beyond the EOF.  We do this since the
 * size is being increased without writing anything to that block
 * and we don't want anyone to read the garbage on the disk.
 */
STATIC int				/* error (positive) */
xfs_zero_last_block(
	xfs_vnode_t	*vp,
	xfs_iocore_t	*io,
	xfs_fsize_t	isize,
	xfs_fsize_t	end_size)
{
	xfs_fileoff_t	last_fsb;
	xfs_mount_t	*mp;
	int		nimaps;
	int		zero_offset;
	int		zero_len;
	int		error = 0;
	xfs_bmbt_irec_t	imap;
	xfs_off_t	loff;

	ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);

	mp = io->io_mount;

	zero_offset = XFS_B_FSB_OFFSET(mp, isize);
	if (zero_offset == 0) {
		/*
		 * There are no extra bytes in the last block on disk to
		 * zero, so return.
		 */
		return 0;
	}

	last_fsb = XFS_B_TO_FSBT(mp, isize);
	nimaps = 1;
	error = XFS_BMAPI(mp, NULL, io, last_fsb, 1, 0, NULL, 0, &imap,
			  &nimaps, NULL, NULL);
	if (error) {
		return error;
	}
	ASSERT(nimaps > 0);
	/*
	 * If the block underlying isize is just a hole, then there
	 * is nothing to zero.
	 */
	if (imap.br_startblock == HOLESTARTBLOCK) {
		return 0;
	}
	/*
	 * Zero the part of the last block beyond the EOF, and write it
	 * out sync.  We need to drop the ilock while we do this so we
	 * don't deadlock when the buffer cache calls back to us.
	 */
	XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD);
	loff = XFS_FSB_TO_B(mp, last_fsb);

	zero_len = mp->m_sb.sb_blocksize - zero_offset;

	error = xfs_iozero(vp, loff + zero_offset, zero_len, end_size);

	XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD);
	ASSERT(error >= 0);
	return error;
}
Esempio n. 24
0
/*
 * Growing the data section of the filesystem.
 *	superblock
 *	agi and agf
 *	allocation btrees
 */
STATIC uint
xfs_calc_growdata_reservation(
	struct xfs_mount	*mp)
{
	return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
				 XFS_FSB_TO_B(mp, 1));
}
Esempio n. 25
0
/*
 * Growing the data section of the filesystem.
 *	superblock
 *	agi and agf
 *	allocation btrees
 */
STATIC uint
xfs_calc_growdata_reservation(
	struct xfs_mount	*mp)
{
	return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1),
				 XFS_FSB_TO_B(mp, 1));
}
Esempio n. 26
0
/*
 * Allocating quota on disk if needed.
 *	the write transaction log space for quota file extent allocation
 *	the unit of quota allocation: one system block size
 */
STATIC uint
xfs_calc_qm_dqalloc_reservation(
	struct xfs_mount	*mp)
{
	return xfs_calc_write_reservation(mp) +
		xfs_calc_buf_res(1,
			XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1);
}
Esempio n. 27
0
/*
 * In truncating a file we free up to two extents at once.  We can modify:
 *    the inode being truncated: inode size
 *    the inode's bmap btree: (max depth + 1) * block size
 * And the bmap_finish transaction can free the blocks and bmap blocks:
 *    the agf for each of the ags: 4 * sector size
 *    the agfl for each of the ags: 4 * sector size
 *    the super block to reflect the freed blocks: sector size
 *    worst case split in allocation btrees per extent assuming 4 extents:
 *		4 exts * 2 trees * (2 * max depth - 1) * block size
 *    the inode btree: max depth * blocksize
 *    the allocation btrees: 2 trees * (max depth - 1) * block size
 */
STATIC uint
xfs_calc_itruncate_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		MAX((xfs_calc_inode_res(mp, 1) +
		     xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1,
				      XFS_FSB_TO_B(mp, 1))),
		    (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) +
		     xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 4),
				      XFS_FSB_TO_B(mp, 1)) +
		    xfs_calc_buf_res(5, 0) +
		    xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
				     XFS_FSB_TO_B(mp, 1)) +
		    xfs_calc_buf_res(2 + mp->m_ialloc_blks +
				     mp->m_in_maxlevels, 0)));
}
Esempio n. 28
0
/*
 * Setting an attribute at runtime, transaction space unit per block.
 * 	the superblock for allocations: sector size
 *	the inode bmap btree could join or split: max depth * block size
 * Since the runtime attribute transaction space is dependent on the total
 * blocks needed for the 1st bmap, here we calculate out the space unit for
 * one block so that the caller could figure out the total space according
 * to the attibute extent length in blocks by:
 *	ext * M_RES(mp)->tr_attrsetrt.tr_logres
 */
STATIC uint
xfs_calc_attrsetrt_reservation(
	struct xfs_mount	*mp)
{
	return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK),
				 XFS_FSB_TO_B(mp, 1));
}
Esempio n. 29
0
/*
 * Setting an attribute at mount time.
 *	the inode getting the attribute
 *	the superblock for allocations
 *	the agfs extents are allocated from
 *	the attribute btree * max depth
 *	the inode allocation btree
 * Since attribute transaction space is dependent on the size of the attribute,
 * the calculation is done partially at mount time and partially at runtime(see
 * below).
 */
STATIC uint
xfs_calc_attrsetm_reservation(
	struct xfs_mount	*mp)
{
	return XFS_DQUOT_LOGRES(mp) +
		xfs_calc_inode_res(mp, 1) +
		xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
		xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1));
}
Esempio n. 30
0
STATIC int
xfs_imap_to_bmap(
	xfs_inode_t	*ip,
	xfs_off_t	offset,
	xfs_bmbt_irec_t *imap,
	xfs_iomap_t	*iomapp,
	int		imaps,			/* Number of imap entries */
	int		iomaps,			/* Number of iomap entries */
	int		flags)
{
	xfs_mount_t	*mp = ip->i_mount;
	int		pbm;
	xfs_fsblock_t	start_block;


	for (pbm = 0; imaps && pbm < iomaps; imaps--, iomapp++, imap++, pbm++) {
		iomapp->iomap_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
		iomapp->iomap_delta = offset - iomapp->iomap_offset;
		iomapp->iomap_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
		iomapp->iomap_flags = flags;

		if (XFS_IS_REALTIME_INODE(ip)) {
			iomapp->iomap_flags |= IOMAP_REALTIME;
			iomapp->iomap_target = mp->m_rtdev_targp;
		} else {
			iomapp->iomap_target = mp->m_ddev_targp;
		}
		start_block = imap->br_startblock;
		if (start_block == HOLESTARTBLOCK) {
			iomapp->iomap_bn = IOMAP_DADDR_NULL;
			iomapp->iomap_flags |= IOMAP_HOLE;
		} else if (start_block == DELAYSTARTBLOCK) {
			iomapp->iomap_bn = IOMAP_DADDR_NULL;
			iomapp->iomap_flags |= IOMAP_DELAY;
		} else {
			iomapp->iomap_bn = xfs_fsb_to_db(ip, start_block);
			if (ISUNWRITTEN(imap))
				iomapp->iomap_flags |= IOMAP_UNWRITTEN;
		}

		offset += iomapp->iomap_bsize - iomapp->iomap_delta;
	}
	return pbm;	/* Return the number filled */
}