Commit 52a4a148 authored by Chandan Babu R's avatar Chandan Babu R
Browse files

xfs: Introduce per-inode 64-bit extent counters



This commit introduces new fields in the on-disk inode format to support
64-bit data fork extent counters and 32-bit attribute fork extent
counters. The new fields will be used only when an inode has
XFS_DIFLAG2_NREXT64 flag set. Otherwise we continue to use the regular 32-bit
data fork extent counters and 16-bit attribute fork extent counters.

Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarChandan Babu R <chandan.babu@oracle.com>
Suggested-by: default avatarDave Chinner <dchinner@redhat.com>
parent 8314bca0
Loading
Loading
Loading
Loading
+29 −4
Original line number Diff line number Diff line
@@ -792,16 +792,41 @@ struct xfs_dinode {
	__be32		di_nlink;	/* number of links to file */
	__be16		di_projid_lo;	/* lower part of owner's project id */
	__be16		di_projid_hi;	/* higher part owner's project id */
	__u8		di_pad[6];	/* unused, zeroed space */
	__be16		di_flushiter;	/* incremented on flush */
	union {
		/* Number of data fork extents if NREXT64 is set */
		__be64	di_big_nextents;

		/* Padding for V3 inodes without NREXT64 set. */
		__be64	di_v3_pad;

		/* Padding and inode flush counter for V2 inodes. */
		struct {
			__u8	di_v2_pad[6];
			__be16	di_flushiter;
		};
	};
	xfs_timestamp_t	di_atime;	/* time last accessed */
	xfs_timestamp_t	di_mtime;	/* time last modified */
	xfs_timestamp_t	di_ctime;	/* time created/inode modified */
	__be64		di_size;	/* number of bytes in file */
	__be64		di_nblocks;	/* # of direct & btree blocks used */
	__be32		di_extsize;	/* basic/minimum extent size for file */
	__be32		di_nextents;	/* number of extents in data fork */
	__be16		di_anextents;	/* number of extents in attribute fork*/
	union {
		/*
		 * For V2 inodes and V3 inodes without NREXT64 set, this
		 * is the number of data and attr fork extents.
		 */
		struct {
			__be32	di_nextents;
			__be16	di_anextents;
		} __packed;

		/* Number of attr fork extents if NREXT64 is set. */
		struct {
			__be32	di_big_anextents;
			__be16	di_nrext64_pad;
		} __packed;
	} __packed;
	__u8		di_forkoff;	/* attr fork offs, <<3 for 64b align */
	__s8		di_aformat;	/* format of attr fork's data */
	__be32		di_dmevmask;	/* DMIG event mask */
+45 −4
Original line number Diff line number Diff line
@@ -279,6 +279,25 @@ xfs_inode_to_disk_ts(
	return ts;
}

static inline void
xfs_inode_to_disk_iext_counters(
	struct xfs_inode	*ip,
	struct xfs_dinode	*to)
{
	if (xfs_inode_has_large_extent_counts(ip)) {
		to->di_big_nextents = cpu_to_be64(xfs_ifork_nextents(&ip->i_df));
		to->di_big_anextents = cpu_to_be32(xfs_ifork_nextents(ip->i_afp));
		/*
		 * We might be upgrading the inode to use larger extent counters
		 * than was previously used. Hence zero the unused field.
		 */
		to->di_nrext64_pad = cpu_to_be16(0);
	} else {
		to->di_nextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
		to->di_anextents = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
	}
}

void
xfs_inode_to_disk(
	struct xfs_inode	*ip,
@@ -296,7 +315,6 @@ xfs_inode_to_disk(
	to->di_projid_lo = cpu_to_be16(ip->i_projid & 0xffff);
	to->di_projid_hi = cpu_to_be16(ip->i_projid >> 16);

	memset(to->di_pad, 0, sizeof(to->di_pad));
	to->di_atime = xfs_inode_to_disk_ts(ip, inode->i_atime);
	to->di_mtime = xfs_inode_to_disk_ts(ip, inode->i_mtime);
	to->di_ctime = xfs_inode_to_disk_ts(ip, inode->i_ctime);
@@ -307,8 +325,6 @@ xfs_inode_to_disk(
	to->di_size = cpu_to_be64(ip->i_disk_size);
	to->di_nblocks = cpu_to_be64(ip->i_nblocks);
	to->di_extsize = cpu_to_be32(ip->i_extsize);
	to->di_nextents = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
	to->di_anextents = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
	to->di_forkoff = ip->i_forkoff;
	to->di_aformat = xfs_ifork_format(ip->i_afp);
	to->di_flags = cpu_to_be16(ip->i_diflags);
@@ -323,11 +339,14 @@ xfs_inode_to_disk(
		to->di_lsn = cpu_to_be64(lsn);
		memset(to->di_pad2, 0, sizeof(to->di_pad2));
		uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid);
		to->di_flushiter = 0;
		to->di_v3_pad = 0;
	} else {
		to->di_version = 2;
		to->di_flushiter = cpu_to_be16(ip->i_flushiter);
		memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
	}

	xfs_inode_to_disk_iext_counters(ip, to);
}

static xfs_failaddr_t
@@ -398,6 +417,24 @@ xfs_dinode_verify_forkoff(
	return NULL;
}

static xfs_failaddr_t
xfs_dinode_verify_nrext64(
	struct xfs_mount	*mp,
	struct xfs_dinode	*dip)
{
	if (xfs_dinode_has_large_extent_counts(dip)) {
		if (!xfs_has_large_extent_counts(mp))
			return __this_address;
		if (dip->di_nrext64_pad != 0)
			return __this_address;
	} else if (dip->di_version >= 3) {
		if (dip->di_v3_pad != 0)
			return __this_address;
	}

	return NULL;
}

xfs_failaddr_t
xfs_dinode_verify(
	struct xfs_mount	*mp,
@@ -442,6 +479,10 @@ xfs_dinode_verify(
	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
		return __this_address;

	fa = xfs_dinode_verify_nrext64(mp, dip);
	if (fa)
		return fa;

	nextents = xfs_dfork_data_extents(dip);
	naextents = xfs_dfork_attr_extents(dip);
	nblocks = be64_to_cpu(dip->di_nblocks);
+6 −0
Original line number Diff line number Diff line
@@ -158,6 +158,9 @@ static inline xfs_extnum_t
xfs_dfork_data_extents(
	struct xfs_dinode	*dip)
{
	if (xfs_dinode_has_large_extent_counts(dip))
		return be64_to_cpu(dip->di_big_nextents);

	return be32_to_cpu(dip->di_nextents);
}

@@ -165,6 +168,9 @@ static inline xfs_extnum_t
xfs_dfork_attr_extents(
	struct xfs_dinode	*dip)
{
	if (xfs_dinode_has_large_extent_counts(dip))
		return be32_to_cpu(dip->di_big_anextents);

	return be16_to_cpu(dip->di_anextents);
}

+29 −4
Original line number Diff line number Diff line
@@ -388,16 +388,41 @@ struct xfs_log_dinode {
	uint32_t	di_nlink;	/* number of links to file */
	uint16_t	di_projid_lo;	/* lower part of owner's project id */
	uint16_t	di_projid_hi;	/* higher part of owner's project id */
	uint8_t		di_pad[6];	/* unused, zeroed space */
	uint16_t	di_flushiter;	/* incremented on flush */
	union {
		/* Number of data fork extents if NREXT64 is set */
		uint64_t	di_big_nextents;

		/* Padding for V3 inodes without NREXT64 set. */
		uint64_t	di_v3_pad;

		/* Padding and inode flush counter for V2 inodes. */
		struct {
			uint8_t	di_v2_pad[6];	/* V2 inode zeroed space */
			uint16_t di_flushiter;	/* V2 inode incremented on flush */
		};
	};
	xfs_log_timestamp_t di_atime;	/* time last accessed */
	xfs_log_timestamp_t di_mtime;	/* time last modified */
	xfs_log_timestamp_t di_ctime;	/* time created/inode modified */
	xfs_fsize_t	di_size;	/* number of bytes in file */
	xfs_rfsblock_t	di_nblocks;	/* # of direct & btree blocks used */
	xfs_extlen_t	di_extsize;	/* basic/minimum extent size for file */
	uint32_t	di_nextents;	/* number of extents in data fork */
	uint16_t	di_anextents;	/* number of extents in attribute fork*/
	union {
		/*
		 * For V2 inodes and V3 inodes without NREXT64 set, this
		 * is the number of data and attr fork extents.
		 */
		struct {
			uint32_t  di_nextents;
			uint16_t  di_anextents;
		} __packed;

		/* Number of attr fork extents if NREXT64 is set. */
		struct {
			uint32_t  di_big_anextents;
			uint16_t  di_nrext64_pad;
		} __packed;
	} __packed;
	uint8_t		di_forkoff;	/* attr fork offs, <<3 for 64b align */
	int8_t		di_aformat;	/* format of attr fork's data */
	uint32_t	di_dmevmask;	/* DMIG event mask */
+19 −4
Original line number Diff line number Diff line
@@ -359,6 +359,21 @@ xfs_copy_dm_fields_to_log_dinode(
	}
}

static inline void
xfs_inode_to_log_dinode_iext_counters(
	struct xfs_inode	*ip,
	struct xfs_log_dinode	*to)
{
	if (xfs_inode_has_large_extent_counts(ip)) {
		to->di_big_nextents = xfs_ifork_nextents(&ip->i_df);
		to->di_big_anextents = xfs_ifork_nextents(ip->i_afp);
		to->di_nrext64_pad = 0;
	} else {
		to->di_nextents = xfs_ifork_nextents(&ip->i_df);
		to->di_anextents = xfs_ifork_nextents(ip->i_afp);
	}
}

static void
xfs_inode_to_log_dinode(
	struct xfs_inode	*ip,
@@ -374,7 +389,6 @@ xfs_inode_to_log_dinode(
	to->di_projid_lo = ip->i_projid & 0xffff;
	to->di_projid_hi = ip->i_projid >> 16;

	memset(to->di_pad, 0, sizeof(to->di_pad));
	memset(to->di_pad3, 0, sizeof(to->di_pad3));
	to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode->i_atime);
	to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode->i_mtime);
@@ -386,8 +400,6 @@ xfs_inode_to_log_dinode(
	to->di_size = ip->i_disk_size;
	to->di_nblocks = ip->i_nblocks;
	to->di_extsize = ip->i_extsize;
	to->di_nextents = xfs_ifork_nextents(&ip->i_df);
	to->di_anextents = xfs_ifork_nextents(ip->i_afp);
	to->di_forkoff = ip->i_forkoff;
	to->di_aformat = xfs_ifork_format(ip->i_afp);
	to->di_flags = ip->i_diflags;
@@ -407,11 +419,14 @@ xfs_inode_to_log_dinode(
		to->di_lsn = lsn;
		memset(to->di_pad2, 0, sizeof(to->di_pad2));
		uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid);
		to->di_flushiter = 0;
		to->di_v3_pad = 0;
	} else {
		to->di_version = 2;
		to->di_flushiter = ip->i_flushiter;
		memset(to->di_v2_pad, 0, sizeof(to->di_v2_pad));
	}

	xfs_inode_to_log_dinode_iext_counters(ip, to);
}

/*
Loading