Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3993baeb authored by Darrick J. Wong's avatar Darrick J. Wong
Browse files

xfs: introduce the CoW fork



Introduce a new in-core fork for storing copy-on-write delalloc
reservations and allocated extents that are in the process of being
written out.

Signed-off-by: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent 11715a21
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ xfs-y += xfs_aops.o \
				   xfs_message.o \
				   xfs_mount.o \
				   xfs_mru_cache.o \
				   xfs_reflink.o \
				   xfs_stats.o \
				   xfs_super.o \
				   xfs_symlink.o \
+20 −7
Original line number Diff line number Diff line
@@ -2924,6 +2924,7 @@ xfs_bmap_add_extent_hole_real(
	ASSERT(!isnullstartblock(new->br_startblock));
	ASSERT(!bma->cur ||
	       !(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL));
	ASSERT(whichfork != XFS_COW_FORK);

	XFS_STATS_INC(mp, xs_add_exlist);

@@ -4072,12 +4073,11 @@ xfs_bmapi_read(
	int			error;
	int			eof;
	int			n = 0;
	int			whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
						XFS_ATTR_FORK : XFS_DATA_FORK;
	int			whichfork = xfs_bmapi_whichfork(flags);

	ASSERT(*nmap >= 1);
	ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE|
			   XFS_BMAPI_IGSTATE)));
			   XFS_BMAPI_IGSTATE|XFS_BMAPI_COWFORK)));
	ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED|XFS_ILOCK_EXCL));

	if (unlikely(XFS_TEST_ERROR(
@@ -4095,6 +4095,16 @@ xfs_bmapi_read(

	ifp = XFS_IFORK_PTR(ip, whichfork);

	/* No CoW fork?  Return a hole. */
	if (whichfork == XFS_COW_FORK && !ifp) {
		mval->br_startoff = bno;
		mval->br_startblock = HOLESTARTBLOCK;
		mval->br_blockcount = len;
		mval->br_state = XFS_EXT_NORM;
		*nmap = 1;
		return 0;
	}

	if (!(ifp->if_flags & XFS_IFEXTENTS)) {
		error = xfs_iread_extents(NULL, ip, whichfork);
		if (error)
@@ -4368,8 +4378,7 @@ xfs_bmapi_convert_unwritten(
	xfs_filblks_t		len,
	int			flags)
{
	int			whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
						XFS_ATTR_FORK : XFS_DATA_FORK;
	int			whichfork = xfs_bmapi_whichfork(flags);
	struct xfs_ifork	*ifp = XFS_IFORK_PTR(bma->ip, whichfork);
	int			tmp_logflags = 0;
	int			error;
@@ -4385,6 +4394,8 @@ xfs_bmapi_convert_unwritten(
			(XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT))
		return 0;

	ASSERT(whichfork != XFS_COW_FORK);

	/*
	 * Modify (by adding) the state flag, if writing.
	 */
@@ -4795,6 +4806,8 @@ xfs_bmap_del_extent(

	if (whichfork == XFS_ATTR_FORK)
		state |= BMAP_ATTRFORK;
	else if (whichfork == XFS_COW_FORK)
		state |= BMAP_COWFORK;

	ifp = XFS_IFORK_PTR(ip, whichfork);
	ASSERT((*idx >= 0) && (*idx < ifp->if_bytes /
@@ -5133,8 +5146,8 @@ __xfs_bunmapi(

	trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_);

	whichfork = (flags & XFS_BMAPI_ATTRFORK) ?
		XFS_ATTR_FORK : XFS_DATA_FORK;
	whichfork = xfs_bmapi_whichfork(flags);
	ASSERT(whichfork != XFS_COW_FORK);
	ifp = XFS_IFORK_PTR(ip, whichfork);
	if (unlikely(
	    XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS &&
+19 −3
Original line number Diff line number Diff line
@@ -107,6 +107,9 @@ struct xfs_extent_free_item
 */
#define XFS_BMAPI_REMAP		0x100

/* Map something in the CoW fork. */
#define XFS_BMAPI_COWFORK	0x200

#define XFS_BMAPI_FLAGS \
	{ XFS_BMAPI_ENTIRE,	"ENTIRE" }, \
	{ XFS_BMAPI_METADATA,	"METADATA" }, \
@@ -116,12 +119,23 @@ struct xfs_extent_free_item
	{ XFS_BMAPI_CONTIG,	"CONTIG" }, \
	{ XFS_BMAPI_CONVERT,	"CONVERT" }, \
	{ XFS_BMAPI_ZERO,	"ZERO" }, \
	{ XFS_BMAPI_REMAP,	"REMAP" }
	{ XFS_BMAPI_REMAP,	"REMAP" }, \
	{ XFS_BMAPI_COWFORK,	"COWFORK" }


static inline int xfs_bmapi_aflag(int w)
{
	return (w == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : 0);
	return (w == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK :
	       (w == XFS_COW_FORK ? XFS_BMAPI_COWFORK : 0));
}

static inline int xfs_bmapi_whichfork(int bmapi_flags)
{
	if (bmapi_flags & XFS_BMAPI_COWFORK)
		return XFS_COW_FORK;
	else if (bmapi_flags & XFS_BMAPI_ATTRFORK)
		return XFS_ATTR_FORK;
	return XFS_DATA_FORK;
}

/*
@@ -142,13 +156,15 @@ static inline int xfs_bmapi_aflag(int w)
#define BMAP_LEFT_VALID		(1 << 6)
#define BMAP_RIGHT_VALID	(1 << 7)
#define BMAP_ATTRFORK		(1 << 8)
#define BMAP_COWFORK		(1 << 9)

#define XFS_BMAP_EXT_FLAGS \
	{ BMAP_LEFT_CONTIG,	"LC" }, \
	{ BMAP_RIGHT_CONTIG,	"RC" }, \
	{ BMAP_LEFT_FILLING,	"LF" }, \
	{ BMAP_RIGHT_FILLING,	"RF" }, \
	{ BMAP_ATTRFORK,	"ATTR" }
	{ BMAP_ATTRFORK,	"ATTR" }, \
	{ BMAP_COWFORK,		"COW" }


/*
+1 −0
Original line number Diff line number Diff line
@@ -777,6 +777,7 @@ xfs_bmbt_init_cursor(
{
	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
	struct xfs_btree_cur	*cur;
	ASSERT(whichfork != XFS_COW_FORK);

	cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP);

+44 −3
Original line number Diff line number Diff line
@@ -206,9 +206,14 @@ xfs_iformat_fork(
		XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount);
		return -EFSCORRUPTED;
	}
	if (error) {
	if (error)
		return error;

	if (xfs_is_reflink_inode(ip)) {
		ASSERT(ip->i_cowfp == NULL);
		xfs_ifork_init_cow(ip);
	}

	if (!XFS_DFORK_Q(dip))
		return 0;

@@ -247,6 +252,9 @@ xfs_iformat_fork(
	if (error) {
		kmem_zone_free(xfs_ifork_zone, ip->i_afp);
		ip->i_afp = NULL;
		if (ip->i_cowfp)
			kmem_zone_free(xfs_ifork_zone, ip->i_cowfp);
		ip->i_cowfp = NULL;
		xfs_idestroy_fork(ip, XFS_DATA_FORK);
	}
	return error;
@@ -761,6 +769,9 @@ xfs_idestroy_fork(
	if (whichfork == XFS_ATTR_FORK) {
		kmem_zone_free(xfs_ifork_zone, ip->i_afp);
		ip->i_afp = NULL;
	} else if (whichfork == XFS_COW_FORK) {
		kmem_zone_free(xfs_ifork_zone, ip->i_cowfp);
		ip->i_cowfp = NULL;
	}
}

@@ -948,6 +959,19 @@ xfs_iext_get_ext(
	}
}

/* Convert bmap state flags to an inode fork. */
struct xfs_ifork *
xfs_iext_state_to_fork(
	struct xfs_inode	*ip,
	int			state)
{
	if (state & BMAP_COWFORK)
		return ip->i_cowfp;
	else if (state & BMAP_ATTRFORK)
		return ip->i_afp;
	return &ip->i_df;
}

/*
 * Insert new item(s) into the extent records for incore inode
 * fork 'ifp'.  'count' new items are inserted at index 'idx'.
@@ -960,7 +984,7 @@ xfs_iext_insert(
	xfs_bmbt_irec_t	*new,		/* items to insert */
	int		state)		/* type of extent conversion */
{
	xfs_ifork_t	*ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
	xfs_ifork_t	*ifp = xfs_iext_state_to_fork(ip, state);
	xfs_extnum_t	i;		/* extent record index */

	trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_);
@@ -1210,7 +1234,7 @@ xfs_iext_remove(
	int		ext_diff,	/* number of extents to remove */
	int		state)		/* type of extent conversion */
{
	xfs_ifork_t	*ifp = (state & BMAP_ATTRFORK) ? ip->i_afp : &ip->i_df;
	xfs_ifork_t	*ifp = xfs_iext_state_to_fork(ip, state);
	xfs_extnum_t	nextents;	/* number of extents in file */
	int		new_size;	/* size of extents after removal */

@@ -1955,3 +1979,20 @@ xfs_iext_irec_update_extoffs(
		ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff;
	}
}

/*
 * Initialize an inode's copy-on-write fork.
 */
void
xfs_ifork_init_cow(
	struct xfs_inode	*ip)
{
	if (ip->i_cowfp)
		return;

	ip->i_cowfp = kmem_zone_zalloc(xfs_ifork_zone,
				       KM_SLEEP | KM_NOFS);
	ip->i_cowfp->if_flags = XFS_IFEXTENTS;
	ip->i_cformat = XFS_DINODE_FMT_EXTENTS;
	ip->i_cnextents = 0;
}
Loading