linux-xfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V2 00/12] xfs: Extend per-inode extent counters
@ 2021-07-26 11:45 Chandan Babu R
  2021-07-26 11:45 ` [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h Chandan Babu R
                   ` (12 more replies)
  0 siblings, 13 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

The commit xfs: fix inode fork extent count overflow
(3f8a4f1d876d3e3e49e50b0396eaffcc4ba71b08) mentions that 10 billion
data fork extents should be possible to create. However the
corresponding on-disk field has a signed 32-bit type. Hence this
patchset extends the per-inode data extent counter to 64 bits out of
which 48 bits are used to store the extent count. 

Also, XFS has an attr fork extent counter which is 16 bits wide. A
workload which,
1. Creates 1 million 255-byte sized xattrs,
2. Deletes 50% of these xattrs in an alternating manner,
3. Tries to insert 400,000 new 255-byte sized xattrs
   causes the xattr extent counter to overflow.

Dave tells me that there are instances where a single file has more
than 100 million hardlinks. With parent pointers being stored in
xattrs, we will overflow the signed 16-bits wide xattr extent counter
when large number of hardlinks are created. Hence this patchset
extends the on-disk field to 32-bits.

The following changes are made to accomplish this,
1. A new incompat superblock flag to prevent older kernels from mounting
   the filesystem. This flag has to be set during mkfs time.
2. A new 64-bit inode field is created to hold the data extent
   counter.
3. The existing 32-bit inode data extent counter will be used to hold
   the attr fork extent counter.

The patchset has been tested by executing xfstests with the following
mkfs.xfs options,
1. -m crc=0 -b size=1k
2. -m crc=0 -b size=4k
3. -m crc=0 -b size=512
4. -m rmapbt=1,reflink=1 -b size=1k
5. -m rmapbt=1,reflink=1 -b size=4k

Each of the above test scenarios were executed on the following
combinations (For V4 FS test scenario, the last combination
i.e. "Patched (enable extcnt64bit)", was omitted).
|-------------------------------+-----------|
| Xfsprogs                      | Kernel    |
|-------------------------------+-----------|
| Unpatched                     | Patched   |
| Patched (disable extcnt64bit) | Unpatched |
| Patched (disable extcnt64bit) | Patched   |
| Patched (enable extcnt64bit)  | Patched   |
|-------------------------------+-----------|

I have also written a test (yet to be converted into xfstests format)
to check if the correct extent counter fields are updated with/without
the new incompat flag. I have also fixed some of the existing fstests
to work with the new extent counter fields.

Increasing data extent counter width also causes the maximum height of
BMBT to increase. This requires that the macro XFS_BTREE_MAXLEVELS be
updated with a larger value. However such a change causes the value of
mp->m_rmap_maxlevels to increase which in turn causes log reservation
sizes to increase and hence a modified XFS driver will fail to mount
filesystems created by older versions of mkfs.xfs.

Hence this patchset is built on top of Darrick's btree-dynamic-depth
branch which removes the macro XFS_BTREE_MAXLEVELS and computes
mp->m_rmap_maxlevels based on the size of an AG.

These patches can also be obtained from
https://github.com/chandanr/linux.git at branch
xfs-incompat-extend-extcnt-v2.

I will be posting the changes associated with xfsprogs separately.

Changelog:
V1 -> V2:
1. Rebase patches on top of Darrick's btree-dynamic-depth branch.
2. Add new bulkstat ioctl version to support 64-bit data fork extent
   counter field.
3. Introduce new error tag to verify if the old bulkstat ioctls skip
   reporting inodes with large data fork extent counters.

Chandan Babu R (12):
  xfs: Move extent count limits to xfs_format.h
  xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32,
    XFS_IFORK_EXTCNT_MAXS16
  xfs: Introduce xfs_iext_max() helper
  xfs: Use xfs_extnum_t instead of basic data types
  xfs: Introduce xfs_dfork_nextents() helper
  xfs: xfs_dfork_nextents: Return extent count via an out argument
  xfs: Rename inode's extent counter fields based on their width
  xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits
    respectively
  xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
  xfs: Enable bulkstat ioctl to support 64-bit extent counters
  xfs: Extend per-inode extent counter widths
  xfs: Error tag to test if v5 bulkstat skips inodes with large extent
    count

 fs/xfs/libxfs/xfs_bmap.c        | 21 +++----
 fs/xfs/libxfs/xfs_errortag.h    |  4 +-
 fs/xfs/libxfs/xfs_format.h      | 42 +++++++++++---
 fs/xfs/libxfs/xfs_fs.h          |  9 ++-
 fs/xfs/libxfs/xfs_inode_buf.c   | 82 ++++++++++++++++++++++++----
 fs/xfs/libxfs/xfs_inode_buf.h   |  2 +
 fs/xfs/libxfs/xfs_inode_fork.c  | 35 +++++++++---
 fs/xfs/libxfs/xfs_inode_fork.h  | 22 +++++++-
 fs/xfs/libxfs/xfs_log_format.h  |  7 ++-
 fs/xfs/libxfs/xfs_types.h       | 11 +---
 fs/xfs/scrub/attr_repair.c      |  2 +-
 fs/xfs/scrub/inode.c            | 97 ++++++++++++++++++++-------------
 fs/xfs/scrub/inode_repair.c     | 71 +++++++++++++++++-------
 fs/xfs/scrub/trace.h            | 16 +++---
 fs/xfs/xfs_error.c              |  3 +
 fs/xfs/xfs_inode.c              |  4 +-
 fs/xfs/xfs_inode_item.c         | 15 ++++-
 fs/xfs/xfs_inode_item_recover.c | 25 +++++++--
 fs/xfs/xfs_ioctl.c              | 33 +++++++++--
 fs/xfs/xfs_ioctl32.c            |  7 +++
 fs/xfs/xfs_itable.c             | 35 ++++++++++--
 fs/xfs/xfs_itable.h             |  1 +
 fs/xfs/xfs_trace.h              |  6 +-
 23 files changed, 402 insertions(+), 148 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 45+ messages in thread

* [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-26 18:00   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16 Chandan Babu R
                   ` (11 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

Maximum values associated with extent counters i.e. Maximum extent length,
Maximum data extents and Maximum xattr extents are dictated by the on-disk
format. Hence move these definitions over to xfs_format.h.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_format.h | 7 +++++++
 fs/xfs/libxfs/xfs_types.h  | 7 -------
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 8cd48a651b96..37cca918d2ba 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1109,6 +1109,13 @@ enum xfs_dinode_fmt {
 	{ XFS_DINODE_FMT_BTREE,		"btree" }, \
 	{ XFS_DINODE_FMT_UUID,		"uuid" }
 
+/*
+ * Max values for extlen, extnum, aextnum.
+ */
+#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */
+#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
+#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */
+
 /*
  * Inode minimum and maximum sizes.
  */
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 5c0cc806068b..8908346b1deb 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -56,13 +56,6 @@ typedef void *		xfs_failaddr_t;
 #define	NULLFSINO	((xfs_ino_t)-1)
 #define	NULLAGINO	((xfs_agino_t)-1)
 
-/*
- * Max values for extlen, extnum, aextnum.
- */
-#define	MAXEXTLEN	((xfs_extlen_t)0x001fffff)	/* 21 bits */
-#define	MAXEXTNUM	((xfs_extnum_t)0x7fffffff)	/* signed int */
-#define	MAXAEXTNUM	((xfs_aextnum_t)0x7fff)		/* signed short */
-
 /*
  * Minimum and maximum blocksize and sectorsize.
  * The blocksize upper limit is pretty much arbitrary.
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
  2021-07-26 11:45 ` [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 21:56   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper Chandan Babu R
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

In preparation for introducing larger extent count limits, this commit renames
existing extent count limits based on their signedness and width.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
 fs/xfs/libxfs/xfs_format.h     | 8 ++++----
 fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
 fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
 fs/xfs/scrub/inode_repair.c    | 2 +-
 5 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index f3c9a0ebb0a5..8f262405a5b5 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
 	 * available.
 	 */
 	if (whichfork == XFS_DATA_FORK) {
-		maxleafents = MAXEXTNUM;
+		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
 		sz = xfs_bmdr_space_calc(MINDBTPTRS);
 	} else {
-		maxleafents = MAXAEXTNUM;
+		maxleafents = XFS_IFORK_EXTCNT_MAXS16;
 		sz = xfs_bmdr_space_calc(MINABTPTRS);
 	}
 	maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 37cca918d2ba..920e3f9c418f 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1110,11 +1110,11 @@ enum xfs_dinode_fmt {
 	{ XFS_DINODE_FMT_UUID,		"uuid" }
 
 /*
- * Max values for extlen, extnum, aextnum.
+ * Max values for extlen and disk inode's extent counters.
  */
-#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */
-#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
-#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */
+#define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
+#define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
+#define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
 
 /*
  * Inode minimum and maximum sizes.
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 5625df1ddd95..66d13e8fa420 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -365,9 +365,9 @@ xfs_dinode_verify_fork(
 		break;
 	case XFS_DINODE_FMT_BTREE:
 		if (whichfork == XFS_ATTR_FORK) {
-			if (di_nextents > MAXAEXTNUM)
+			if (di_nextents > XFS_IFORK_EXTCNT_MAXS16)
 				return __this_address;
-		} else if (di_nextents > MAXEXTNUM) {
+		} else if (di_nextents > XFS_IFORK_EXTCNT_MAXS32) {
 			return __this_address;
 		}
 		break;
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 801a6f7dbd0c..6f4b14d3d381 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -736,7 +736,8 @@ xfs_iext_count_may_overflow(
 	if (whichfork == XFS_COW_FORK)
 		return 0;
 
-	max_exts = (whichfork == XFS_ATTR_FORK) ? MAXAEXTNUM : MAXEXTNUM;
+	max_exts = (whichfork == XFS_ATTR_FORK) ?
+		XFS_IFORK_EXTCNT_MAXS16 : XFS_IFORK_EXTCNT_MAXS32;
 
 	if (XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
 		max_exts = 10;
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index a80cd633fe59..c44f8d06939b 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
 			return error;
 		if (count >= sc->mp->m_sb.sb_dblocks)
 			return -EFSCORRUPTED;
-		if (nextents >= MAXAEXTNUM)
+		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
 			return -EFSCORRUPTED;
 		ifp->if_nextents = nextents;
 	} else {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
  2021-07-26 11:45 ` [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h Chandan Babu R
  2021-07-26 11:45 ` [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16 Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 21:58   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types Chandan Babu R
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

xfs_iext_max() returns the maximum number of extents possible for one of
data, cow or attribute fork. This helper will be extended further in a
future commit when maximum extent counts associated with data/attribute
forks are increased.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_bmap.c       | 9 ++++-----
 fs/xfs/libxfs/xfs_inode_buf.c  | 8 +++-----
 fs/xfs/libxfs/xfs_inode_fork.c | 6 +++---
 fs/xfs/libxfs/xfs_inode_fork.h | 8 ++++++++
 fs/xfs/scrub/inode_repair.c    | 2 +-
 5 files changed, 19 insertions(+), 14 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 8f262405a5b5..282aeb3c0e49 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -75,13 +75,12 @@ xfs_bmap_compute_maxlevels(
 	 * ATTR2 we have to assume the worst case scenario of a minimum size
 	 * available.
 	 */
-	if (whichfork == XFS_DATA_FORK) {
-		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
+	maxleafents = xfs_iext_max(mp, whichfork);
+	if (whichfork == XFS_DATA_FORK)
 		sz = xfs_bmdr_space_calc(MINDBTPTRS);
-	} else {
-		maxleafents = XFS_IFORK_EXTCNT_MAXS16;
+	else
 		sz = xfs_bmdr_space_calc(MINABTPTRS);
-	}
+
 	maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
 	minleafrecs = mp->m_bmap_dmnr[0];
 	minnoderecs = mp->m_bmap_dmnr[1];
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 66d13e8fa420..419b92dc6ac8 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -343,6 +343,7 @@ xfs_dinode_verify_fork(
 	int			whichfork)
 {
 	uint32_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
+	xfs_extnum_t		max_extents;
 
 	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
 	case XFS_DINODE_FMT_LOCAL:
@@ -364,12 +365,9 @@ xfs_dinode_verify_fork(
 			return __this_address;
 		break;
 	case XFS_DINODE_FMT_BTREE:
-		if (whichfork == XFS_ATTR_FORK) {
-			if (di_nextents > XFS_IFORK_EXTCNT_MAXS16)
-				return __this_address;
-		} else if (di_nextents > XFS_IFORK_EXTCNT_MAXS32) {
+		max_extents = xfs_iext_max(mp, whichfork);
+		if (di_nextents > max_extents)
 			return __this_address;
-		}
 		break;
 	default:
 		return __this_address;
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 6f4b14d3d381..c6856ec95335 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -729,6 +729,7 @@ xfs_iext_count_may_overflow(
 	int			whichfork,
 	int			nr_to_add)
 {
+	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
 	uint64_t		max_exts;
 	uint64_t		nr_exts;
@@ -736,10 +737,9 @@ xfs_iext_count_may_overflow(
 	if (whichfork == XFS_COW_FORK)
 		return 0;
 
-	max_exts = (whichfork == XFS_ATTR_FORK) ?
-		XFS_IFORK_EXTCNT_MAXS16 : XFS_IFORK_EXTCNT_MAXS32;
+	max_exts = xfs_iext_max(mp, whichfork);
 
-	if (XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
+	if (XFS_TEST_ERROR(false, mp, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
 		max_exts = 10;
 
 	nr_exts = ifp->if_nextents + nr_to_add;
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index cf82be263b48..1eda2163603e 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -133,6 +133,14 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp)
 	return ifp->if_format;
 }
 
+static inline xfs_extnum_t xfs_iext_max(struct xfs_mount *mp, int whichfork)
+{
+	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK)
+		return XFS_IFORK_EXTCNT_MAXS32;
+	else
+		return XFS_IFORK_EXTCNT_MAXS16;
+}
+
 struct xfs_ifork *xfs_ifork_alloc(enum xfs_dinode_fmt format,
 				xfs_extnum_t nextents);
 struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state);
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index c44f8d06939b..a44d7b48c374 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
 			return error;
 		if (count >= sc->mp->m_sb.sb_dblocks)
 			return -EFSCORRUPTED;
-		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
+		if (nextents >= xfs_iext_max(sc->mp, XFS_ATTR_FORK))
 			return -EFSCORRUPTED;
 		ifp->if_nextents = nextents;
 	} else {
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (2 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 21:59   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper Chandan Babu R
                   ` (8 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

xfs_extnum_t is the type to use to declare variables which have values
obtained from xfs_dinode->di_[a]nextents. This commit replaces basic
types (e.g. uint32_t) with xfs_extnum_t for such variables.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_bmap.c       | 2 +-
 fs/xfs/libxfs/xfs_inode_buf.c  | 2 +-
 fs/xfs/libxfs/xfs_inode_fork.c | 2 +-
 fs/xfs/scrub/inode.c           | 2 +-
 fs/xfs/scrub/inode_repair.c    | 2 +-
 fs/xfs/xfs_trace.h             | 2 +-
 6 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 282aeb3c0e49..e5d243fd187d 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -53,9 +53,9 @@ xfs_bmap_compute_maxlevels(
 	xfs_mount_t	*mp,		/* file system mount structure */
 	int		whichfork)	/* data or attr fork */
 {
+	xfs_extnum_t	maxleafents;	/* max leaf entries possible */
 	int		level;		/* btree level */
 	uint		maxblocks;	/* max blocks at this level */
-	uint		maxleafents;	/* max leaf entries possible */
 	int		maxrootrecs;	/* max records in root block */
 	int		minleafrecs;	/* min records in leaf block */
 	int		minnoderecs;	/* min records in node block */
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 419b92dc6ac8..cba9a38f3270 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -342,7 +342,7 @@ xfs_dinode_verify_fork(
 	struct xfs_mount	*mp,
 	int			whichfork)
 {
-	uint32_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
+	xfs_extnum_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
 	xfs_extnum_t		max_extents;
 
 	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index c6856ec95335..a1e40df585a3 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -107,7 +107,7 @@ xfs_iformat_extents(
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
 	int			state = xfs_bmap_fork_to_state(whichfork);
-	int			nex = XFS_DFORK_NEXTENTS(dip, whichfork);
+	xfs_extnum_t		nex = XFS_DFORK_NEXTENTS(dip, whichfork);
 	int			size = nex * sizeof(xfs_bmbt_rec_t);
 	struct xfs_iext_cursor	icur;
 	struct xfs_bmbt_rec	*dp;
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index e6068590484b..246d11ca133f 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -219,7 +219,7 @@ xchk_dinode(
 	size_t			fork_recs;
 	unsigned long long	isize;
 	uint64_t		flags2;
-	uint32_t		nextents;
+	xfs_extnum_t		nextents;
 	prid_t			prid;
 	uint16_t		flags;
 	uint16_t		mode;
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index a44d7b48c374..042c7d0bc0f5 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -597,9 +597,9 @@ xrep_dinode_bad_extents_fork(
 {
 	struct xfs_bmbt_irec	new;
 	struct xfs_bmbt_rec	*dp;
+	xfs_extnum_t		nex;
 	bool			isrt;
 	int			i;
-	int			nex;
 	int			fork_size;
 
 	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index affc9b5834fb..5ed11f894f79 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -2338,7 +2338,7 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
 		__field(int, which)
 		__field(xfs_ino_t, ino)
 		__field(int, format)
-		__field(int, nex)
+		__field(xfs_extnum_t, nex)
 		__field(int, broot_size)
 		__field(int, fork_off)
 	),
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (3 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 22:10   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument Chandan Babu R
                   ` (7 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit replaces the macro XFS_DFORK_NEXTENTS() with the helper function
xfs_dfork_nextents(). As of this commit, xfs_dfork_nextents() returns the same
value as XFS_DFORK_NEXTENTS(). A future commit which extends inode's extent
counter fields will add more logic to this helper.

This commit also replaces direct accesses to xfs_dinode->di_[a]nextents
with calls to xfs_dfork_nextents().

No functional changes have been made.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_format.h     |  4 ----
 fs/xfs/libxfs/xfs_inode_buf.c  | 41 +++++++++++++++++++++++++++++-----
 fs/xfs/libxfs/xfs_inode_buf.h  |  2 ++
 fs/xfs/libxfs/xfs_inode_fork.c | 12 ++++++----
 fs/xfs/scrub/inode.c           | 19 +++++++++-------
 fs/xfs/scrub/inode_repair.c    | 38 +++++++++++++++++++------------
 6 files changed, 81 insertions(+), 35 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 920e3f9c418f..001a4077a7c6 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1166,10 +1166,6 @@ enum xfs_dinode_fmt {
 	((w) == XFS_DATA_FORK ? \
 		(dip)->di_format : \
 		(dip)->di_aformat)
-#define XFS_DFORK_NEXTENTS(dip,w) \
-	((w) == XFS_DATA_FORK ? \
-		be32_to_cpu((dip)->di_nextents) : \
-		be16_to_cpu((dip)->di_anextents))
 
 /*
  * For block and character special files the 32bit dev_t is stored at the
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index cba9a38f3270..6bef0757fca4 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -342,9 +342,11 @@ xfs_dinode_verify_fork(
 	struct xfs_mount	*mp,
 	int			whichfork)
 {
-	xfs_extnum_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
+	xfs_extnum_t		di_nextents;
 	xfs_extnum_t		max_extents;
 
+	di_nextents = xfs_dfork_nextents(mp, dip, whichfork);
+
 	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
 	case XFS_DINODE_FMT_LOCAL:
 		/*
@@ -375,6 +377,31 @@ xfs_dinode_verify_fork(
 	return NULL;
 }
 
+xfs_extnum_t
+xfs_dfork_nextents(
+	struct xfs_mount	*mp,
+	struct xfs_dinode	*dip,
+	int			whichfork)
+{
+	xfs_extnum_t		nextents = 0;
+
+	switch (whichfork) {
+	case XFS_DATA_FORK:
+		nextents = be32_to_cpu(dip->di_nextents);
+		break;
+
+	case XFS_ATTR_FORK:
+		nextents = be16_to_cpu(dip->di_anextents);
+		break;
+
+	default:
+		ASSERT(0);
+		break;
+	}
+
+	return nextents;
+}
+
 static xfs_failaddr_t
 xfs_dinode_verify_forkoff(
 	struct xfs_dinode	*dip,
@@ -474,6 +501,8 @@ xfs_dinode_verify(
 	uint16_t		flags;
 	uint64_t		flags2;
 	uint64_t		di_size;
+	xfs_extnum_t            nextents;
+	int64_t			nblocks;
 
 	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
 		return __this_address;
@@ -504,10 +533,12 @@ xfs_dinode_verify(
 	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
 		return __this_address;
 
+	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
+	nextents += xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
+	nblocks = be64_to_cpu(dip->di_nblocks);
+
 	/* Fork checks carried over from xfs_iformat_fork */
-	if (mode &&
-	    be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) >
-			be64_to_cpu(dip->di_nblocks))
+	if (mode && nextents > nblocks)
 		return __this_address;
 
 	if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize)
@@ -564,7 +595,7 @@ xfs_dinode_verify(
 		default:
 			return __this_address;
 		}
-		if (dip->di_anextents)
+		if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
 			return __this_address;
 	}
 
diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
index a30b7676098a..ea2c35091609 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.h
+++ b/fs/xfs/libxfs/xfs_inode_buf.h
@@ -36,6 +36,8 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
 xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
 		uint32_t cowextsize, uint16_t mode, uint16_t flags,
 		uint64_t flags2);
+xfs_extnum_t xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
+		int whichfork);
 
 static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
 {
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index a1e40df585a3..38dd2dfc31fa 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -107,7 +107,7 @@ xfs_iformat_extents(
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
 	int			state = xfs_bmap_fork_to_state(whichfork);
-	xfs_extnum_t		nex = XFS_DFORK_NEXTENTS(dip, whichfork);
+	xfs_extnum_t		nex = xfs_dfork_nextents(mp, dip, whichfork);
 	int			size = nex * sizeof(xfs_bmbt_rec_t);
 	struct xfs_iext_cursor	icur;
 	struct xfs_bmbt_rec	*dp;
@@ -226,6 +226,7 @@ xfs_iformat_data_fork(
 	struct xfs_inode	*ip,
 	struct xfs_dinode	*dip)
 {
+	struct xfs_mount	*mp = ip->i_mount;
 	struct inode		*inode = VFS_I(ip);
 	int			error;
 
@@ -234,7 +235,7 @@ xfs_iformat_data_fork(
 	 * depend on it.
 	 */
 	ip->i_df.if_format = dip->di_format;
-	ip->i_df.if_nextents = be32_to_cpu(dip->di_nextents);
+	ip->i_df.if_nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
 
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFIFO:
@@ -301,14 +302,17 @@ xfs_iformat_attr_fork(
 	struct xfs_inode	*ip,
 	struct xfs_dinode	*dip)
 {
+	struct xfs_mount	*mp = ip->i_mount;
+	xfs_extnum_t		nextents;
 	int			error = 0;
 
+	nextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
+
 	/*
 	 * Initialize the extent count early, as the per-format routines may
 	 * depend on it.
 	 */
-	ip->i_afp = xfs_ifork_alloc(dip->di_aformat,
-				be16_to_cpu(dip->di_anextents));
+	ip->i_afp = xfs_ifork_alloc(dip->di_aformat, nextents);
 
 	switch (ip->i_afp->if_format) {
 	case XFS_DINODE_FMT_LOCAL:
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index 246d11ca133f..a161dac31a6f 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -220,6 +220,7 @@ xchk_dinode(
 	unsigned long long	isize;
 	uint64_t		flags2;
 	xfs_extnum_t		nextents;
+	xfs_extnum_t		naextents;
 	prid_t			prid;
 	uint16_t		flags;
 	uint16_t		mode;
@@ -378,7 +379,7 @@ xchk_dinode(
 	xchk_inode_extsize(sc, dip, ino, mode, flags);
 
 	/* di_nextents */
-	nextents = be32_to_cpu(dip->di_nextents);
+	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
 	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
 	switch (dip->di_format) {
 	case XFS_DINODE_FMT_EXTENTS:
@@ -395,10 +396,12 @@ xchk_dinode(
 		break;
 	}
 
+	naextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
+
 	/* di_forkoff */
 	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
 		xchk_ino_set_corrupt(sc, ino);
-	if (dip->di_anextents != 0 && dip->di_forkoff == 0)
+	if (naextents != 0 && dip->di_forkoff == 0)
 		xchk_ino_set_corrupt(sc, ino);
 	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
 		xchk_ino_set_corrupt(sc, ino);
@@ -410,19 +413,18 @@ xchk_dinode(
 		xchk_ino_set_corrupt(sc, ino);
 
 	/* di_anextents */
-	nextents = be16_to_cpu(dip->di_anextents);
 	fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
 	switch (dip->di_aformat) {
 	case XFS_DINODE_FMT_EXTENTS:
-		if (nextents > fork_recs)
+		if (naextents > fork_recs)
 			xchk_ino_set_corrupt(sc, ino);
 		break;
 	case XFS_DINODE_FMT_BTREE:
-		if (nextents <= fork_recs)
+		if (naextents <= fork_recs)
 			xchk_ino_set_corrupt(sc, ino);
 		break;
 	default:
-		if (nextents != 0)
+		if (naextents != 0)
 			xchk_ino_set_corrupt(sc, ino);
 	}
 
@@ -487,6 +489,7 @@ xchk_inode_xref_bmap(
 	struct xfs_scrub	*sc,
 	struct xfs_dinode	*dip)
 {
+	struct xfs_mount	*mp = sc->mp;
 	xfs_extnum_t		nextents;
 	xfs_filblks_t		count;
 	xfs_filblks_t		acount;
@@ -500,14 +503,14 @@ xchk_inode_xref_bmap(
 			&nextents, &count);
 	if (!xchk_should_check_xref(sc, &error, NULL))
 		return;
-	if (nextents < be32_to_cpu(dip->di_nextents))
+	if (nextents < xfs_dfork_nextents(mp, dip, XFS_DATA_FORK))
 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
 
 	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
 			&nextents, &acount);
 	if (!xchk_should_check_xref(sc, &error, NULL))
 		return;
-	if (nextents != be16_to_cpu(dip->di_anextents))
+	if (nextents != xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
 
 	/* Check nblocks against the inode. */
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index 042c7d0bc0f5..bdb4685923c0 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -602,7 +602,7 @@ xrep_dinode_bad_extents_fork(
 	int			i;
 	int			fork_size;
 
-	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
+	nex = xfs_dfork_nextents(sc->mp, dip, whichfork);
 	fork_size = nex * sizeof(struct xfs_bmbt_rec);
 	if (fork_size < 0 || fork_size > dfork_size)
 		return true;
@@ -636,7 +636,7 @@ xrep_dinode_bad_btree_fork(
 	int			nrecs;
 	int			level;
 
-	if (XFS_DFORK_NEXTENTS(dip, whichfork) <=
+	if (xfs_dfork_nextents(sc->mp, dip, whichfork) <=
 			dfork_size / sizeof(struct xfs_bmbt_rec))
 		return true;
 
@@ -831,12 +831,16 @@ xrep_dinode_ensure_forkoff(
 	struct xrep_dinode_stats	*dis)
 {
 	struct xfs_bmdr_block		*bmdr;
+	xfs_extnum_t			anextents, dnextents;
 	size_t				bmdr_minsz = xfs_bmdr_space_calc(1);
 	unsigned int			lit_sz = XFS_LITINO(sc->mp);
 	unsigned int			afork_min, dfork_min;
 
 	trace_xrep_dinode_ensure_forkoff(sc, dip);
 
+	dnextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
+	anextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
+
 	/*
 	 * Before calling this function, xrep_dinode_core ensured that both
 	 * forks actually fit inside their respective literal areas.  If this
@@ -857,15 +861,14 @@ xrep_dinode_ensure_forkoff(
 		afork_min = XFS_DFORK_SIZE(dip, sc->mp, XFS_ATTR_FORK);
 		break;
 	case XFS_DINODE_FMT_EXTENTS:
-		if (dip->di_anextents) {
+		if (anextents) {
 			/*
 			 * We must maintain sufficient space to hold the entire
 			 * extent map array in the data fork.  Note that we
 			 * previously zapped the fork if it had no chance of
 			 * fitting in the inode.
 			 */
-			afork_min = sizeof(struct xfs_bmbt_rec) *
-						be16_to_cpu(dip->di_anextents);
+			afork_min = sizeof(struct xfs_bmbt_rec) * anextents;
 		} else if (dis->attr_extents > 0) {
 			/*
 			 * The attr fork thinks it has zero extents, but we
@@ -908,15 +911,14 @@ xrep_dinode_ensure_forkoff(
 		dfork_min = be64_to_cpu(dip->di_size);
 		break;
 	case XFS_DINODE_FMT_EXTENTS:
-		if (dip->di_nextents) {
+		if (dnextents) {
 			/*
 			 * We must maintain sufficient space to hold the entire
 			 * extent map array in the data fork.  Note that we
 			 * previously zapped the fork if it had no chance of
 			 * fitting in the inode.
 			 */
-			dfork_min = sizeof(struct xfs_bmbt_rec) *
-						be32_to_cpu(dip->di_nextents);
+			dfork_min = sizeof(struct xfs_bmbt_rec) * dnextents;
 		} else if (dis->data_extents > 0 || dis->rt_extents > 0) {
 			/*
 			 * The data fork thinks it has zero extents, but we
@@ -956,7 +958,7 @@ xrep_dinode_ensure_forkoff(
 	 * recovery fork, move the attr fork up.
 	 */
 	if (dip->di_format == XFS_DINODE_FMT_EXTENTS &&
-	    dip->di_nextents == 0 &&
+	    dnextents == 0 &&
 	    (dis->data_extents > 0 || dis->rt_extents > 0) &&
 	    bmdr_minsz > XFS_DFORK_DSIZE(dip, sc->mp)) {
 		if (bmdr_minsz + afork_min > lit_sz) {
@@ -982,7 +984,7 @@ xrep_dinode_ensure_forkoff(
 	 * recovery fork, move the attr fork down.
 	 */
 	if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
-	    dip->di_anextents == 0 &&
+	    anextents == 0 &&
 	    dis->attr_extents > 0 &&
 	    bmdr_minsz > XFS_DFORK_ASIZE(dip, sc->mp)) {
 		if (dip->di_format == XFS_DINODE_FMT_BTREE) {
@@ -1019,6 +1021,9 @@ xrep_dinode_zap_forks(
 	struct xfs_dinode		*dip,
 	struct xrep_dinode_stats	*dis)
 {
+	uint64_t			nblocks;
+	xfs_extnum_t			nextents;
+	xfs_extnum_t			naextents;
 	uint16_t			mode;
 	bool				zap_datafork = false;
 	bool				zap_attrfork = false;
@@ -1028,12 +1033,17 @@ xrep_dinode_zap_forks(
 	mode = be16_to_cpu(dip->di_mode);
 
 	/* Inode counters don't make sense? */
-	if (be32_to_cpu(dip->di_nextents) > be64_to_cpu(dip->di_nblocks))
+	nblocks = be64_to_cpu(dip->di_nblocks);
+
+	nextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
+	if (nextents > nblocks)
 		zap_datafork = true;
-	if (be16_to_cpu(dip->di_anextents) > be64_to_cpu(dip->di_nblocks))
+
+	naextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
+	if (naextents > nblocks)
 		zap_attrfork = true;
-	if (be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) >
-			be64_to_cpu(dip->di_nblocks))
+
+	if (nextents + naextents > nblocks)
 		zap_datafork = zap_attrfork = true;
 
 	if (!zap_datafork)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (4 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 22:22   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width Chandan Babu R
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit changes xfs_dfork_nextents() to return an error code. The extent
count itself is now returned through an out argument. This facility will be
used by a future commit to indicate an inconsistent ondisk extent count.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_inode_buf.c  | 29 +++++++----
 fs/xfs/libxfs/xfs_inode_buf.h  |  4 +-
 fs/xfs/libxfs/xfs_inode_fork.c | 22 ++++++--
 fs/xfs/scrub/inode.c           | 94 +++++++++++++++++++++-------------
 fs/xfs/scrub/inode_repair.c    | 34 ++++++++----
 5 files changed, 119 insertions(+), 64 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 6bef0757fca4..9ed04da2e2b1 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -345,7 +345,8 @@ xfs_dinode_verify_fork(
 	xfs_extnum_t		di_nextents;
 	xfs_extnum_t		max_extents;
 
-	di_nextents = xfs_dfork_nextents(mp, dip, whichfork);
+	if (xfs_dfork_nextents(mp, dip, whichfork, &di_nextents))
+		return __this_address;
 
 	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
 	case XFS_DINODE_FMT_LOCAL:
@@ -377,29 +378,31 @@ xfs_dinode_verify_fork(
 	return NULL;
 }
 
-xfs_extnum_t
+int
 xfs_dfork_nextents(
 	struct xfs_mount	*mp,
 	struct xfs_dinode	*dip,
-	int			whichfork)
+	int			whichfork,
+	xfs_extnum_t		*nextents)
 {
-	xfs_extnum_t		nextents = 0;
+	int			error = 0;
 
 	switch (whichfork) {
 	case XFS_DATA_FORK:
-		nextents = be32_to_cpu(dip->di_nextents);
+		*nextents = be32_to_cpu(dip->di_nextents);
 		break;
 
 	case XFS_ATTR_FORK:
-		nextents = be16_to_cpu(dip->di_anextents);
+		*nextents = be16_to_cpu(dip->di_anextents);
 		break;
 
 	default:
 		ASSERT(0);
+		error = -EINVAL;
 		break;
 	}
 
-	return nextents;
+	return error;
 }
 
 static xfs_failaddr_t
@@ -502,6 +505,7 @@ xfs_dinode_verify(
 	uint64_t		flags2;
 	uint64_t		di_size;
 	xfs_extnum_t            nextents;
+	xfs_extnum_t            naextents;
 	int64_t			nblocks;
 
 	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
@@ -533,8 +537,13 @@ xfs_dinode_verify(
 	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
 		return __this_address;
 
-	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
-	nextents += xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
+	if (xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents))
+		return __this_address;
+
+	if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &naextents))
+		return __this_address;
+
+	nextents += naextents;
 	nblocks = be64_to_cpu(dip->di_nblocks);
 
 	/* Fork checks carried over from xfs_iformat_fork */
@@ -595,7 +604,7 @@ xfs_dinode_verify(
 		default:
 			return __this_address;
 		}
-		if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
+		if (naextents)
 			return __this_address;
 	}
 
diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
index ea2c35091609..20f796610d46 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.h
+++ b/fs/xfs/libxfs/xfs_inode_buf.h
@@ -36,8 +36,8 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
 xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
 		uint32_t cowextsize, uint16_t mode, uint16_t flags,
 		uint64_t flags2);
-xfs_extnum_t xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
-		int whichfork);
+int xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
+		int whichfork, xfs_extnum_t *nextents);
 
 static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
 {
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 38dd2dfc31fa..7f7ffe29436d 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -107,13 +107,20 @@ xfs_iformat_extents(
 	struct xfs_mount	*mp = ip->i_mount;
 	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
 	int			state = xfs_bmap_fork_to_state(whichfork);
-	xfs_extnum_t		nex = xfs_dfork_nextents(mp, dip, whichfork);
-	int			size = nex * sizeof(xfs_bmbt_rec_t);
+	xfs_extnum_t		nex;
+	int			size;
 	struct xfs_iext_cursor	icur;
 	struct xfs_bmbt_rec	*dp;
 	struct xfs_bmbt_irec	new;
+	int			error;
 	int			i;
 
+	error = xfs_dfork_nextents(mp, dip, whichfork, &nex);
+	if (error)
+		return error;
+
+	size = nex * sizeof(xfs_bmbt_rec_t);
+
 	/*
 	 * If the number of extents is unreasonable, then something is wrong and
 	 * we just bail out rather than crash in kmem_alloc() or memcpy() below.
@@ -235,7 +242,10 @@ xfs_iformat_data_fork(
 	 * depend on it.
 	 */
 	ip->i_df.if_format = dip->di_format;
-	ip->i_df.if_nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
+	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK,
+			&ip->i_df.if_nextents);
+	if (error)
+		return error;
 
 	switch (inode->i_mode & S_IFMT) {
 	case S_IFIFO:
@@ -304,9 +314,11 @@ xfs_iformat_attr_fork(
 {
 	struct xfs_mount	*mp = ip->i_mount;
 	xfs_extnum_t		nextents;
-	int			error = 0;
+	int			error;
 
-	nextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
+	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &nextents);
+	if (error)
+		return error;
 
 	/*
 	 * Initialize the extent count early, as the per-format routines may
diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
index a161dac31a6f..e9dc3749ea08 100644
--- a/fs/xfs/scrub/inode.c
+++ b/fs/xfs/scrub/inode.c
@@ -208,6 +208,44 @@ xchk_dinode_nsec(
 		xchk_ino_set_corrupt(sc, ino);
 }
 
+STATIC void
+xchk_dinode_fork_recs(
+	struct xfs_scrub	*sc,
+	struct xfs_dinode	*dip,
+	xfs_ino_t		ino,
+	xfs_extnum_t		nextents,
+	int			whichfork)
+{
+	struct xfs_mount	*mp = sc->mp;
+	size_t			fork_recs;
+	unsigned char		format;
+
+	if (whichfork == XFS_DATA_FORK) {
+		fork_recs =  XFS_DFORK_DSIZE(dip, mp)
+			/ sizeof(struct xfs_bmbt_rec);
+		format = dip->di_format;
+	} else if (whichfork == XFS_ATTR_FORK) {
+		fork_recs =  XFS_DFORK_ASIZE(dip, mp)
+			/ sizeof(struct xfs_bmbt_rec);
+		format = dip->di_aformat;
+	}
+
+	switch (format) {
+	case XFS_DINODE_FMT_EXTENTS:
+		if (nextents > fork_recs)
+			xchk_ino_set_corrupt(sc, ino);
+		break;
+	case XFS_DINODE_FMT_BTREE:
+		if (nextents <= fork_recs)
+			xchk_ino_set_corrupt(sc, ino);
+		break;
+	default:
+		if (nextents != 0)
+			xchk_ino_set_corrupt(sc, ino);
+		break;
+	}
+}
+
 /* Scrub all the ondisk inode fields. */
 STATIC void
 xchk_dinode(
@@ -216,7 +254,6 @@ xchk_dinode(
 	xfs_ino_t		ino)
 {
 	struct xfs_mount	*mp = sc->mp;
-	size_t			fork_recs;
 	unsigned long long	isize;
 	uint64_t		flags2;
 	xfs_extnum_t		nextents;
@@ -224,6 +261,7 @@ xchk_dinode(
 	prid_t			prid;
 	uint16_t		flags;
 	uint16_t		mode;
+	int			error;
 
 	flags = be16_to_cpu(dip->di_flags);
 	if (dip->di_version >= 3)
@@ -379,33 +417,22 @@ xchk_dinode(
 	xchk_inode_extsize(sc, dip, ino, mode, flags);
 
 	/* di_nextents */
-	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
-	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
-	switch (dip->di_format) {
-	case XFS_DINODE_FMT_EXTENTS:
-		if (nextents > fork_recs)
-			xchk_ino_set_corrupt(sc, ino);
-		break;
-	case XFS_DINODE_FMT_BTREE:
-		if (nextents <= fork_recs)
-			xchk_ino_set_corrupt(sc, ino);
-		break;
-	default:
-		if (nextents != 0)
-			xchk_ino_set_corrupt(sc, ino);
-		break;
-	}
-
-	naextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
+	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents);
+	if (error)
+		xchk_ino_set_corrupt(sc, ino);
+	else
+		xchk_dinode_fork_recs(sc, dip, ino, nextents, XFS_DATA_FORK);
 
 	/* di_forkoff */
 	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
 		xchk_ino_set_corrupt(sc, ino);
-	if (naextents != 0 && dip->di_forkoff == 0)
-		xchk_ino_set_corrupt(sc, ino);
 	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
 		xchk_ino_set_corrupt(sc, ino);
 
+	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &naextents);
+	if (error || (naextents != 0 && dip->di_forkoff == 0))
+		xchk_ino_set_corrupt(sc, ino);
+
 	/* di_aformat */
 	if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
 	    dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
@@ -413,20 +440,8 @@ xchk_dinode(
 		xchk_ino_set_corrupt(sc, ino);
 
 	/* di_anextents */
-	fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
-	switch (dip->di_aformat) {
-	case XFS_DINODE_FMT_EXTENTS:
-		if (naextents > fork_recs)
-			xchk_ino_set_corrupt(sc, ino);
-		break;
-	case XFS_DINODE_FMT_BTREE:
-		if (naextents <= fork_recs)
-			xchk_ino_set_corrupt(sc, ino);
-		break;
-	default:
-		if (naextents != 0)
-			xchk_ino_set_corrupt(sc, ino);
-	}
+	if (!error)
+		xchk_dinode_fork_recs(sc, dip, ino, naextents, XFS_ATTR_FORK);
 
 	if (dip->di_version >= 3) {
 		xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
@@ -490,6 +505,7 @@ xchk_inode_xref_bmap(
 	struct xfs_dinode	*dip)
 {
 	struct xfs_mount	*mp = sc->mp;
+	xfs_extnum_t		dip_nextents;
 	xfs_extnum_t		nextents;
 	xfs_filblks_t		count;
 	xfs_filblks_t		acount;
@@ -503,14 +519,18 @@ xchk_inode_xref_bmap(
 			&nextents, &count);
 	if (!xchk_should_check_xref(sc, &error, NULL))
 		return;
-	if (nextents < xfs_dfork_nextents(mp, dip, XFS_DATA_FORK))
+
+	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &dip_nextents);
+	if (error || nextents < dip_nextents)
 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
 
 	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
 			&nextents, &acount);
 	if (!xchk_should_check_xref(sc, &error, NULL))
 		return;
-	if (nextents != xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
+
+	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &dip_nextents);
+	if (error || nextents < dip_nextents)
 		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
 
 	/* Check nblocks against the inode. */
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index bdb4685923c0..521c8df00990 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -602,7 +602,9 @@ xrep_dinode_bad_extents_fork(
 	int			i;
 	int			fork_size;
 
-	nex = xfs_dfork_nextents(sc->mp, dip, whichfork);
+	if (xfs_dfork_nextents(sc->mp, dip, whichfork, &nex))
+		return true;
+
 	fork_size = nex * sizeof(struct xfs_bmbt_rec);
 	if (fork_size < 0 || fork_size > dfork_size)
 		return true;
@@ -633,11 +635,14 @@ xrep_dinode_bad_btree_fork(
 	int			whichfork)
 {
 	struct xfs_bmdr_block	*dfp;
+	xfs_extnum_t		nextents;
 	int			nrecs;
 	int			level;
 
-	if (xfs_dfork_nextents(sc->mp, dip, whichfork) <=
-			dfork_size / sizeof(struct xfs_bmbt_rec))
+	if (xfs_dfork_nextents(sc->mp, dip, whichfork, &nextents))
+		return true;
+
+	if (nextents <= dfork_size / sizeof(struct xfs_bmbt_rec))
 		return true;
 
 	if (dfork_size < sizeof(struct xfs_bmdr_block))
@@ -774,11 +779,15 @@ xrep_dinode_check_afork(
 	struct xfs_dinode		*dip)
 {
 	struct xfs_attr_shortform	*sfp;
+	xfs_extnum_t			nextents;
 	int				size;
 
+	if (xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK, &nextents))
+		return true;
+
 	if (XFS_DFORK_BOFF(dip) == 0)
 		return dip->di_aformat != XFS_DINODE_FMT_EXTENTS ||
-		       dip->di_anextents != 0;
+		       nextents != 0;
 
 	size = XFS_DFORK_SIZE(dip, sc->mp, XFS_ATTR_FORK);
 	switch (XFS_DFORK_FORMAT(dip, XFS_ATTR_FORK)) {
@@ -835,11 +844,15 @@ xrep_dinode_ensure_forkoff(
 	size_t				bmdr_minsz = xfs_bmdr_space_calc(1);
 	unsigned int			lit_sz = XFS_LITINO(sc->mp);
 	unsigned int			afork_min, dfork_min;
+	int				error;
 
 	trace_xrep_dinode_ensure_forkoff(sc, dip);
 
-	dnextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
-	anextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
+	error = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK, &dnextents);
+	ASSERT(error == 0);
+
+	error = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK, &anextents);
+	ASSERT(error == 0);
 
 	/*
 	 * Before calling this function, xrep_dinode_core ensured that both
@@ -1027,6 +1040,7 @@ xrep_dinode_zap_forks(
 	uint16_t			mode;
 	bool				zap_datafork = false;
 	bool				zap_attrfork = false;
+	int				error;
 
 	trace_xrep_dinode_zap_forks(sc, dip);
 
@@ -1035,12 +1049,12 @@ xrep_dinode_zap_forks(
 	/* Inode counters don't make sense? */
 	nblocks = be64_to_cpu(dip->di_nblocks);
 
-	nextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
-	if (nextents > nblocks)
+	error = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK, &nextents);
+	if (error || nextents > nblocks)
 		zap_datafork = true;
 
-	naextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
-	if (naextents > nblocks)
+	error = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK, &naextents);
+	if (error || naextents > nblocks)
 		zap_attrfork = true;
 
 	if (nextents + naextents > nblocks)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (5 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 22:50   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 08/12] xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits respectively Chandan Babu R
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit renames extent counter fields in "struct xfs_dinode" and "struct
xfs_log_dinode" based on the width of the fields. As of this commit, the
32-bit field will be used to count data fork extents and the 16-bit field will
be used to count attr fork extents.

This change is done to enable a future commit to introduce a new 64-bit extent
counter field.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_format.h      |  4 ++--
 fs/xfs/libxfs/xfs_inode_buf.c   |  8 ++++----
 fs/xfs/libxfs/xfs_log_format.h  |  4 ++--
 fs/xfs/scrub/inode_repair.c     |  4 ++--
 fs/xfs/scrub/trace.h            | 14 +++++++-------
 fs/xfs/xfs_inode_item.c         |  4 ++--
 fs/xfs/xfs_inode_item_recover.c |  8 ++++----
 7 files changed, 23 insertions(+), 23 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 001a4077a7c6..2362cc005cc6 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -1039,8 +1039,8 @@ typedef struct xfs_dinode {
 	__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*/
+	__be32		di_nextents32;	/* number of extents in data fork */
+	__be16		di_nextents16;	/* number of extents in attribute fork*/
 	__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 */
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 9ed04da2e2b1..65d753e16007 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -313,8 +313,8 @@ 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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
+	to->di_nextents16 = 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);
@@ -389,11 +389,11 @@ xfs_dfork_nextents(
 
 	switch (whichfork) {
 	case XFS_DATA_FORK:
-		*nextents = be32_to_cpu(dip->di_nextents);
+		*nextents = be32_to_cpu(dip->di_nextents32);
 		break;
 
 	case XFS_ATTR_FORK:
-		*nextents = be16_to_cpu(dip->di_anextents);
+		*nextents = be16_to_cpu(dip->di_nextents16);
 		break;
 
 	default:
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index 0c888f92184e..ca8e4ad8312a 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -402,8 +402,8 @@ struct xfs_log_dinode {
 	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 */
-	xfs_extnum_t	di_nextents;	/* number of extents in data fork */
-	xfs_aextnum_t	di_anextents;	/* number of extents in attribute fork*/
+	uint32_t	di_nextents32;	/* number of extents in data fork */
+	uint16_t	di_nextents16;	/* number of extents in attribute fork*/
 	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 */
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index 521c8df00990..4d773a16f886 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -736,7 +736,7 @@ xrep_dinode_zap_dfork(
 {
 	trace_xrep_dinode_zap_dfork(sc, dip);
 
-	dip->di_nextents = 0;
+	dip->di_nextents32 = 0;
 
 	/* Special files always get reset to DEV */
 	switch (mode & S_IFMT) {
@@ -823,7 +823,7 @@ xrep_dinode_zap_afork(
 	trace_xrep_dinode_zap_afork(sc, dip);
 
 	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
-	dip->di_anextents = 0;
+	dip->di_nextents16 = 0;
 
 	dip->di_forkoff = 0;
 	dip->di_mode = cpu_to_be16(mode & ~0777);
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index fd03685b1f6b..a0303f692e52 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -1209,8 +1209,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
 		__field(uint64_t, size)
 		__field(uint64_t, nblocks)
 		__field(uint32_t, extsize)
-		__field(uint32_t, nextents)
-		__field(uint16_t, anextents)
+		__field(uint32_t, nextents32)
+		__field(uint16_t, nextents16)
 		__field(uint8_t, forkoff)
 		__field(uint8_t, aformat)
 		__field(uint16_t, flags)
@@ -1229,8 +1229,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
 		__entry->size = be64_to_cpu(dip->di_size);
 		__entry->nblocks = be64_to_cpu(dip->di_nblocks);
 		__entry->extsize = be32_to_cpu(dip->di_extsize);
-		__entry->nextents = be32_to_cpu(dip->di_nextents);
-		__entry->anextents = be16_to_cpu(dip->di_anextents);
+		__entry->nextents32 = be32_to_cpu(dip->di_nextents32);
+		__entry->nextents16 = be16_to_cpu(dip->di_nextents16);
 		__entry->forkoff = dip->di_forkoff;
 		__entry->aformat = dip->di_aformat;
 		__entry->flags = be16_to_cpu(dip->di_flags);
@@ -1238,7 +1238,7 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
 		__entry->flags2 = be64_to_cpu(dip->di_flags2);
 		__entry->cowextsize = be32_to_cpu(dip->di_cowextsize);
 	),
-	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents %u anextents %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
+	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents32 %u nextents16 %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->ino,
 		  __entry->mode,
@@ -1249,8 +1249,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
 		  __entry->size,
 		  __entry->nblocks,
 		  __entry->extsize,
-		  __entry->nextents,
-		  __entry->anextents,
+		  __entry->nextents32,
+		  __entry->nextents16,
 		  __entry->forkoff,
 		  __entry->aformat,
 		  __entry->flags,
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index 35de30849fcc..f54ce7468ba1 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -385,8 +385,8 @@ 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_nextents32 = xfs_ifork_nextents(&ip->i_df);
+	to->di_nextents16 = 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;
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
index 7b79518b6c20..40af9d1265c7 100644
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -166,8 +166,8 @@ xfs_log_dinode_to_disk(
 	to->di_size = cpu_to_be64(from->di_size);
 	to->di_nblocks = cpu_to_be64(from->di_nblocks);
 	to->di_extsize = cpu_to_be32(from->di_extsize);
-	to->di_nextents = cpu_to_be32(from->di_nextents);
-	to->di_anextents = cpu_to_be16(from->di_anextents);
+	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
+	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
 	to->di_forkoff = from->di_forkoff;
 	to->di_aformat = from->di_aformat;
 	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
@@ -332,7 +332,7 @@ xlog_recover_inode_commit_pass2(
 			goto out_release;
 		}
 	}
-	if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){
+	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
 		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
 				     XFS_ERRLEVEL_LOW, mp, ldip,
 				     sizeof(*ldip));
@@ -340,7 +340,7 @@ xlog_recover_inode_commit_pass2(
 	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
 	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
 			__func__, item, dip, bp, in_f->ilf_ino,
-			ldip->di_nextents + ldip->di_anextents,
+			ldip->di_nextents32 + ldip->di_nextents16,
 			ldip->di_nblocks);
 		error = -EFSCORRUPTED;
 		goto out_release;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 08/12] xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits respectively
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (6 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 22:29   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 Chandan Babu R
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

A future commit will introduce a 64-bit on-disk data extent counter and a
32-bit on-disk attr extent counter. This commit promotes xfs_extnum_t and
xfs_aextnum_t to 64 and 32-bits in order to correctly handle in-core versions
of these quantities.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_bmap.c       | 2 +-
 fs/xfs/libxfs/xfs_inode_fork.c | 2 +-
 fs/xfs/libxfs/xfs_types.h      | 4 ++--
 fs/xfs/scrub/attr_repair.c     | 2 +-
 fs/xfs/scrub/trace.h           | 2 +-
 fs/xfs/xfs_inode.c             | 4 ++--
 fs/xfs/xfs_trace.h             | 4 ++--
 7 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index e5d243fd187d..a27d57ea301c 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -472,7 +472,7 @@ xfs_bmap_check_leaf_extents(
 	if (bp_release)
 		xfs_trans_brelse(NULL, bp);
 error_norelse:
-	xfs_warn(mp, "%s: BAD after btree leaves for %d extents",
+	xfs_warn(mp, "%s: BAD after btree leaves for %llu extents",
 		__func__, i);
 	xfs_err(mp, "%s: CORRUPTED BTREE OR SOMETHING", __func__);
 	xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
index 7f7ffe29436d..336eee69703c 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.c
+++ b/fs/xfs/libxfs/xfs_inode_fork.c
@@ -126,7 +126,7 @@ xfs_iformat_extents(
 	 * we just bail out rather than crash in kmem_alloc() or memcpy() below.
 	 */
 	if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, mp, whichfork))) {
-		xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
+		xfs_warn(ip->i_mount, "corrupt inode %llu ((a)extents = %llu).",
 			(unsigned long long) ip->i_ino, nex);
 		xfs_inode_verifier_error(ip, -EFSCORRUPTED,
 				"xfs_iformat_extents(1)", dip, sizeof(*dip),
diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
index 8908346b1deb..584fa61e338e 100644
--- a/fs/xfs/libxfs/xfs_types.h
+++ b/fs/xfs/libxfs/xfs_types.h
@@ -12,8 +12,8 @@ typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
 typedef uint32_t	xfs_agino_t;	/* inode # within allocation grp */
 typedef uint32_t	xfs_extlen_t;	/* extent length in blocks */
 typedef uint32_t	xfs_agnumber_t;	/* allocation group number */
-typedef int32_t		xfs_extnum_t;	/* # of extents in a file */
-typedef int16_t		xfs_aextnum_t;	/* # extents in an attribute fork */
+typedef uint64_t	xfs_extnum_t;	/* # of extents in a file */
+typedef uint32_t	xfs_aextnum_t;	/* # extents in an attribute fork */
 typedef int64_t		xfs_fsize_t;	/* bytes in a file */
 typedef uint64_t	xfs_ufsize_t;	/* unsigned bytes in a file */
 
diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c
index 7d92195d286b..aad4b269949d 100644
--- a/fs/xfs/scrub/attr_repair.c
+++ b/fs/xfs/scrub/attr_repair.c
@@ -769,7 +769,7 @@ xrep_xattr_fork_remove(
 		unsigned int		i = 0;
 
 		xfs_emerg(sc->mp,
-	"inode 0x%llx attr fork still has %u attr extents, format %d?!",
+	"inode 0x%llx attr fork still has %llu attr extents, format %d?!",
 				ip->i_ino, ifp->if_nextents, ifp->if_format);
 		for_each_xfs_iext(ifp, &icur, &irec) {
 			xfs_err(sc->mp, "[%u]: startoff %llu startblock %llu blockcount %llu state %u", i++, irec.br_startoff, irec.br_startblock, irec.br_blockcount, irec.br_state);
diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
index a0303f692e52..f9be7812c8ce 100644
--- a/fs/xfs/scrub/trace.h
+++ b/fs/xfs/scrub/trace.h
@@ -1363,7 +1363,7 @@ TRACE_EVENT(xrep_dinode_count_rmaps,
 		__entry->attr_extents = attr_extents;
 		__entry->block0 = block0;
 	),
-	TP_printk("dev %d:%d ino 0x%llx dblocks %llu rtblocks %llu ablocks %llu dextents %u rtextents %u aextents %u block0 %llu",
+	TP_printk("dev %d:%d ino 0x%llx dblocks %llu rtblocks %llu ablocks %llu dextents %llu rtextents %llu aextents %u block0 %llu",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->ino,
 		  __entry->data_blocks,
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index f152f6dace0c..4070fb01350c 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2510,8 +2510,8 @@ xfs_iflush(
 	if (XFS_TEST_ERROR(ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp) >
 				ip->i_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
 		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
-			"%s: detected corrupt incore inode %Lu, "
-			"total extents = %d, nblocks = %Ld, ptr "PTR_FMT,
+			"%s: detected corrupt incore inode %llu, "
+			"total extents = %llu nblocks = %lld, ptr "PTR_FMT,
 			__func__, ip->i_ino,
 			ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp),
 			ip->i_nblocks, ip);
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index 5ed11f894f79..af426b9824db 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -2351,7 +2351,7 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
 		__entry->broot_size = ip->i_df.if_broot_bytes;
 		__entry->fork_off = XFS_IFORK_BOFF(ip);
 	),
-	TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, "
+	TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %llu, "
 		  "broot size %d, fork offset %d",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->ino,
@@ -4588,7 +4588,7 @@ TRACE_EVENT(xfs_swapext_delta_nextents,
 		__entry->d_nexts1 = d_nexts1;
 		__entry->d_nexts2 = d_nexts2;
 	),
-	TP_printk("dev %d:%d ino1 0x%llx nexts %u ino2 0x%llx nexts %u delta1 %lld delta2 %lld",
+	TP_printk("dev %d:%d ino1 0x%llx nexts %llu ino2 0x%llx nexts %llu delta1 %lld delta2 %lld",
 		  MAJOR(__entry->dev), MINOR(__entry->dev),
 		  __entry->ino1, __entry->nexts1,
 		  __entry->ino2, __entry->nexts2,
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (7 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 08/12] xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits respectively Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 22:54   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 10/12] xfs: Enable bulkstat ioctl to support 64-bit extent counters Chandan Babu R
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit renames XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 to allow a future
commit to extend bulkstat facility to support 64-bit extent counters. To this
end, this commit also renames xfs_bulkstat->bs_extents field to
xfs_bulkstat->bs_extents32.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_fs.h |  4 ++--
 fs/xfs/xfs_ioctl.c     | 27 ++++++++++++++++++++++-----
 fs/xfs/xfs_ioctl32.c   |  7 +++++++
 fs/xfs/xfs_itable.c    |  4 ++--
 fs/xfs/xfs_itable.h    |  1 +
 5 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 2594fb647384..d760a969599e 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -394,7 +394,7 @@ struct xfs_bulkstat {
 	uint32_t	bs_extsize_blks; /* extent size hint, blocks	*/
 
 	uint32_t	bs_nlink;	/* number of links		*/
-	uint32_t	bs_extents;	/* number of extents		*/
+	uint32_t	bs_extents32;	/* number of extents		*/
 	uint32_t	bs_aextents;	/* attribute number of extents	*/
 	uint16_t	bs_version;	/* structure version		*/
 	uint16_t	bs_forkoff;	/* inode fork offset in bytes	*/
@@ -853,7 +853,7 @@ struct xfs_scrub_metadata {
 #define XFS_IOC_FSGEOMETRY_V4	     _IOR ('X', 124, struct xfs_fsop_geom_v4)
 #define XFS_IOC_GOINGDOWN	     _IOR ('X', 125, uint32_t)
 #define XFS_IOC_FSGEOMETRY	     _IOR ('X', 126, struct xfs_fsop_geom)
-#define XFS_IOC_BULKSTAT	     _IOR ('X', 127, struct xfs_bulkstat_req)
+#define XFS_IOC_BULKSTAT_V5	     _IOR ('X', 127, struct xfs_bulkstat_req)
 #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
 /*	FIEXCHANGE_RANGE ----------- hoisted 129	 */
 /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 2da90f81e6e3..85f45340cb16 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -715,6 +715,8 @@ xfs_fsbulkstat_one_fmt(
 {
 	struct xfs_bstat		bs1;
 
+	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V1);
+
 	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
 	if (copy_to_user(breq->ubuffer, &bs1, sizeof(bs1)))
 		return -EFAULT;
@@ -728,6 +730,8 @@ xfs_fsinumbers_fmt(
 {
 	struct xfs_inogrp		ig1;
 
+	ASSERT(breq->version == XFS_INUMBERS_VERSION_V1);
+
 	xfs_inumbers_to_inogrp(&ig1, igrp);
 	if (copy_to_user(breq->ubuffer, &ig1, sizeof(struct xfs_inogrp)))
 		return -EFAULT;
@@ -787,14 +791,17 @@ xfs_ioc_fsbulkstat(
 	 */
 	if (cmd == XFS_IOC_FSINUMBERS) {
 		breq.startino = lastino ? lastino + 1 : 0;
+		breq.version = XFS_INUMBERS_VERSION_V1;
 		error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
 		lastino = breq.startino - 1;
 	} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
 		breq.startino = lastino;
 		breq.icount = 1;
+		breq.version = XFS_BULKSTAT_VERSION_V1;
 		error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
 	} else {	/* XFS_IOC_FSBULKSTAT */
 		breq.startino = lastino ? lastino + 1 : 0;
+		breq.version = XFS_BULKSTAT_VERSION_V1;
 		error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
 		lastino = breq.startino - 1;
 	}
@@ -819,6 +826,8 @@ xfs_bulkstat_fmt(
 	struct xfs_ibulk		*breq,
 	const struct xfs_bulkstat	*bstat)
 {
+	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V5);
+
 	if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat)))
 		return -EFAULT;
 	return xfs_ibulk_advance(breq, sizeof(struct xfs_bulkstat));
@@ -918,13 +927,15 @@ STATIC int
 xfs_ioc_bulkstat(
 	struct file			*file,
 	unsigned int			cmd,
-	struct xfs_bulkstat_req __user	*arg)
+	struct xfs_bulkstat_req __user	*arg,
+	int				version)
 {
 	struct xfs_mount		*mp = XFS_I(file_inode(file))->i_mount;
 	struct xfs_bulk_ireq		hdr;
 	struct xfs_ibulk		breq = {
 		.mp			= mp,
 		.mnt_userns		= file_mnt_user_ns(file),
+		.version		= version,
 	};
 	int				error;
 
@@ -960,6 +971,8 @@ xfs_inumbers_fmt(
 	struct xfs_ibulk		*breq,
 	const struct xfs_inumbers	*igrp)
 {
+	ASSERT(breq->version == XFS_INUMBERS_VERSION_V5);
+
 	if (copy_to_user(breq->ubuffer, igrp, sizeof(struct xfs_inumbers)))
 		return -EFAULT;
 	return xfs_ibulk_advance(breq, sizeof(struct xfs_inumbers));
@@ -970,11 +983,13 @@ STATIC int
 xfs_ioc_inumbers(
 	struct xfs_mount		*mp,
 	unsigned int			cmd,
-	struct xfs_inumbers_req __user	*arg)
+	struct xfs_inumbers_req __user	*arg,
+	int				version)
 {
 	struct xfs_bulk_ireq		hdr;
 	struct xfs_ibulk		breq = {
 		.mp			= mp,
+		.version		= version,
 	};
 	int				error;
 
@@ -1882,10 +1897,12 @@ xfs_file_ioctl(
 	case XFS_IOC_FSINUMBERS:
 		return xfs_ioc_fsbulkstat(filp, cmd, arg);
 
-	case XFS_IOC_BULKSTAT:
-		return xfs_ioc_bulkstat(filp, cmd, arg);
+	case XFS_IOC_BULKSTAT_V5:
+		return xfs_ioc_bulkstat(filp, cmd, arg,
+				XFS_BULKSTAT_VERSION_V5);
 	case XFS_IOC_INUMBERS:
-		return xfs_ioc_inumbers(mp, cmd, arg);
+		return xfs_ioc_inumbers(mp, cmd, arg,
+				XFS_INUMBERS_VERSION_V5);
 
 	case XFS_IOC_FSGEOMETRY_V1:
 		return xfs_ioc_fsgeometry(mp, arg, 3);
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index bef19060f4aa..d9a7abc209b5 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -88,6 +88,8 @@ xfs_fsinumbers_fmt_compat(
 	struct xfs_inogrp		ig1;
 	struct xfs_inogrp		*igrp = &ig1;
 
+	ASSERT(breq->version == XFS_INUMBERS_VERSION_V1);
+
 	xfs_inumbers_to_inogrp(&ig1, ig);
 
 	if (put_user(igrp->xi_startino,   &p32->xi_startino) ||
@@ -177,6 +179,8 @@ xfs_fsbulkstat_one_fmt_compat(
 	struct xfs_bstat		bs1;
 	struct xfs_bstat		*buffer = &bs1;
 
+	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V1);
+
 	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
 
 	if (put_user(buffer->bs_ino,	  &p32->bs_ino)		||
@@ -293,15 +297,18 @@ xfs_compat_ioc_fsbulkstat(
 	 */
 	if (cmd == XFS_IOC_FSINUMBERS_32) {
 		breq.startino = lastino ? lastino + 1 : 0;
+		breq.version = XFS_INUMBERS_VERSION_V1;
 		error = xfs_inumbers(&breq, inumbers_func);
 		lastino = breq.startino - 1;
 	} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
 		breq.startino = lastino;
 		breq.icount = 1;
+		breq.version = XFS_BULKSTAT_VERSION_V1;
 		error = xfs_bulkstat_one(&breq, bs_one_func);
 		lastino = breq.startino;
 	} else if (cmd == XFS_IOC_FSBULKSTAT_32) {
 		breq.startino = lastino ? lastino + 1 : 0;
+		breq.version = XFS_BULKSTAT_VERSION_V1;
 		error = xfs_bulkstat(&breq, bs_one_func);
 		lastino = breq.startino - 1;
 	} else {
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 65c194cdea79..f0daa65e61ff 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -134,7 +134,7 @@ xfs_bulkstat_one_int(
 
 	buf->bs_xflags = xfs_ip2xflags(ip);
 	buf->bs_extsize_blks = ip->i_extsize;
-	buf->bs_extents = xfs_ifork_nextents(&ip->i_df);
+	buf->bs_extents32 = xfs_ifork_nextents(&ip->i_df);
 	xfs_bulkstat_health(ip, buf);
 	buf->bs_aextents = xfs_ifork_nextents(ip->i_afp);
 	buf->bs_forkoff = XFS_IFORK_BOFF(ip);
@@ -356,7 +356,7 @@ xfs_bulkstat_to_bstat(
 	bs1->bs_blocks = bstat->bs_blocks;
 	bs1->bs_xflags = bstat->bs_xflags;
 	bs1->bs_extsize = XFS_FSB_TO_B(mp, bstat->bs_extsize_blks);
-	bs1->bs_extents = bstat->bs_extents;
+	bs1->bs_extents = bstat->bs_extents32;
 	bs1->bs_gen = bstat->bs_gen;
 	bs1->bs_projid_lo = bstat->bs_projectid & 0xFFFF;
 	bs1->bs_forkoff = bstat->bs_forkoff;
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
index f5a13f69883a..ee4d8d0461ca 100644
--- a/fs/xfs/xfs_itable.h
+++ b/fs/xfs/xfs_itable.h
@@ -14,6 +14,7 @@ struct xfs_ibulk {
 	unsigned int		icount;   /* number of elements in ubuffer */
 	unsigned int		ocount;   /* number of records returned */
 	unsigned int		flags;    /* see XFS_IBULK_FLAG_* */
+	int			version;  /* structure version to be returned */
 };
 
 /* Only iterate within the same AG as startino */
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 10/12] xfs: Enable bulkstat ioctl to support 64-bit extent counters
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (8 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-26 11:45 ` [PATCH V2 11/12] xfs: Extend per-inode extent counter widths Chandan Babu R
                   ` (2 subsequent siblings)
  12 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit adds XFS_IOC_BULKSTAT_V6 to support 64-bit inode extent
counters. The new field xfs_bulkstat->bs_extents64 is added to hold data
extent count for filesystems supporting 64-bit data extent counters.

However, the accessibility of this ioctl is deferred to a future commit which
actually adds support for 64-bit data extent counter.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_fs.h |  6 ++++--
 fs/xfs/xfs_ioctl.c     |  5 +++--
 fs/xfs/xfs_itable.c    | 26 +++++++++++++++++++++++---
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index d760a969599e..756be4ff5996 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -394,7 +394,7 @@ struct xfs_bulkstat {
 	uint32_t	bs_extsize_blks; /* extent size hint, blocks	*/
 
 	uint32_t	bs_nlink;	/* number of links		*/
-	uint32_t	bs_extents32;	/* number of extents		*/
+	uint32_t	bs_extents32;	/* number of extents; v5 only	*/
 	uint32_t	bs_aextents;	/* attribute number of extents	*/
 	uint16_t	bs_version;	/* structure version		*/
 	uint16_t	bs_forkoff;	/* inode fork offset in bytes	*/
@@ -403,12 +403,14 @@ struct xfs_bulkstat {
 	uint16_t	bs_checked;	/* checked inode metadata	*/
 	uint16_t	bs_mode;	/* type and mode		*/
 	uint16_t	bs_pad2;	/* zeroed			*/
+	uint64_t	bs_extents64;	/* number of extents; v6 only	*/
 
-	uint64_t	bs_pad[7];	/* zeroed			*/
+	uint64_t	bs_pad[6];	/* zeroed			*/
 };
 
 #define XFS_BULKSTAT_VERSION_V1	(1)
 #define XFS_BULKSTAT_VERSION_V5	(5)
+#define XFS_BULKSTAT_VERSION_V6	(6)
 
 /* bs_sick flags */
 #define XFS_BS_SICK_INODE	(1 << 0)  /* inode core */
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 85f45340cb16..19964b394dc4 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -826,7 +826,8 @@ xfs_bulkstat_fmt(
 	struct xfs_ibulk		*breq,
 	const struct xfs_bulkstat	*bstat)
 {
-	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V5);
+	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V5 ||
+		breq->version == XFS_BULKSTAT_VERSION_V6);
 
 	if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat)))
 		return -EFAULT;
@@ -922,7 +923,7 @@ xfs_bulk_ireq_teardown(
 	hdr->ocount = breq->ocount;
 }
 
-/* Handle the v5 bulkstat ioctl. */
+/* Handle the v5/v6 bulkstat ioctl. */
 STATIC int
 xfs_ioc_bulkstat(
 	struct file			*file,
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index f0daa65e61ff..8493870a0a87 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -74,6 +74,7 @@ xfs_bulkstat_one_int(
 	struct xfs_inode	*ip;		/* incore inode pointer */
 	struct inode		*inode;
 	struct xfs_bulkstat	*buf = bc->buf;
+	xfs_extnum_t		nextents;
 	int			error = -EINVAL;
 
 	error = xfs_iget(mp, tp, ino,
@@ -95,7 +96,12 @@ xfs_bulkstat_one_int(
 		buf->bs_gen = inode->i_generation;
 		buf->bs_mode = inode->i_mode & S_IFMT;
 		xfs_bulkstat_health(ip, buf);
-		buf->bs_version = XFS_BULKSTAT_VERSION_V5;
+
+		if (bc->breq->version != XFS_BULKSTAT_VERSION_V6)
+			buf->bs_version = XFS_BULKSTAT_VERSION_V5;
+		else
+			buf->bs_version = XFS_BULKSTAT_VERSION_V6;
+
 		xfs_iunlock(ip, XFS_ILOCK_SHARED);
 		xfs_irele(ip);
 
@@ -134,11 +140,25 @@ xfs_bulkstat_one_int(
 
 	buf->bs_xflags = xfs_ip2xflags(ip);
 	buf->bs_extsize_blks = ip->i_extsize;
-	buf->bs_extents32 = xfs_ifork_nextents(&ip->i_df);
+
+	nextents = xfs_ifork_nextents(&ip->i_df);
+	if (bc->breq->version != XFS_BULKSTAT_VERSION_V6) {
+		if (nextents > XFS_IFORK_EXTCNT_MAXS32) {
+			xfs_iunlock(ip, XFS_ILOCK_SHARED);
+			xfs_irele(ip);
+			error = -EINVAL;
+			goto out_advance;
+		}
+		buf->bs_extents32 = nextents;
+		buf->bs_version = XFS_BULKSTAT_VERSION_V5;
+	} else {
+		buf->bs_extents64 = nextents;
+		buf->bs_version = XFS_BULKSTAT_VERSION_V6;
+	}
+
 	xfs_bulkstat_health(ip, buf);
 	buf->bs_aextents = xfs_ifork_nextents(ip->i_afp);
 	buf->bs_forkoff = XFS_IFORK_BOFF(ip);
-	buf->bs_version = XFS_BULKSTAT_VERSION_V5;
 
 	if (xfs_sb_version_has_v3inode(&mp->m_sb)) {
 		buf->bs_btime = ip->i_crtime.tv_sec;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 11/12] xfs: Extend per-inode extent counter widths
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (9 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 10/12] xfs: Enable bulkstat ioctl to support 64-bit extent counters Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 23:09   ` Darrick J. Wong
  2021-07-26 11:45 ` [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count Chandan Babu R
  2021-07-28 21:27 ` [PATCH V2 00/12] xfs: Extend per-inode extent counters Darrick J. Wong
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit adds a new 64-bit per-inode data extent counter. However the
maximum number of extents that a data fork can hold is limited to 2^48
extents. This feature is available only when
XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT feature bit is enabled on the
filesystem. Also, enabling this feature bit causes attr fork extent counter to
use the 32-bit extent counter that was previously used to hold the data fork
extent counter. This implies that the attr fork can now occupy a maximum of
2^32 extents.

This commit also exposes the newly introduced XFS_IOC_BULKSTAT_V6 ioctl
interface to user space.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_bmap.c        |  8 +++-----
 fs/xfs/libxfs/xfs_format.h      | 27 ++++++++++++++++++++++++---
 fs/xfs/libxfs/xfs_fs.h          |  1 +
 fs/xfs/libxfs/xfs_inode_buf.c   | 28 ++++++++++++++++++++++++----
 fs/xfs/libxfs/xfs_inode_fork.h  | 22 +++++++++++++++++-----
 fs/xfs/libxfs/xfs_log_format.h  |  3 ++-
 fs/xfs/scrub/inode_repair.c     | 11 +++++++++--
 fs/xfs/xfs_inode.c              |  2 +-
 fs/xfs/xfs_inode_item.c         | 15 +++++++++++++--
 fs/xfs/xfs_inode_item_recover.c | 25 +++++++++++++++++++------
 fs/xfs/xfs_ioctl.c              |  3 +++
 11 files changed, 116 insertions(+), 29 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index a27d57ea301c..e05898c9acbc 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -54,18 +54,16 @@ xfs_bmap_compute_maxlevels(
 	int		whichfork)	/* data or attr fork */
 {
 	xfs_extnum_t	maxleafents;	/* max leaf entries possible */
+	uint64_t	maxblocks;	/* max blocks at this level */
 	int		level;		/* btree level */
-	uint		maxblocks;	/* max blocks at this level */
 	int		maxrootrecs;	/* max records in root block */
 	int		minleafrecs;	/* min records in leaf block */
 	int		minnoderecs;	/* min records in node block */
 	int		sz;		/* root block size */
 
 	/*
-	 * The maximum number of extents in a file, hence the maximum number of
-	 * leaf entries, is controlled by the size of the on-disk extent count,
-	 * either a signed 32-bit number for the data fork, or a signed 16-bit
-	 * number for the attr fork.
+	 * The maximum number of extents in a fork, hence the maximum number of
+	 * leaf entries, is controlled by the size of the on-disk extent count.
 	 *
 	 * Note that we can no longer assume that if we are in ATTR1 that the
 	 * fork offset of all the inodes will be
diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
index 2362cc005cc6..3aa83d75670d 100644
--- a/fs/xfs/libxfs/xfs_format.h
+++ b/fs/xfs/libxfs/xfs_format.h
@@ -485,13 +485,15 @@ xfs_sb_has_ro_compat_feature(
 #define XFS_SB_FEAT_INCOMPAT_BIGTIME	(1 << 3)	/* large timestamps */
 #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4)	/* needs xfs_repair */
 #define XFS_SB_FEAT_INCOMPAT_METADIR	(1 << 5)	/* metadata dir tree */
-#define XFS_SB_FEAT_INCOMPAT_ALL \
+#define XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT (1 << 6)	/* 64-bit inode fork extent counter */
+#define XFS_SB_FEAT_INCOMPAT_ALL		\
 		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
 		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
 		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
 		 XFS_SB_FEAT_INCOMPAT_BIGTIME| \
 		 XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \
-		 XFS_SB_FEAT_INCOMPAT_METADIR)
+		 XFS_SB_FEAT_INCOMPAT_METADIR| \
+		 XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT)
 
 #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
 static inline bool
@@ -591,6 +593,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
 		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
 }
 
+static inline bool xfs_sb_version_hasextcount_64bit(struct xfs_sb *sbp)
+{
+	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
+		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT);
+}
+
 static inline bool xfs_sb_version_hasrmapbt(struct xfs_sb *sbp)
 {
 	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
@@ -1039,6 +1047,16 @@ typedef struct xfs_dinode {
 	__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 */
+
+	/*
+	 * On a extcnt64bit filesystem, di_nextents64 holds the data fork
+	 * extent count, di_nextents32 holds the attr fork extent count,
+	 * and di_nextents16 must be zero.
+	 *
+	 * Otherwise, di_nextents32 holds the data fork extent count,
+	 * di_nextents16 holds the attr fork extent count, and di_nextents64
+	 * must be zero.
+	 */
 	__be32		di_nextents32;	/* number of extents in data fork */
 	__be16		di_nextents16;	/* number of extents in attribute fork*/
 	__u8		di_forkoff;	/* attr fork offs, <<3 for 64b align */
@@ -1057,7 +1075,8 @@ typedef struct xfs_dinode {
 	__be64		di_lsn;		/* flush sequence */
 	__be64		di_flags2;	/* more random flags */
 	__be32		di_cowextsize;	/* basic cow extent size for file */
-	__u8		di_pad2[12];	/* more padding for future expansion */
+	__u8		di_pad2[4];	/* more padding for future expansion */
+	__be64		di_nextents64;
 
 	/* fields only written to during inode creation */
 	xfs_timestamp_t	di_crtime;	/* time created */
@@ -1113,6 +1132,8 @@ enum xfs_dinode_fmt {
  * Max values for extlen and disk inode's extent counters.
  */
 #define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
+#define XFS_IFORK_EXTCNT_MAXU48	((uint64_t)0xffffffffffff) /* Unsigned 48-bits */
+#define XFS_IFORK_EXTCNT_MAXU32	((uint32_t)0xffffffff)	/* Unsigned 32-bits */
 #define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
 #define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
 
diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
index 756be4ff5996..57f67445f095 100644
--- a/fs/xfs/libxfs/xfs_fs.h
+++ b/fs/xfs/libxfs/xfs_fs.h
@@ -858,6 +858,7 @@ struct xfs_scrub_metadata {
 #define XFS_IOC_BULKSTAT_V5	     _IOR ('X', 127, struct xfs_bulkstat_req)
 #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
 /*	FIEXCHANGE_RANGE ----------- hoisted 129	 */
+#define XFS_IOC_BULKSTAT_V6	     _IOR ('X', 130, struct xfs_bulkstat_req)
 /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
 
 
diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
index 65d753e16007..28e49394edbb 100644
--- a/fs/xfs/libxfs/xfs_inode_buf.c
+++ b/fs/xfs/libxfs/xfs_inode_buf.c
@@ -291,6 +291,7 @@ xfs_inode_to_disk(
 	struct xfs_dinode	*to,
 	xfs_lsn_t		lsn)
 {
+	struct xfs_sb		*sbp = &ip->i_mount->m_sb;
 	struct inode		*inode = VFS_I(ip);
 
 	to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
@@ -313,8 +314,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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
-	to->di_nextents16 = 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);
@@ -334,6 +333,19 @@ xfs_inode_to_disk(
 		to->di_version = 2;
 		to->di_flushiter = cpu_to_be16(ip->i_flushiter);
 	}
+
+	if (xfs_sb_version_hasextcount_64bit(sbp)) {
+		to->di_nextents64 = cpu_to_be64(xfs_ifork_nextents(&ip->i_df));
+		to->di_nextents32 = cpu_to_be32(xfs_ifork_nextents(ip->i_afp));
+		/*
+		 * xchk_dinode() passes an uninitialized disk inode. Hence,
+		 * clear di_nextents16 field explicitly.
+		 */
+		to->di_nextents16 = cpu_to_be16(0);
+	} else {
+		to->di_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
+		to->di_nextents16 = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
+	}
 }
 
 static xfs_failaddr_t
@@ -386,14 +398,22 @@ xfs_dfork_nextents(
 	xfs_extnum_t		*nextents)
 {
 	int			error = 0;
+	bool			has_64bit_extcnt;
+
+	has_64bit_extcnt = xfs_sb_version_hasextcount_64bit(&mp->m_sb);
+
+	if (has_64bit_extcnt && dip->di_nextents16 != 0)
+		return -EFSCORRUPTED;
 
 	switch (whichfork) {
 	case XFS_DATA_FORK:
-		*nextents = be32_to_cpu(dip->di_nextents32);
+		*nextents = has_64bit_extcnt ? be64_to_cpu(dip->di_nextents64)
+			: be32_to_cpu(dip->di_nextents32);
 		break;
 
 	case XFS_ATTR_FORK:
-		*nextents = be16_to_cpu(dip->di_nextents16);
+		*nextents = has_64bit_extcnt ? be32_to_cpu(dip->di_nextents32)
+			: be16_to_cpu(dip->di_nextents16);
 		break;
 
 	default:
diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
index 1eda2163603e..ffdd2abcd73c 100644
--- a/fs/xfs/libxfs/xfs_inode_fork.h
+++ b/fs/xfs/libxfs/xfs_inode_fork.h
@@ -21,9 +21,9 @@ struct xfs_ifork {
 		void		*if_root;	/* extent tree root */
 		char		*if_data;	/* inline file data */
 	} if_u1;
+	xfs_extnum_t		if_nextents;	/* # of extents in this fork */
 	short			if_broot_bytes;	/* bytes allocated for root */
 	int8_t			if_format;	/* format of this fork */
-	xfs_extnum_t		if_nextents;	/* # of extents in this fork */
 };
 
 /*
@@ -135,10 +135,22 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp)
 
 static inline xfs_extnum_t xfs_iext_max(struct xfs_mount *mp, int whichfork)
 {
-	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK)
-		return XFS_IFORK_EXTCNT_MAXS32;
-	else
-		return XFS_IFORK_EXTCNT_MAXS16;
+	bool has_64bit_extcnt = xfs_sb_version_hasextcount_64bit(&mp->m_sb);
+
+	switch (whichfork) {
+	case XFS_DATA_FORK:
+	case XFS_COW_FORK:
+		return has_64bit_extcnt ? XFS_IFORK_EXTCNT_MAXU48
+			: XFS_IFORK_EXTCNT_MAXS32;
+
+	case XFS_ATTR_FORK:
+		return has_64bit_extcnt ? XFS_IFORK_EXTCNT_MAXU32
+			: XFS_IFORK_EXTCNT_MAXS16;
+
+	default:
+		ASSERT(0);
+		return 0;
+	}
 }
 
 struct xfs_ifork *xfs_ifork_alloc(enum xfs_dinode_fmt format,
diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
index ca8e4ad8312a..9b5d64708ed1 100644
--- a/fs/xfs/libxfs/xfs_log_format.h
+++ b/fs/xfs/libxfs/xfs_log_format.h
@@ -420,7 +420,8 @@ struct xfs_log_dinode {
 	xfs_lsn_t	di_lsn;		/* flush sequence */
 	uint64_t	di_flags2;	/* more random flags */
 	uint32_t	di_cowextsize;	/* basic cow extent size for file */
-	uint8_t		di_pad2[12];	/* more padding for future expansion */
+	uint8_t		di_pad2[4];	/* more padding for future expansion */
+	uint64_t	di_nextents64; /* higher part of data fork extent count */
 
 	/* fields only written to during inode creation */
 	xfs_log_timestamp_t di_crtime;	/* time created */
diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
index 4d773a16f886..dde6b700e891 100644
--- a/fs/xfs/scrub/inode_repair.c
+++ b/fs/xfs/scrub/inode_repair.c
@@ -736,7 +736,10 @@ xrep_dinode_zap_dfork(
 {
 	trace_xrep_dinode_zap_dfork(sc, dip);
 
-	dip->di_nextents32 = 0;
+	if (xfs_sb_version_hasextcount_64bit(&sc->mp->m_sb))
+		dip->di_nextents64 = 0;
+	else
+		dip->di_nextents32 = 0;
 
 	/* Special files always get reset to DEV */
 	switch (mode & S_IFMT) {
@@ -823,7 +826,11 @@ xrep_dinode_zap_afork(
 	trace_xrep_dinode_zap_afork(sc, dip);
 
 	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
-	dip->di_nextents16 = 0;
+
+	if (xfs_sb_version_hasextcount_64bit(&sc->mp->m_sb))
+		dip->di_nextents32 = 0;
+	else
+		dip->di_nextents16 = 0;
 
 	dip->di_forkoff = 0;
 	dip->di_mode = cpu_to_be16(mode & ~0777);
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 4070fb01350c..19d525093702 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -2511,7 +2511,7 @@ xfs_iflush(
 				ip->i_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
 		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
 			"%s: detected corrupt incore inode %llu, "
-			"total extents = %llu nblocks = %lld, ptr "PTR_FMT,
+			"total extents = %llu, nblocks = %lld, ptr "PTR_FMT,
 			__func__, ip->i_ino,
 			ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp),
 			ip->i_nblocks, ip);
diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
index f54ce7468ba1..3fa73100484b 100644
--- a/fs/xfs/xfs_inode_item.c
+++ b/fs/xfs/xfs_inode_item.c
@@ -364,6 +364,7 @@ xfs_inode_to_log_dinode(
 	struct xfs_log_dinode	*to,
 	xfs_lsn_t		lsn)
 {
+	struct xfs_sb		*sbp = &ip->i_mount->m_sb;
 	struct inode		*inode = VFS_I(ip);
 
 	to->di_magic = XFS_DINODE_MAGIC;
@@ -385,8 +386,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_nextents32 = xfs_ifork_nextents(&ip->i_df);
-	to->di_nextents16 = 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;
@@ -402,6 +401,16 @@ xfs_inode_to_log_dinode(
 		to->di_crtime = xfs_inode_to_log_dinode_ts(ip, ip->i_crtime);
 		to->di_flags2 = ip->i_diflags2;
 		to->di_cowextsize = ip->i_cowextsize;
+		if (xfs_sb_version_hasextcount_64bit(sbp)) {
+			to->di_nextents64 = xfs_ifork_nextents(&ip->i_df);
+			to->di_nextents32 = xfs_ifork_nextents(ip->i_afp);
+			to->di_nextents16 = 0;
+		} else {
+			to->di_nextents64 = 0;
+			to->di_nextents32 = xfs_ifork_nextents(&ip->i_df);
+			to->di_nextents16 = xfs_ifork_nextents(ip->i_afp);
+		}
+
 		to->di_ino = ip->i_ino;
 		to->di_lsn = lsn;
 		memset(to->di_pad2, 0, sizeof(to->di_pad2));
@@ -410,6 +419,8 @@ xfs_inode_to_log_dinode(
 	} else {
 		to->di_version = 2;
 		to->di_flushiter = ip->i_flushiter;
+		to->di_nextents32 = xfs_ifork_nextents(&ip->i_df);
+		to->di_nextents16 = xfs_ifork_nextents(ip->i_afp);
 	}
 }
 
diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
index 40af9d1265c7..fcf360c03bc1 100644
--- a/fs/xfs/xfs_inode_item_recover.c
+++ b/fs/xfs/xfs_inode_item_recover.c
@@ -166,8 +166,6 @@ xfs_log_dinode_to_disk(
 	to->di_size = cpu_to_be64(from->di_size);
 	to->di_nblocks = cpu_to_be64(from->di_nblocks);
 	to->di_extsize = cpu_to_be32(from->di_extsize);
-	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
-	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
 	to->di_forkoff = from->di_forkoff;
 	to->di_aformat = from->di_aformat;
 	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
@@ -181,12 +179,17 @@ xfs_log_dinode_to_disk(
 							  from->di_crtime);
 		to->di_flags2 = cpu_to_be64(from->di_flags2);
 		to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
+		to->di_nextents64 = cpu_to_be64(from->di_nextents64);
+		to->di_nextents32 = cpu_to_be32(from->di_nextents32);
+		to->di_nextents16 = cpu_to_be16(from->di_nextents16);
 		to->di_ino = cpu_to_be64(from->di_ino);
 		to->di_lsn = cpu_to_be64(from->di_lsn);
 		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
 		uuid_copy(&to->di_uuid, &from->di_uuid);
 		to->di_flushiter = 0;
 	} else {
+		to->di_nextents32 = cpu_to_be32(from->di_nextents32);
+		to->di_nextents16 = cpu_to_be16(from->di_nextents16);
 		to->di_flushiter = cpu_to_be16(from->di_flushiter);
 	}
 }
@@ -202,6 +205,8 @@ xlog_recover_inode_commit_pass2(
 	struct xfs_mount		*mp = log->l_mp;
 	struct xfs_buf			*bp;
 	struct xfs_dinode		*dip;
+	xfs_extnum_t                    nextents;
+	xfs_aextnum_t                   anextents;
 	int				len;
 	char				*src;
 	char				*dest;
@@ -332,16 +337,24 @@ xlog_recover_inode_commit_pass2(
 			goto out_release;
 		}
 	}
-	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
+
+	if (xfs_sb_version_hasextcount_64bit(&mp->m_sb)) {
+		nextents = ldip->di_nextents64;
+		anextents = ldip->di_nextents32;
+	} else {
+		nextents = ldip->di_nextents32;
+		anextents = ldip->di_nextents16;
+	}
+
+	if (unlikely(nextents + anextents > ldip->di_nblocks)) {
 		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
 				     XFS_ERRLEVEL_LOW, mp, ldip,
 				     sizeof(*ldip));
 		xfs_alert(mp,
 	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
-	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
+	"dino bp "PTR_FMT", ino %Ld, total extents = %llu, nblocks = %Ld",
 			__func__, item, dip, bp, in_f->ilf_ino,
-			ldip->di_nextents32 + ldip->di_nextents16,
-			ldip->di_nblocks);
+			nextents + anextents, ldip->di_nblocks);
 		error = -EFSCORRUPTED;
 		goto out_release;
 	}
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 19964b394dc4..2d44aa655f41 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1901,6 +1901,9 @@ xfs_file_ioctl(
 	case XFS_IOC_BULKSTAT_V5:
 		return xfs_ioc_bulkstat(filp, cmd, arg,
 				XFS_BULKSTAT_VERSION_V5);
+	case XFS_IOC_BULKSTAT_V6:
+		return xfs_ioc_bulkstat(filp, cmd, arg,
+				XFS_BULKSTAT_VERSION_V6);
 	case XFS_IOC_INUMBERS:
 		return xfs_ioc_inumbers(mp, cmd, arg,
 				XFS_INUMBERS_VERSION_V5);
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (10 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 11/12] xfs: Extend per-inode extent counter widths Chandan Babu R
@ 2021-07-26 11:45 ` Chandan Babu R
  2021-07-27 23:10   ` Darrick J. Wong
  2021-07-28 21:27 ` [PATCH V2 00/12] xfs: Extend per-inode extent counters Darrick J. Wong
  12 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-26 11:45 UTC (permalink / raw)
  To: linux-xfs; +Cc: Chandan Babu R, djwong

This commit adds a new error tag to allow user space tests to check if V5
bulkstat ioctl skips reporting inodes with large extent count.

Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
---
 fs/xfs/libxfs/xfs_errortag.h | 4 +++-
 fs/xfs/xfs_error.c           | 3 +++
 fs/xfs/xfs_itable.c          | 9 ++++++++-
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
index f5fa2151e05d..b2c533153737 100644
--- a/fs/xfs/libxfs/xfs_errortag.h
+++ b/fs/xfs/libxfs/xfs_errortag.h
@@ -60,7 +60,8 @@
 #define XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT		37
 #define XFS_ERRTAG_AG_RESV_FAIL				38
 #define XFS_ERRTAG_SWAPEXT_FINISH_ONE			39
-#define XFS_ERRTAG_MAX					40
+#define XFS_ERRTAG_BULKSTAT_REDUCE_MAX_IEXTENTS		40
+#define XFS_ERRTAG_MAX					41
 
 /*
  * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -105,5 +106,6 @@
 #define XFS_RANDOM_BMAP_ALLOC_MINLEN_EXTENT		1
 #define XFS_RANDOM_AG_RESV_FAIL				1
 #define XFS_RANDOM_SWAPEXT_FINISH_ONE			1
+#define XFS_RANDOM_BULKSTAT_REDUCE_MAX_IEXTENTS		1
 
 #endif /* __XFS_ERRORTAG_H_ */
diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
index e25b440cbfd3..e2a9446fb025 100644
--- a/fs/xfs/xfs_error.c
+++ b/fs/xfs/xfs_error.c
@@ -58,6 +58,7 @@ static unsigned int xfs_errortag_random_default[] = {
 	XFS_RANDOM_BMAP_ALLOC_MINLEN_EXTENT,
 	XFS_RANDOM_AG_RESV_FAIL,
 	XFS_RANDOM_SWAPEXT_FINISH_ONE,
+	XFS_RANDOM_BULKSTAT_REDUCE_MAX_IEXTENTS,
 };
 
 struct xfs_errortag_attr {
@@ -172,6 +173,7 @@ XFS_ERRORTAG_ATTR_RW(reduce_max_iextents,	XFS_ERRTAG_REDUCE_MAX_IEXTENTS);
 XFS_ERRORTAG_ATTR_RW(bmap_alloc_minlen_extent,	XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT);
 XFS_ERRORTAG_ATTR_RW(ag_resv_fail, XFS_ERRTAG_AG_RESV_FAIL);
 XFS_ERRORTAG_ATTR_RW(swapext_finish_one, XFS_RANDOM_SWAPEXT_FINISH_ONE);
+XFS_ERRORTAG_ATTR_RW(bulkstat_reduce_max_iextents, XFS_ERRTAG_BULKSTAT_REDUCE_MAX_IEXTENTS);
 
 static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(noerror),
@@ -214,6 +216,7 @@ static struct attribute *xfs_errortag_attrs[] = {
 	XFS_ERRORTAG_ATTR_LIST(bmap_alloc_minlen_extent),
 	XFS_ERRORTAG_ATTR_LIST(ag_resv_fail),
 	XFS_ERRORTAG_ATTR_LIST(swapext_finish_one),
+	XFS_ERRORTAG_ATTR_LIST(bulkstat_reduce_max_iextents),
 	NULL,
 };
 
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
index 8493870a0a87..1b252d1cda9d 100644
--- a/fs/xfs/xfs_itable.c
+++ b/fs/xfs/xfs_itable.c
@@ -20,6 +20,7 @@
 #include "xfs_icache.h"
 #include "xfs_health.h"
 #include "xfs_trans.h"
+#include "xfs_errortag.h"
 
 /*
  * Bulk Stat
@@ -143,7 +144,13 @@ xfs_bulkstat_one_int(
 
 	nextents = xfs_ifork_nextents(&ip->i_df);
 	if (bc->breq->version != XFS_BULKSTAT_VERSION_V6) {
-		if (nextents > XFS_IFORK_EXTCNT_MAXS32) {
+		xfs_extnum_t max_nextents = XFS_IFORK_EXTCNT_MAXS32;
+
+		if (unlikely(XFS_TEST_ERROR(false, mp,
+				XFS_ERRTAG_BULKSTAT_REDUCE_MAX_IEXTENTS)))
+			max_nextents = 10;
+
+		if (nextents > max_nextents) {
 			xfs_iunlock(ip, XFS_ILOCK_SHARED);
 			xfs_irele(ip);
 			error = -EINVAL;
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h
  2021-07-26 11:45 ` [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h Chandan Babu R
@ 2021-07-26 18:00   ` Darrick J. Wong
  2021-07-27  8:07     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-26 18:00 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:30PM +0530, Chandan Babu R wrote:
> Maximum values associated with extent counters i.e. Maximum extent length,
> Maximum data extents and Maximum xattr extents are dictated by the on-disk
> format. Hence move these definitions over to xfs_format.h.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_format.h | 7 +++++++
>  fs/xfs/libxfs/xfs_types.h  | 7 -------
>  2 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 8cd48a651b96..37cca918d2ba 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1109,6 +1109,13 @@ enum xfs_dinode_fmt {
>  	{ XFS_DINODE_FMT_BTREE,		"btree" }, \
>  	{ XFS_DINODE_FMT_UUID,		"uuid" }
>  
> +/*
> + * Max values for extlen, extnum, aextnum.
> + */
> +#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */
> +#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
> +#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */

Why do the cast types change here?  This is a simple hoist, right?

--D

> +
>  /*
>   * Inode minimum and maximum sizes.
>   */
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 5c0cc806068b..8908346b1deb 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -56,13 +56,6 @@ typedef void *		xfs_failaddr_t;
>  #define	NULLFSINO	((xfs_ino_t)-1)
>  #define	NULLAGINO	((xfs_agino_t)-1)
>  
> -/*
> - * Max values for extlen, extnum, aextnum.
> - */
> -#define	MAXEXTLEN	((xfs_extlen_t)0x001fffff)	/* 21 bits */
> -#define	MAXEXTNUM	((xfs_extnum_t)0x7fffffff)	/* signed int */
> -#define	MAXAEXTNUM	((xfs_aextnum_t)0x7fff)		/* signed short */
> -
>  /*
>   * Minimum and maximum blocksize and sectorsize.
>   * The blocksize upper limit is pretty much arbitrary.
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h
  2021-07-26 18:00   ` Darrick J. Wong
@ 2021-07-27  8:07     ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-27  8:07 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 26 Jul 2021 at 23:30, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:30PM +0530, Chandan Babu R wrote:
>> Maximum values associated with extent counters i.e. Maximum extent length,
>> Maximum data extents and Maximum xattr extents are dictated by the on-disk
>> format. Hence move these definitions over to xfs_format.h.
>>
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> ---
>>  fs/xfs/libxfs/xfs_format.h | 7 +++++++
>>  fs/xfs/libxfs/xfs_types.h  | 7 -------
>>  2 files changed, 7 insertions(+), 7 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 8cd48a651b96..37cca918d2ba 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -1109,6 +1109,13 @@ enum xfs_dinode_fmt {
>>  	{ XFS_DINODE_FMT_BTREE,		"btree" }, \
>>  	{ XFS_DINODE_FMT_UUID,		"uuid" }
>>
>> +/*
>> + * Max values for extlen, extnum, aextnum.
>> + */
>> +#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */
>> +#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
>> +#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */
>
> Why do the cast types change here?  This is a simple hoist, right?

Sorry, I will restore the casts to how it was earlier. I don't remember the
exact reason for changing them. I thought I had seen some compilation
issues. But after restoring them, I see that the code compiles fine.

--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-07-26 11:45 ` [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16 Chandan Babu R
@ 2021-07-27 21:56   ` Darrick J. Wong
  2021-07-27 22:03     ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 21:56 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:31PM +0530, Chandan Babu R wrote:
> In preparation for introducing larger extent count limits, this commit renames
> existing extent count limits based on their signedness and width.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
>  fs/xfs/libxfs/xfs_format.h     | 8 ++++----
>  fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
>  fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
>  fs/xfs/scrub/inode_repair.c    | 2 +-
>  5 files changed, 11 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index f3c9a0ebb0a5..8f262405a5b5 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
>  	 * available.
>  	 */
>  	if (whichfork == XFS_DATA_FORK) {
> -		maxleafents = MAXEXTNUM;
> +		maxleafents = XFS_IFORK_EXTCNT_MAXS32;

I'm not in love with these names, since they tell me roughly about the
size of the constant (which I could glean from the definition) but less
about when I would expect to find them.  How about:

#define XFS_MAX_DFORK_NEXTENTS    ((xfs_extnum_t) 0x7FFFFFFF)
#define XFS_MAX_AFORK_NEXTENTS    ((xfs_aextnum_t)0x00007FFF)

and when we get to the iext64 feature (or whatever we end up calling it)
then we can define new ones:

#define XFS_MAX_DFORK_NEXTENTS64  ((xfs_extnum_t) 0xFFFFFFFFFFFF)
#define XFS_MAX_AFORK_NEXTENTS64  ((xfs_aextnum_t)0x0000FFFFFFFF)

or something like that.

>  		sz = xfs_bmdr_space_calc(MINDBTPTRS);
>  	} else {
> -		maxleafents = MAXAEXTNUM;
> +		maxleafents = XFS_IFORK_EXTCNT_MAXS16;
>  		sz = xfs_bmdr_space_calc(MINABTPTRS);
>  	}
>  	maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 37cca918d2ba..920e3f9c418f 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1110,11 +1110,11 @@ enum xfs_dinode_fmt {
>  	{ XFS_DINODE_FMT_UUID,		"uuid" }
>  
>  /*
> - * Max values for extlen, extnum, aextnum.
> + * Max values for extlen and disk inode's extent counters.
>   */
> -#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */

As for MAXEXTLEN... would you mind tacking a new patch on the end to fix
its definition as well?  It /really/ ought to be based on the disk
format definitions and not open-coded.

#define XFS_MAX_EXTLEN		((xfs_extlen_t)(1 << BMBT_BLOCKCOUNT_BITLEN) - 1)

--D

> -#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
> -#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */
> +#define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
> +#define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
> +#define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
>  
>  /*
>   * Inode minimum and maximum sizes.
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 5625df1ddd95..66d13e8fa420 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -365,9 +365,9 @@ xfs_dinode_verify_fork(
>  		break;
>  	case XFS_DINODE_FMT_BTREE:
>  		if (whichfork == XFS_ATTR_FORK) {
> -			if (di_nextents > MAXAEXTNUM)
> +			if (di_nextents > XFS_IFORK_EXTCNT_MAXS16)
>  				return __this_address;
> -		} else if (di_nextents > MAXEXTNUM) {
> +		} else if (di_nextents > XFS_IFORK_EXTCNT_MAXS32) {
>  			return __this_address;
>  		}
>  		break;
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index 801a6f7dbd0c..6f4b14d3d381 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -736,7 +736,8 @@ xfs_iext_count_may_overflow(
>  	if (whichfork == XFS_COW_FORK)
>  		return 0;
>  
> -	max_exts = (whichfork == XFS_ATTR_FORK) ? MAXAEXTNUM : MAXEXTNUM;
> +	max_exts = (whichfork == XFS_ATTR_FORK) ?
> +		XFS_IFORK_EXTCNT_MAXS16 : XFS_IFORK_EXTCNT_MAXS32;
>  
>  	if (XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
>  		max_exts = 10;
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index a80cd633fe59..c44f8d06939b 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c
> @@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
>  			return error;
>  		if (count >= sc->mp->m_sb.sb_dblocks)
>  			return -EFSCORRUPTED;
> -		if (nextents >= MAXAEXTNUM)
> +		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
>  			return -EFSCORRUPTED;
>  		ifp->if_nextents = nextents;
>  	} else {
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper
  2021-07-26 11:45 ` [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper Chandan Babu R
@ 2021-07-27 21:58   ` Darrick J. Wong
  2021-07-28  3:17     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 21:58 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:32PM +0530, Chandan Babu R wrote:
> xfs_iext_max() returns the maximum number of extents possible for one of
> data, cow or attribute fork. This helper will be extended further in a
> future commit when maximum extent counts associated with data/attribute
> forks are increased.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_bmap.c       | 9 ++++-----
>  fs/xfs/libxfs/xfs_inode_buf.c  | 8 +++-----
>  fs/xfs/libxfs/xfs_inode_fork.c | 6 +++---
>  fs/xfs/libxfs/xfs_inode_fork.h | 8 ++++++++
>  fs/xfs/scrub/inode_repair.c    | 2 +-
>  5 files changed, 19 insertions(+), 14 deletions(-)
> 

<snip>

> diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
> index cf82be263b48..1eda2163603e 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.h
> +++ b/fs/xfs/libxfs/xfs_inode_fork.h
> @@ -133,6 +133,14 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp)
>  	return ifp->if_format;
>  }
>  
> +static inline xfs_extnum_t xfs_iext_max(struct xfs_mount *mp, int whichfork)

xfs_iext_max_nextents() to go with the constants?  "max" on its own is a
little vague.  I /really/ like this getting cleaned up finally though.

> +{
> +	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK)
> +		return XFS_IFORK_EXTCNT_MAXS32;
> +	else
> +		return XFS_IFORK_EXTCNT_MAXS16;

No need for the 'else'.

--D

> +}
> +
>  struct xfs_ifork *xfs_ifork_alloc(enum xfs_dinode_fmt format,
>  				xfs_extnum_t nextents);
>  struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state);
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index c44f8d06939b..a44d7b48c374 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c
> @@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
>  			return error;
>  		if (count >= sc->mp->m_sb.sb_dblocks)
>  			return -EFSCORRUPTED;
> -		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
> +		if (nextents >= xfs_iext_max(sc->mp, XFS_ATTR_FORK))
>  			return -EFSCORRUPTED;
>  		ifp->if_nextents = nextents;
>  	} else {
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types
  2021-07-26 11:45 ` [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types Chandan Babu R
@ 2021-07-27 21:59   ` Darrick J. Wong
  2021-07-28  3:38     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 21:59 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:33PM +0530, Chandan Babu R wrote:
> xfs_extnum_t is the type to use to declare variables which have values
> obtained from xfs_dinode->di_[a]nextents. This commit replaces basic
> types (e.g. uint32_t) with xfs_extnum_t for such variables.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>

Not sure why the structure members change places, but otherwise LGTM.

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D


> ---
>  fs/xfs/libxfs/xfs_bmap.c       | 2 +-
>  fs/xfs/libxfs/xfs_inode_buf.c  | 2 +-
>  fs/xfs/libxfs/xfs_inode_fork.c | 2 +-
>  fs/xfs/scrub/inode.c           | 2 +-
>  fs/xfs/scrub/inode_repair.c    | 2 +-
>  fs/xfs/xfs_trace.h             | 2 +-
>  6 files changed, 6 insertions(+), 6 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index 282aeb3c0e49..e5d243fd187d 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -53,9 +53,9 @@ xfs_bmap_compute_maxlevels(
>  	xfs_mount_t	*mp,		/* file system mount structure */
>  	int		whichfork)	/* data or attr fork */
>  {
> +	xfs_extnum_t	maxleafents;	/* max leaf entries possible */
>  	int		level;		/* btree level */
>  	uint		maxblocks;	/* max blocks at this level */
> -	uint		maxleafents;	/* max leaf entries possible */
>  	int		maxrootrecs;	/* max records in root block */
>  	int		minleafrecs;	/* min records in leaf block */
>  	int		minnoderecs;	/* min records in node block */
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 419b92dc6ac8..cba9a38f3270 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -342,7 +342,7 @@ xfs_dinode_verify_fork(
>  	struct xfs_mount	*mp,
>  	int			whichfork)
>  {
> -	uint32_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
> +	xfs_extnum_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
>  	xfs_extnum_t		max_extents;
>  
>  	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index c6856ec95335..a1e40df585a3 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -107,7 +107,7 @@ xfs_iformat_extents(
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	int			state = xfs_bmap_fork_to_state(whichfork);
> -	int			nex = XFS_DFORK_NEXTENTS(dip, whichfork);
> +	xfs_extnum_t		nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>  	int			size = nex * sizeof(xfs_bmbt_rec_t);
>  	struct xfs_iext_cursor	icur;
>  	struct xfs_bmbt_rec	*dp;
> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
> index e6068590484b..246d11ca133f 100644
> --- a/fs/xfs/scrub/inode.c
> +++ b/fs/xfs/scrub/inode.c
> @@ -219,7 +219,7 @@ xchk_dinode(
>  	size_t			fork_recs;
>  	unsigned long long	isize;
>  	uint64_t		flags2;
> -	uint32_t		nextents;
> +	xfs_extnum_t		nextents;
>  	prid_t			prid;
>  	uint16_t		flags;
>  	uint16_t		mode;
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index a44d7b48c374..042c7d0bc0f5 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c
> @@ -597,9 +597,9 @@ xrep_dinode_bad_extents_fork(
>  {
>  	struct xfs_bmbt_irec	new;
>  	struct xfs_bmbt_rec	*dp;
> +	xfs_extnum_t		nex;
>  	bool			isrt;
>  	int			i;
> -	int			nex;
>  	int			fork_size;
>  
>  	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index affc9b5834fb..5ed11f894f79 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -2338,7 +2338,7 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
>  		__field(int, which)
>  		__field(xfs_ino_t, ino)
>  		__field(int, format)
> -		__field(int, nex)
> +		__field(xfs_extnum_t, nex)
>  		__field(int, broot_size)
>  		__field(int, fork_off)
>  	),
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-07-27 21:56   ` Darrick J. Wong
@ 2021-07-27 22:03     ` Darrick J. Wong
  2021-07-28  3:15       ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 22:03 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Tue, Jul 27, 2021 at 02:56:11PM -0700, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:31PM +0530, Chandan Babu R wrote:
> > In preparation for introducing larger extent count limits, this commit renames
> > existing extent count limits based on their signedness and width.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
> >  fs/xfs/libxfs/xfs_format.h     | 8 ++++----
> >  fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
> >  fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
> >  fs/xfs/scrub/inode_repair.c    | 2 +-
> >  5 files changed, 11 insertions(+), 10 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> > index f3c9a0ebb0a5..8f262405a5b5 100644
> > --- a/fs/xfs/libxfs/xfs_bmap.c
> > +++ b/fs/xfs/libxfs/xfs_bmap.c
> > @@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
> >  	 * available.
> >  	 */
> >  	if (whichfork == XFS_DATA_FORK) {
> > -		maxleafents = MAXEXTNUM;
> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
> 
> I'm not in love with these names, since they tell me roughly about the
> size of the constant (which I could glean from the definition) but less
> about when I would expect to find them.  How about:
> 
> #define XFS_MAX_DFORK_NEXTENTS    ((xfs_extnum_t) 0x7FFFFFFF)
> #define XFS_MAX_AFORK_NEXTENTS    ((xfs_aextnum_t)0x00007FFF)

Or, given that 'DFORK' already means 'ondisk fork', how about:

XFS_MAX_DATA_NEXTENTS
XFS_MAX_ATTR_NEXTENTS

?

--D

> 
> and when we get to the iext64 feature (or whatever we end up calling it)
> then we can define new ones:
> 
> #define XFS_MAX_DFORK_NEXTENTS64  ((xfs_extnum_t) 0xFFFFFFFFFFFF)
> #define XFS_MAX_AFORK_NEXTENTS64  ((xfs_aextnum_t)0x0000FFFFFFFF)
> 
> or something like that.
> 
> >  		sz = xfs_bmdr_space_calc(MINDBTPTRS);
> >  	} else {
> > -		maxleafents = MAXAEXTNUM;
> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS16;
> >  		sz = xfs_bmdr_space_calc(MINABTPTRS);
> >  	}
> >  	maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
> > diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> > index 37cca918d2ba..920e3f9c418f 100644
> > --- a/fs/xfs/libxfs/xfs_format.h
> > +++ b/fs/xfs/libxfs/xfs_format.h
> > @@ -1110,11 +1110,11 @@ enum xfs_dinode_fmt {
> >  	{ XFS_DINODE_FMT_UUID,		"uuid" }
> >  
> >  /*
> > - * Max values for extlen, extnum, aextnum.
> > + * Max values for extlen and disk inode's extent counters.
> >   */
> > -#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */
> 
> As for MAXEXTLEN... would you mind tacking a new patch on the end to fix
> its definition as well?  It /really/ ought to be based on the disk
> format definitions and not open-coded.
> 
> #define XFS_MAX_EXTLEN		((xfs_extlen_t)(1 << BMBT_BLOCKCOUNT_BITLEN) - 1)
> 
> --D
> 
> > -#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
> > -#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */
> > +#define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
> > +#define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
> > +#define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
> >  
> >  /*
> >   * Inode minimum and maximum sizes.
> > diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> > index 5625df1ddd95..66d13e8fa420 100644
> > --- a/fs/xfs/libxfs/xfs_inode_buf.c
> > +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> > @@ -365,9 +365,9 @@ xfs_dinode_verify_fork(
> >  		break;
> >  	case XFS_DINODE_FMT_BTREE:
> >  		if (whichfork == XFS_ATTR_FORK) {
> > -			if (di_nextents > MAXAEXTNUM)
> > +			if (di_nextents > XFS_IFORK_EXTCNT_MAXS16)
> >  				return __this_address;
> > -		} else if (di_nextents > MAXEXTNUM) {
> > +		} else if (di_nextents > XFS_IFORK_EXTCNT_MAXS32) {
> >  			return __this_address;
> >  		}
> >  		break;
> > diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> > index 801a6f7dbd0c..6f4b14d3d381 100644
> > --- a/fs/xfs/libxfs/xfs_inode_fork.c
> > +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> > @@ -736,7 +736,8 @@ xfs_iext_count_may_overflow(
> >  	if (whichfork == XFS_COW_FORK)
> >  		return 0;
> >  
> > -	max_exts = (whichfork == XFS_ATTR_FORK) ? MAXAEXTNUM : MAXEXTNUM;
> > +	max_exts = (whichfork == XFS_ATTR_FORK) ?
> > +		XFS_IFORK_EXTCNT_MAXS16 : XFS_IFORK_EXTCNT_MAXS32;
> >  
> >  	if (XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
> >  		max_exts = 10;
> > diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> > index a80cd633fe59..c44f8d06939b 100644
> > --- a/fs/xfs/scrub/inode_repair.c
> > +++ b/fs/xfs/scrub/inode_repair.c
> > @@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
> >  			return error;
> >  		if (count >= sc->mp->m_sb.sb_dblocks)
> >  			return -EFSCORRUPTED;
> > -		if (nextents >= MAXAEXTNUM)
> > +		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
> >  			return -EFSCORRUPTED;
> >  		ifp->if_nextents = nextents;
> >  	} else {
> > -- 
> > 2.30.2
> > 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper
  2021-07-26 11:45 ` [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper Chandan Babu R
@ 2021-07-27 22:10   ` Darrick J. Wong
  2021-07-28  4:06     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 22:10 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:34PM +0530, Chandan Babu R wrote:
> This commit replaces the macro XFS_DFORK_NEXTENTS() with the helper function
> xfs_dfork_nextents(). As of this commit, xfs_dfork_nextents() returns the same
> value as XFS_DFORK_NEXTENTS(). A future commit which extends inode's extent

Yay fewer shouty macros!

> counter fields will add more logic to this helper.
> 
> This commit also replaces direct accesses to xfs_dinode->di_[a]nextents
> with calls to xfs_dfork_nextents().
> 
> No functional changes have been made.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_format.h     |  4 ----
>  fs/xfs/libxfs/xfs_inode_buf.c  | 41 +++++++++++++++++++++++++++++-----
>  fs/xfs/libxfs/xfs_inode_buf.h  |  2 ++
>  fs/xfs/libxfs/xfs_inode_fork.c | 12 ++++++----
>  fs/xfs/scrub/inode.c           | 19 +++++++++-------
>  fs/xfs/scrub/inode_repair.c    | 38 +++++++++++++++++++------------
>  6 files changed, 81 insertions(+), 35 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 920e3f9c418f..001a4077a7c6 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1166,10 +1166,6 @@ enum xfs_dinode_fmt {
>  	((w) == XFS_DATA_FORK ? \
>  		(dip)->di_format : \
>  		(dip)->di_aformat)
> -#define XFS_DFORK_NEXTENTS(dip,w) \
> -	((w) == XFS_DATA_FORK ? \
> -		be32_to_cpu((dip)->di_nextents) : \
> -		be16_to_cpu((dip)->di_anextents))
>  
>  /*
>   * For block and character special files the 32bit dev_t is stored at the
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index cba9a38f3270..6bef0757fca4 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -342,9 +342,11 @@ xfs_dinode_verify_fork(
>  	struct xfs_mount	*mp,
>  	int			whichfork)
>  {
> -	xfs_extnum_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
> +	xfs_extnum_t		di_nextents;
>  	xfs_extnum_t		max_extents;
>  
> +	di_nextents = xfs_dfork_nextents(mp, dip, whichfork);
> +
>  	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
>  	case XFS_DINODE_FMT_LOCAL:
>  		/*
> @@ -375,6 +377,31 @@ xfs_dinode_verify_fork(
>  	return NULL;
>  }
>  
> +xfs_extnum_t
> +xfs_dfork_nextents(
> +	struct xfs_mount	*mp,
> +	struct xfs_dinode	*dip,
> +	int			whichfork)
> +{
> +	xfs_extnum_t		nextents = 0;
> +
> +	switch (whichfork) {
> +	case XFS_DATA_FORK:
> +		nextents = be32_to_cpu(dip->di_nextents);
> +		break;
> +
> +	case XFS_ATTR_FORK:
> +		nextents = be16_to_cpu(dip->di_anextents);
> +		break;
> +
> +	default:
> +		ASSERT(0);
> +		break;
> +	}
> +
> +	return nextents;
> +}

This could be a static inline function taking the place of
XFS_DFORK_NEXTENTS instead of another new function with a stack frame,
etc:

static inline xfs_extnum_t
xfs_dfork_nextents(
	struct xfs_mount	*mp,
	struct xfs_dinode	*dip,
	int			whichfork)
{
	switch (whichfork) {
	case XFS_DATA_FORK:
		return be32_to_cpu(dip->di_nextents);
	case XFS_ATTR_FORK:
		return be16_to_cpu(dip->di_anextents);
	default:
		ASSERT(0);
		return 0;
	}
}

> +
>  static xfs_failaddr_t
>  xfs_dinode_verify_forkoff(
>  	struct xfs_dinode	*dip,
> @@ -474,6 +501,8 @@ xfs_dinode_verify(
>  	uint16_t		flags;
>  	uint64_t		flags2;
>  	uint64_t		di_size;
> +	xfs_extnum_t            nextents;
> +	int64_t			nblocks;

xfs_rfsblock_t, since that's the type we use for nblocks in xfs_inode.

>  
>  	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
>  		return __this_address;
> @@ -504,10 +533,12 @@ xfs_dinode_verify(
>  	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
>  		return __this_address;
>  
> +	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
> +	nextents += xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
> +	nblocks = be64_to_cpu(dip->di_nblocks);
> +
>  	/* Fork checks carried over from xfs_iformat_fork */
> -	if (mode &&
> -	    be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) >
> -			be64_to_cpu(dip->di_nblocks))
> +	if (mode && nextents > nblocks)
>  		return __this_address;
>  
>  	if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize)
> @@ -564,7 +595,7 @@ xfs_dinode_verify(
>  		default:
>  			return __this_address;
>  		}
> -		if (dip->di_anextents)
> +		if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
>  			return __this_address;
>  	}
>  
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
> index a30b7676098a..ea2c35091609 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.h
> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
> @@ -36,6 +36,8 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
>  xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
>  		uint32_t cowextsize, uint16_t mode, uint16_t flags,
>  		uint64_t flags2);
> +xfs_extnum_t xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
> +		int whichfork);
>  
>  static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
>  {
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index a1e40df585a3..38dd2dfc31fa 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -107,7 +107,7 @@ xfs_iformat_extents(
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	int			state = xfs_bmap_fork_to_state(whichfork);
> -	xfs_extnum_t		nex = XFS_DFORK_NEXTENTS(dip, whichfork);
> +	xfs_extnum_t		nex = xfs_dfork_nextents(mp, dip, whichfork);
>  	int			size = nex * sizeof(xfs_bmbt_rec_t);
>  	struct xfs_iext_cursor	icur;
>  	struct xfs_bmbt_rec	*dp;
> @@ -226,6 +226,7 @@ xfs_iformat_data_fork(
>  	struct xfs_inode	*ip,
>  	struct xfs_dinode	*dip)
>  {
> +	struct xfs_mount	*mp = ip->i_mount;
>  	struct inode		*inode = VFS_I(ip);
>  	int			error;
>  
> @@ -234,7 +235,7 @@ xfs_iformat_data_fork(
>  	 * depend on it.
>  	 */
>  	ip->i_df.if_format = dip->di_format;
> -	ip->i_df.if_nextents = be32_to_cpu(dip->di_nextents);
> +	ip->i_df.if_nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>  
>  	switch (inode->i_mode & S_IFMT) {
>  	case S_IFIFO:
> @@ -301,14 +302,17 @@ xfs_iformat_attr_fork(
>  	struct xfs_inode	*ip,
>  	struct xfs_dinode	*dip)
>  {
> +	struct xfs_mount	*mp = ip->i_mount;
> +	xfs_extnum_t		nextents;

naextents for consistency?

>  	int			error = 0;
>  
> +	nextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
> +
>  	/*
>  	 * Initialize the extent count early, as the per-format routines may
>  	 * depend on it.
>  	 */
> -	ip->i_afp = xfs_ifork_alloc(dip->di_aformat,
> -				be16_to_cpu(dip->di_anextents));
> +	ip->i_afp = xfs_ifork_alloc(dip->di_aformat, nextents);
>  
>  	switch (ip->i_afp->if_format) {
>  	case XFS_DINODE_FMT_LOCAL:
> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
> index 246d11ca133f..a161dac31a6f 100644
> --- a/fs/xfs/scrub/inode.c
> +++ b/fs/xfs/scrub/inode.c
> @@ -220,6 +220,7 @@ xchk_dinode(
>  	unsigned long long	isize;
>  	uint64_t		flags2;
>  	xfs_extnum_t		nextents;
> +	xfs_extnum_t		naextents;
>  	prid_t			prid;
>  	uint16_t		flags;
>  	uint16_t		mode;
> @@ -378,7 +379,7 @@ xchk_dinode(
>  	xchk_inode_extsize(sc, dip, ino, mode, flags);
>  
>  	/* di_nextents */
> -	nextents = be32_to_cpu(dip->di_nextents);
> +	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>  	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
>  	switch (dip->di_format) {
>  	case XFS_DINODE_FMT_EXTENTS:
> @@ -395,10 +396,12 @@ xchk_dinode(
>  		break;
>  	}
>  
> +	naextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
> +
>  	/* di_forkoff */
>  	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
>  		xchk_ino_set_corrupt(sc, ino);
> -	if (dip->di_anextents != 0 && dip->di_forkoff == 0)
> +	if (naextents != 0 && dip->di_forkoff == 0)
>  		xchk_ino_set_corrupt(sc, ino);
>  	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
>  		xchk_ino_set_corrupt(sc, ino);
> @@ -410,19 +413,18 @@ xchk_dinode(
>  		xchk_ino_set_corrupt(sc, ino);
>  
>  	/* di_anextents */
> -	nextents = be16_to_cpu(dip->di_anextents);
>  	fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
>  	switch (dip->di_aformat) {
>  	case XFS_DINODE_FMT_EXTENTS:
> -		if (nextents > fork_recs)
> +		if (naextents > fork_recs)
>  			xchk_ino_set_corrupt(sc, ino);
>  		break;
>  	case XFS_DINODE_FMT_BTREE:
> -		if (nextents <= fork_recs)
> +		if (naextents <= fork_recs)
>  			xchk_ino_set_corrupt(sc, ino);
>  		break;
>  	default:
> -		if (nextents != 0)
> +		if (naextents != 0)
>  			xchk_ino_set_corrupt(sc, ino);
>  	}
>  
> @@ -487,6 +489,7 @@ xchk_inode_xref_bmap(
>  	struct xfs_scrub	*sc,
>  	struct xfs_dinode	*dip)
>  {
> +	struct xfs_mount	*mp = sc->mp;
>  	xfs_extnum_t		nextents;
>  	xfs_filblks_t		count;
>  	xfs_filblks_t		acount;
> @@ -500,14 +503,14 @@ xchk_inode_xref_bmap(
>  			&nextents, &count);
>  	if (!xchk_should_check_xref(sc, &error, NULL))
>  		return;
> -	if (nextents < be32_to_cpu(dip->di_nextents))
> +	if (nextents < xfs_dfork_nextents(mp, dip, XFS_DATA_FORK))
>  		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
>  
>  	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
>  			&nextents, &acount);
>  	if (!xchk_should_check_xref(sc, &error, NULL))
>  		return;
> -	if (nextents != be16_to_cpu(dip->di_anextents))
> +	if (nextents != xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
>  		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
>  
>  	/* Check nblocks against the inode. */
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index 042c7d0bc0f5..bdb4685923c0 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c

Hey waitaminute, is this based off of djwong-dev??

> @@ -602,7 +602,7 @@ xrep_dinode_bad_extents_fork(
>  	int			i;
>  	int			fork_size;
>  
> -	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
> +	nex = xfs_dfork_nextents(sc->mp, dip, whichfork);
>  	fork_size = nex * sizeof(struct xfs_bmbt_rec);
>  	if (fork_size < 0 || fork_size > dfork_size)
>  		return true;
> @@ -636,7 +636,7 @@ xrep_dinode_bad_btree_fork(
>  	int			nrecs;
>  	int			level;
>  
> -	if (XFS_DFORK_NEXTENTS(dip, whichfork) <=
> +	if (xfs_dfork_nextents(sc->mp, dip, whichfork) <=
>  			dfork_size / sizeof(struct xfs_bmbt_rec))
>  		return true;
>  
> @@ -831,12 +831,16 @@ xrep_dinode_ensure_forkoff(
>  	struct xrep_dinode_stats	*dis)
>  {
>  	struct xfs_bmdr_block		*bmdr;
> +	xfs_extnum_t			anextents, dnextents;
>  	size_t				bmdr_minsz = xfs_bmdr_space_calc(1);
>  	unsigned int			lit_sz = XFS_LITINO(sc->mp);
>  	unsigned int			afork_min, dfork_min;
>  
>  	trace_xrep_dinode_ensure_forkoff(sc, dip);
>  
> +	dnextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
> +	anextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
> +
>  	/*
>  	 * Before calling this function, xrep_dinode_core ensured that both
>  	 * forks actually fit inside their respective literal areas.  If this
> @@ -857,15 +861,14 @@ xrep_dinode_ensure_forkoff(
>  		afork_min = XFS_DFORK_SIZE(dip, sc->mp, XFS_ATTR_FORK);
>  		break;
>  	case XFS_DINODE_FMT_EXTENTS:
> -		if (dip->di_anextents) {
> +		if (anextents) {
>  			/*
>  			 * We must maintain sufficient space to hold the entire
>  			 * extent map array in the data fork.  Note that we
>  			 * previously zapped the fork if it had no chance of
>  			 * fitting in the inode.
>  			 */
> -			afork_min = sizeof(struct xfs_bmbt_rec) *
> -						be16_to_cpu(dip->di_anextents);
> +			afork_min = sizeof(struct xfs_bmbt_rec) * anextents;
>  		} else if (dis->attr_extents > 0) {
>  			/*
>  			 * The attr fork thinks it has zero extents, but we
> @@ -908,15 +911,14 @@ xrep_dinode_ensure_forkoff(
>  		dfork_min = be64_to_cpu(dip->di_size);
>  		break;
>  	case XFS_DINODE_FMT_EXTENTS:
> -		if (dip->di_nextents) {
> +		if (dnextents) {
>  			/*
>  			 * We must maintain sufficient space to hold the entire
>  			 * extent map array in the data fork.  Note that we
>  			 * previously zapped the fork if it had no chance of
>  			 * fitting in the inode.
>  			 */
> -			dfork_min = sizeof(struct xfs_bmbt_rec) *
> -						be32_to_cpu(dip->di_nextents);
> +			dfork_min = sizeof(struct xfs_bmbt_rec) * dnextents;
>  		} else if (dis->data_extents > 0 || dis->rt_extents > 0) {
>  			/*
>  			 * The data fork thinks it has zero extents, but we
> @@ -956,7 +958,7 @@ xrep_dinode_ensure_forkoff(
>  	 * recovery fork, move the attr fork up.
>  	 */
>  	if (dip->di_format == XFS_DINODE_FMT_EXTENTS &&
> -	    dip->di_nextents == 0 &&
> +	    dnextents == 0 &&
>  	    (dis->data_extents > 0 || dis->rt_extents > 0) &&
>  	    bmdr_minsz > XFS_DFORK_DSIZE(dip, sc->mp)) {
>  		if (bmdr_minsz + afork_min > lit_sz) {
> @@ -982,7 +984,7 @@ xrep_dinode_ensure_forkoff(
>  	 * recovery fork, move the attr fork down.
>  	 */
>  	if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
> -	    dip->di_anextents == 0 &&
> +	    anextents == 0 &&
>  	    dis->attr_extents > 0 &&
>  	    bmdr_minsz > XFS_DFORK_ASIZE(dip, sc->mp)) {
>  		if (dip->di_format == XFS_DINODE_FMT_BTREE) {
> @@ -1019,6 +1021,9 @@ xrep_dinode_zap_forks(
>  	struct xfs_dinode		*dip,
>  	struct xrep_dinode_stats	*dis)
>  {
> +	uint64_t			nblocks;

xfs_rfsblock_t.

--D

> +	xfs_extnum_t			nextents;
> +	xfs_extnum_t			naextents;
>  	uint16_t			mode;
>  	bool				zap_datafork = false;
>  	bool				zap_attrfork = false;
> @@ -1028,12 +1033,17 @@ xrep_dinode_zap_forks(
>  	mode = be16_to_cpu(dip->di_mode);
>  
>  	/* Inode counters don't make sense? */
> -	if (be32_to_cpu(dip->di_nextents) > be64_to_cpu(dip->di_nblocks))
> +	nblocks = be64_to_cpu(dip->di_nblocks);
> +
> +	nextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
> +	if (nextents > nblocks)
>  		zap_datafork = true;
> -	if (be16_to_cpu(dip->di_anextents) > be64_to_cpu(dip->di_nblocks))
> +
> +	naextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
> +	if (naextents > nblocks)
>  		zap_attrfork = true;
> -	if (be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) >
> -			be64_to_cpu(dip->di_nblocks))
> +
> +	if (nextents + naextents > nblocks)
>  		zap_datafork = zap_attrfork = true;
>  
>  	if (!zap_datafork)
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument
  2021-07-26 11:45 ` [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument Chandan Babu R
@ 2021-07-27 22:22   ` Darrick J. Wong
  2021-07-28  4:21     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 22:22 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:35PM +0530, Chandan Babu R wrote:
> This commit changes xfs_dfork_nextents() to return an error code. The extent
> count itself is now returned through an out argument. This facility will be
> used by a future commit to indicate an inconsistent ondisk extent count.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_inode_buf.c  | 29 +++++++----
>  fs/xfs/libxfs/xfs_inode_buf.h  |  4 +-
>  fs/xfs/libxfs/xfs_inode_fork.c | 22 ++++++--
>  fs/xfs/scrub/inode.c           | 94 +++++++++++++++++++++-------------
>  fs/xfs/scrub/inode_repair.c    | 34 ++++++++----
>  5 files changed, 119 insertions(+), 64 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 6bef0757fca4..9ed04da2e2b1 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -345,7 +345,8 @@ xfs_dinode_verify_fork(
>  	xfs_extnum_t		di_nextents;
>  	xfs_extnum_t		max_extents;
>  
> -	di_nextents = xfs_dfork_nextents(mp, dip, whichfork);
> +	if (xfs_dfork_nextents(mp, dip, whichfork, &di_nextents))
> +		return __this_address;
>  
>  	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
>  	case XFS_DINODE_FMT_LOCAL:
> @@ -377,29 +378,31 @@ xfs_dinode_verify_fork(
>  	return NULL;
>  }
>  
> -xfs_extnum_t
> +int
>  xfs_dfork_nextents(
>  	struct xfs_mount	*mp,
>  	struct xfs_dinode	*dip,
> -	int			whichfork)
> +	int			whichfork,
> +	xfs_extnum_t		*nextents)
>  {
> -	xfs_extnum_t		nextents = 0;
> +	int			error = 0;
>  
>  	switch (whichfork) {
>  	case XFS_DATA_FORK:
> -		nextents = be32_to_cpu(dip->di_nextents);
> +		*nextents = be32_to_cpu(dip->di_nextents);
>  		break;
>  
>  	case XFS_ATTR_FORK:
> -		nextents = be16_to_cpu(dip->di_anextents);
> +		*nextents = be16_to_cpu(dip->di_anextents);
>  		break;
>  
>  	default:
>  		ASSERT(0);
> +		error = -EINVAL;

-EFSCORRUPTED?  We don't have a specific code for "your darn software
screwed up, hyuck!!" but I guess this will at least get peoples'
attention.

>  		break;
>  	}
>  
> -	return nextents;
> +	return error;
>  }
>  
>  static xfs_failaddr_t
> @@ -502,6 +505,7 @@ xfs_dinode_verify(
>  	uint64_t		flags2;
>  	uint64_t		di_size;
>  	xfs_extnum_t            nextents;
> +	xfs_extnum_t            naextents;
>  	int64_t			nblocks;
>  
>  	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
> @@ -533,8 +537,13 @@ xfs_dinode_verify(
>  	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
>  		return __this_address;
>  
> -	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
> -	nextents += xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
> +	if (xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents))
> +		return __this_address;
> +
> +	if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &naextents))
> +		return __this_address;
> +
> +	nextents += naextents;
>  	nblocks = be64_to_cpu(dip->di_nblocks);
>  
>  	/* Fork checks carried over from xfs_iformat_fork */
> @@ -595,7 +604,7 @@ xfs_dinode_verify(
>  		default:
>  			return __this_address;
>  		}
> -		if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
> +		if (naextents)
>  			return __this_address;
>  	}
>  
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
> index ea2c35091609..20f796610d46 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.h
> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
> @@ -36,8 +36,8 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
>  xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
>  		uint32_t cowextsize, uint16_t mode, uint16_t flags,
>  		uint64_t flags2);
> -xfs_extnum_t xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
> -		int whichfork);
> +int xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
> +		int whichfork, xfs_extnum_t *nextents);
>  
>  static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
>  {
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index 38dd2dfc31fa..7f7ffe29436d 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -107,13 +107,20 @@ xfs_iformat_extents(
>  	struct xfs_mount	*mp = ip->i_mount;
>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>  	int			state = xfs_bmap_fork_to_state(whichfork);
> -	xfs_extnum_t		nex = xfs_dfork_nextents(mp, dip, whichfork);
> -	int			size = nex * sizeof(xfs_bmbt_rec_t);
> +	xfs_extnum_t		nex;
> +	int			size;
>  	struct xfs_iext_cursor	icur;
>  	struct xfs_bmbt_rec	*dp;
>  	struct xfs_bmbt_irec	new;
> +	int			error;
>  	int			i;
>  
> +	error = xfs_dfork_nextents(mp, dip, whichfork, &nex);
> +	if (error)
> +		return error;
> +
> +	size = nex * sizeof(xfs_bmbt_rec_t);

sizeof(struct xfs_bmbt_rec);

(Please convert the old typedef usage when possible.)

> +
>  	/*
>  	 * If the number of extents is unreasonable, then something is wrong and
>  	 * we just bail out rather than crash in kmem_alloc() or memcpy() below.
> @@ -235,7 +242,10 @@ xfs_iformat_data_fork(
>  	 * depend on it.
>  	 */
>  	ip->i_df.if_format = dip->di_format;
> -	ip->i_df.if_nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
> +	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK,
> +			&ip->i_df.if_nextents);
> +	if (error)
> +		return error;
>  
>  	switch (inode->i_mode & S_IFMT) {
>  	case S_IFIFO:
> @@ -304,9 +314,11 @@ xfs_iformat_attr_fork(
>  {
>  	struct xfs_mount	*mp = ip->i_mount;
>  	xfs_extnum_t		nextents;
> -	int			error = 0;
> +	int			error;
>  
> -	nextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
> +	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &nextents);
> +	if (error)
> +		return error;
>  
>  	/*
>  	 * Initialize the extent count early, as the per-format routines may
> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
> index a161dac31a6f..e9dc3749ea08 100644
> --- a/fs/xfs/scrub/inode.c
> +++ b/fs/xfs/scrub/inode.c
> @@ -208,6 +208,44 @@ xchk_dinode_nsec(
>  		xchk_ino_set_corrupt(sc, ino);
>  }
>  
> +STATIC void
> +xchk_dinode_fork_recs(
> +	struct xfs_scrub	*sc,
> +	struct xfs_dinode	*dip,
> +	xfs_ino_t		ino,
> +	xfs_extnum_t		nextents,
> +	int			whichfork)
> +{
> +	struct xfs_mount	*mp = sc->mp;
> +	size_t			fork_recs;
> +	unsigned char		format;
> +
> +	if (whichfork == XFS_DATA_FORK) {
> +		fork_recs =  XFS_DFORK_DSIZE(dip, mp)
> +			/ sizeof(struct xfs_bmbt_rec);
> +		format = dip->di_format;
> +	} else if (whichfork == XFS_ATTR_FORK) {
> +		fork_recs =  XFS_DFORK_ASIZE(dip, mp)
> +			/ sizeof(struct xfs_bmbt_rec);
> +		format = dip->di_aformat;
> +	}

	fork_recs = XFS_DFORK_SIZE(dip, mp, whichfork);
	format = XFS_DFORK_FORMAT(dip, whichfork);

?

> +
> +	switch (format) {
> +	case XFS_DINODE_FMT_EXTENTS:
> +		if (nextents > fork_recs)
> +			xchk_ino_set_corrupt(sc, ino);
> +		break;
> +	case XFS_DINODE_FMT_BTREE:
> +		if (nextents <= fork_recs)
> +			xchk_ino_set_corrupt(sc, ino);
> +		break;
> +	default:
> +		if (nextents != 0)
> +			xchk_ino_set_corrupt(sc, ino);
> +		break;
> +	}
> +}
> +
>  /* Scrub all the ondisk inode fields. */
>  STATIC void
>  xchk_dinode(
> @@ -216,7 +254,6 @@ xchk_dinode(
>  	xfs_ino_t		ino)
>  {
>  	struct xfs_mount	*mp = sc->mp;
> -	size_t			fork_recs;
>  	unsigned long long	isize;
>  	uint64_t		flags2;
>  	xfs_extnum_t		nextents;
> @@ -224,6 +261,7 @@ xchk_dinode(
>  	prid_t			prid;
>  	uint16_t		flags;
>  	uint16_t		mode;
> +	int			error;
>  
>  	flags = be16_to_cpu(dip->di_flags);
>  	if (dip->di_version >= 3)
> @@ -379,33 +417,22 @@ xchk_dinode(
>  	xchk_inode_extsize(sc, dip, ino, mode, flags);
>  
>  	/* di_nextents */
> -	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
> -	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
> -	switch (dip->di_format) {
> -	case XFS_DINODE_FMT_EXTENTS:
> -		if (nextents > fork_recs)
> -			xchk_ino_set_corrupt(sc, ino);
> -		break;
> -	case XFS_DINODE_FMT_BTREE:
> -		if (nextents <= fork_recs)
> -			xchk_ino_set_corrupt(sc, ino);
> -		break;
> -	default:
> -		if (nextents != 0)
> -			xchk_ino_set_corrupt(sc, ino);
> -		break;
> -	}
> -
> -	naextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
> +	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents);
> +	if (error)
> +		xchk_ino_set_corrupt(sc, ino);
> +	else

	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents);
	if (error) {
		xchk_ino_set_corrupt(sc, ino);
		return;
	}
	xchk_dinode_fork_recs(sc, dip, ino, nextents, XFS_DATA_FORK);

At this point you might as well return; you have sufficient information
to generate the corruption report for userspace.

> +		xchk_dinode_fork_recs(sc, dip, ino, nextents, XFS_DATA_FORK);
>  
>  	/* di_forkoff */
>  	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
>  		xchk_ino_set_corrupt(sc, ino);
> -	if (naextents != 0 && dip->di_forkoff == 0)
> -		xchk_ino_set_corrupt(sc, ino);
>  	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
>  		xchk_ino_set_corrupt(sc, ino);
>  
> +	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &naextents);
> +	if (error || (naextents != 0 && dip->di_forkoff == 0))
> +		xchk_ino_set_corrupt(sc, ino);

Please keep these separate so that the debug tracepoints can capture
them as separate corruption sources.  Also, if xfs_dfork_nextents
returns an error, you might as well return since we have enough data to
generate the corruption report.

(The rest of the scrub and repair code changes look good, btw.)

--D

> +
>  	/* di_aformat */
>  	if (dip->di_aformat != XFS_DINODE_FMT_LOCAL &&
>  	    dip->di_aformat != XFS_DINODE_FMT_EXTENTS &&
> @@ -413,20 +440,8 @@ xchk_dinode(
>  		xchk_ino_set_corrupt(sc, ino);
>  
>  	/* di_anextents */
> -	fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
> -	switch (dip->di_aformat) {
> -	case XFS_DINODE_FMT_EXTENTS:
> -		if (naextents > fork_recs)
> -			xchk_ino_set_corrupt(sc, ino);
> -		break;
> -	case XFS_DINODE_FMT_BTREE:
> -		if (naextents <= fork_recs)
> -			xchk_ino_set_corrupt(sc, ino);
> -		break;
> -	default:
> -		if (naextents != 0)
> -			xchk_ino_set_corrupt(sc, ino);
> -	}
> +	if (!error)
> +		xchk_dinode_fork_recs(sc, dip, ino, naextents, XFS_ATTR_FORK);
>  
>  	if (dip->di_version >= 3) {
>  		xchk_dinode_nsec(sc, ino, dip, dip->di_crtime);
> @@ -490,6 +505,7 @@ xchk_inode_xref_bmap(
>  	struct xfs_dinode	*dip)
>  {
>  	struct xfs_mount	*mp = sc->mp;
> +	xfs_extnum_t		dip_nextents;
>  	xfs_extnum_t		nextents;
>  	xfs_filblks_t		count;
>  	xfs_filblks_t		acount;
> @@ -503,14 +519,18 @@ xchk_inode_xref_bmap(
>  			&nextents, &count);
>  	if (!xchk_should_check_xref(sc, &error, NULL))
>  		return;
> -	if (nextents < xfs_dfork_nextents(mp, dip, XFS_DATA_FORK))
> +
> +	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &dip_nextents);
> +	if (error || nextents < dip_nextents)
>  		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
>  
>  	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
>  			&nextents, &acount);
>  	if (!xchk_should_check_xref(sc, &error, NULL))
>  		return;
> -	if (nextents != xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
> +
> +	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &dip_nextents);
> +	if (error || nextents < dip_nextents)
>  		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
>  
>  	/* Check nblocks against the inode. */
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index bdb4685923c0..521c8df00990 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c
> @@ -602,7 +602,9 @@ xrep_dinode_bad_extents_fork(
>  	int			i;
>  	int			fork_size;
>  
> -	nex = xfs_dfork_nextents(sc->mp, dip, whichfork);
> +	if (xfs_dfork_nextents(sc->mp, dip, whichfork, &nex))
> +		return true;
> +
>  	fork_size = nex * sizeof(struct xfs_bmbt_rec);
>  	if (fork_size < 0 || fork_size > dfork_size)
>  		return true;
> @@ -633,11 +635,14 @@ xrep_dinode_bad_btree_fork(
>  	int			whichfork)
>  {
>  	struct xfs_bmdr_block	*dfp;
> +	xfs_extnum_t		nextents;
>  	int			nrecs;
>  	int			level;
>  
> -	if (xfs_dfork_nextents(sc->mp, dip, whichfork) <=
> -			dfork_size / sizeof(struct xfs_bmbt_rec))
> +	if (xfs_dfork_nextents(sc->mp, dip, whichfork, &nextents))
> +		return true;
> +
> +	if (nextents <= dfork_size / sizeof(struct xfs_bmbt_rec))
>  		return true;
>  
>  	if (dfork_size < sizeof(struct xfs_bmdr_block))
> @@ -774,11 +779,15 @@ xrep_dinode_check_afork(
>  	struct xfs_dinode		*dip)
>  {
>  	struct xfs_attr_shortform	*sfp;
> +	xfs_extnum_t			nextents;
>  	int				size;
>  
> +	if (xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK, &nextents))
> +		return true;
> +
>  	if (XFS_DFORK_BOFF(dip) == 0)
>  		return dip->di_aformat != XFS_DINODE_FMT_EXTENTS ||
> -		       dip->di_anextents != 0;
> +		       nextents != 0;
>  
>  	size = XFS_DFORK_SIZE(dip, sc->mp, XFS_ATTR_FORK);
>  	switch (XFS_DFORK_FORMAT(dip, XFS_ATTR_FORK)) {
> @@ -835,11 +844,15 @@ xrep_dinode_ensure_forkoff(
>  	size_t				bmdr_minsz = xfs_bmdr_space_calc(1);
>  	unsigned int			lit_sz = XFS_LITINO(sc->mp);
>  	unsigned int			afork_min, dfork_min;
> +	int				error;
>  
>  	trace_xrep_dinode_ensure_forkoff(sc, dip);
>  
> -	dnextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
> -	anextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
> +	error = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK, &dnextents);
> +	ASSERT(error == 0);
> +
> +	error = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK, &anextents);
> +	ASSERT(error == 0);
>  
>  	/*
>  	 * Before calling this function, xrep_dinode_core ensured that both
> @@ -1027,6 +1040,7 @@ xrep_dinode_zap_forks(
>  	uint16_t			mode;
>  	bool				zap_datafork = false;
>  	bool				zap_attrfork = false;
> +	int				error;
>  
>  	trace_xrep_dinode_zap_forks(sc, dip);
>  
> @@ -1035,12 +1049,12 @@ xrep_dinode_zap_forks(
>  	/* Inode counters don't make sense? */
>  	nblocks = be64_to_cpu(dip->di_nblocks);
>  
> -	nextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
> -	if (nextents > nblocks)
> +	error = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK, &nextents);
> +	if (error || nextents > nblocks)
>  		zap_datafork = true;
>  
> -	naextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
> -	if (naextents > nblocks)
> +	error = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK, &naextents);
> +	if (error || naextents > nblocks)
>  		zap_attrfork = true;
>  
>  	if (nextents + naextents > nblocks)
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 08/12] xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits respectively
  2021-07-26 11:45 ` [PATCH V2 08/12] xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits respectively Chandan Babu R
@ 2021-07-27 22:29   ` Darrick J. Wong
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 22:29 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:37PM +0530, Chandan Babu R wrote:
> A future commit will introduce a 64-bit on-disk data extent counter and a
> 32-bit on-disk attr extent counter. This commit promotes xfs_extnum_t and
> xfs_aextnum_t to 64 and 32-bits in order to correctly handle in-core versions
> of these quantities.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>

Well done!
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_bmap.c       | 2 +-
>  fs/xfs/libxfs/xfs_inode_fork.c | 2 +-
>  fs/xfs/libxfs/xfs_types.h      | 4 ++--
>  fs/xfs/scrub/attr_repair.c     | 2 +-
>  fs/xfs/scrub/trace.h           | 2 +-
>  fs/xfs/xfs_inode.c             | 4 ++--
>  fs/xfs/xfs_trace.h             | 4 ++--
>  7 files changed, 10 insertions(+), 10 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index e5d243fd187d..a27d57ea301c 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -472,7 +472,7 @@ xfs_bmap_check_leaf_extents(
>  	if (bp_release)
>  		xfs_trans_brelse(NULL, bp);
>  error_norelse:
> -	xfs_warn(mp, "%s: BAD after btree leaves for %d extents",
> +	xfs_warn(mp, "%s: BAD after btree leaves for %llu extents",
>  		__func__, i);
>  	xfs_err(mp, "%s: CORRUPTED BTREE OR SOMETHING", __func__);
>  	xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE);
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
> index 7f7ffe29436d..336eee69703c 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.c
> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
> @@ -126,7 +126,7 @@ xfs_iformat_extents(
>  	 * we just bail out rather than crash in kmem_alloc() or memcpy() below.
>  	 */
>  	if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, mp, whichfork))) {
> -		xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).",
> +		xfs_warn(ip->i_mount, "corrupt inode %llu ((a)extents = %llu).",
>  			(unsigned long long) ip->i_ino, nex);
>  		xfs_inode_verifier_error(ip, -EFSCORRUPTED,
>  				"xfs_iformat_extents(1)", dip, sizeof(*dip),
> diff --git a/fs/xfs/libxfs/xfs_types.h b/fs/xfs/libxfs/xfs_types.h
> index 8908346b1deb..584fa61e338e 100644
> --- a/fs/xfs/libxfs/xfs_types.h
> +++ b/fs/xfs/libxfs/xfs_types.h
> @@ -12,8 +12,8 @@ typedef uint32_t	xfs_agblock_t;	/* blockno in alloc. group */
>  typedef uint32_t	xfs_agino_t;	/* inode # within allocation grp */
>  typedef uint32_t	xfs_extlen_t;	/* extent length in blocks */
>  typedef uint32_t	xfs_agnumber_t;	/* allocation group number */
> -typedef int32_t		xfs_extnum_t;	/* # of extents in a file */
> -typedef int16_t		xfs_aextnum_t;	/* # extents in an attribute fork */
> +typedef uint64_t	xfs_extnum_t;	/* # of extents in a file */
> +typedef uint32_t	xfs_aextnum_t;	/* # extents in an attribute fork */
>  typedef int64_t		xfs_fsize_t;	/* bytes in a file */
>  typedef uint64_t	xfs_ufsize_t;	/* unsigned bytes in a file */
>  
> diff --git a/fs/xfs/scrub/attr_repair.c b/fs/xfs/scrub/attr_repair.c
> index 7d92195d286b..aad4b269949d 100644
> --- a/fs/xfs/scrub/attr_repair.c
> +++ b/fs/xfs/scrub/attr_repair.c
> @@ -769,7 +769,7 @@ xrep_xattr_fork_remove(
>  		unsigned int		i = 0;
>  
>  		xfs_emerg(sc->mp,
> -	"inode 0x%llx attr fork still has %u attr extents, format %d?!",
> +	"inode 0x%llx attr fork still has %llu attr extents, format %d?!",
>  				ip->i_ino, ifp->if_nextents, ifp->if_format);
>  		for_each_xfs_iext(ifp, &icur, &irec) {
>  			xfs_err(sc->mp, "[%u]: startoff %llu startblock %llu blockcount %llu state %u", i++, irec.br_startoff, irec.br_startblock, irec.br_blockcount, irec.br_state);
> diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
> index a0303f692e52..f9be7812c8ce 100644
> --- a/fs/xfs/scrub/trace.h
> +++ b/fs/xfs/scrub/trace.h
> @@ -1363,7 +1363,7 @@ TRACE_EVENT(xrep_dinode_count_rmaps,
>  		__entry->attr_extents = attr_extents;
>  		__entry->block0 = block0;
>  	),
> -	TP_printk("dev %d:%d ino 0x%llx dblocks %llu rtblocks %llu ablocks %llu dextents %u rtextents %u aextents %u block0 %llu",
> +	TP_printk("dev %d:%d ino 0x%llx dblocks %llu rtblocks %llu ablocks %llu dextents %llu rtextents %llu aextents %u block0 %llu",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		  __entry->ino,
>  		  __entry->data_blocks,
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index f152f6dace0c..4070fb01350c 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2510,8 +2510,8 @@ xfs_iflush(
>  	if (XFS_TEST_ERROR(ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp) >
>  				ip->i_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
>  		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
> -			"%s: detected corrupt incore inode %Lu, "
> -			"total extents = %d, nblocks = %Ld, ptr "PTR_FMT,
> +			"%s: detected corrupt incore inode %llu, "
> +			"total extents = %llu nblocks = %lld, ptr "PTR_FMT,
>  			__func__, ip->i_ino,
>  			ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp),
>  			ip->i_nblocks, ip);
> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
> index 5ed11f894f79..af426b9824db 100644
> --- a/fs/xfs/xfs_trace.h
> +++ b/fs/xfs/xfs_trace.h
> @@ -2351,7 +2351,7 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
>  		__entry->broot_size = ip->i_df.if_broot_bytes;
>  		__entry->fork_off = XFS_IFORK_BOFF(ip);
>  	),
> -	TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, "
> +	TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %llu, "
>  		  "broot size %d, fork offset %d",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		  __entry->ino,
> @@ -4588,7 +4588,7 @@ TRACE_EVENT(xfs_swapext_delta_nextents,
>  		__entry->d_nexts1 = d_nexts1;
>  		__entry->d_nexts2 = d_nexts2;
>  	),
> -	TP_printk("dev %d:%d ino1 0x%llx nexts %u ino2 0x%llx nexts %u delta1 %lld delta2 %lld",
> +	TP_printk("dev %d:%d ino1 0x%llx nexts %llu ino2 0x%llx nexts %llu delta1 %lld delta2 %lld",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		  __entry->ino1, __entry->nexts1,
>  		  __entry->ino2, __entry->nexts2,
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width
  2021-07-26 11:45 ` [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width Chandan Babu R
@ 2021-07-27 22:50   ` Darrick J. Wong
  2021-07-28  5:48     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 22:50 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:36PM +0530, Chandan Babu R wrote:
> This commit renames extent counter fields in "struct xfs_dinode" and "struct
> xfs_log_dinode" based on the width of the fields. As of this commit, the
> 32-bit field will be used to count data fork extents and the 16-bit field will
> be used to count attr fork extents.

I totally had the preconceived notion that you were going to make the
existing fields the 'lo' bits and then add six bytes of 'hi' field to
the ondisk inode for the space you need.

Instead, I see that in the new scheme, the the space where di_anextents
is becomes unused, the space where di_nextents is now becomes the attr
fork extent count, and you allocate another 8 bytes at the end of the
ondisk inode for the data fork extent count.

Hm.  That /is/ clever in that we don't have to split bits between
fields, but the downside is that if you want to upgrade existing
filesystems, you'd either have to rewrite every inode in the entire
filesystem, or introduce a di_flags2 bit to signal that this inode
actually has the extended counters.  It also uses 8 bytes at the end of
the ondisk inode structure.

I think if we adjust the design a little bit we can enable the upgrade
use case and reuse existing empty space in the ondisk inode.  Notice
that there are six bytes of di_pad available in the middle of the inode
record?  What do you think about putting the upper fields there?  The
middle of the struct then looks like this:

	__be32		di_nextentshi;	/* upper 32-bits of di_nextents */
	__be16		di_naextentshi;	/* upper 16-bits of di_naextents */
	__be16		di_flushiter;	/* incremented on flush */
	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_nextentslo;	/* number of extents in data fork */
	__be16		di_anextentslo;	/* number of extents in attribute fork*/

And your xfs_dfork_extents function looks like:

	case XFS_DATA_FORK:
		return (xfs_extnum_t)be32_to_cpu(dip->di_nextentshi) << 32 |
				     be32_to_cpu(dip->di_nextentslo);
	case XFS_ATTR_FORK:
		return (xfs_extnum_t)be16_to_cpu(dip->di_naextentshi) << 16 |
				     be16_to_cpu(dip->di_naextentslo);

The pad fields are supposed to be zero, and upgrading now is no more
effort than tapping into the existing xfs_repair upgrader code to add
the EXTCOUNT64 feature flag.

--D

> 
> This change is done to enable a future commit to introduce a new 64-bit extent
> counter field.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_format.h      |  4 ++--
>  fs/xfs/libxfs/xfs_inode_buf.c   |  8 ++++----
>  fs/xfs/libxfs/xfs_log_format.h  |  4 ++--
>  fs/xfs/scrub/inode_repair.c     |  4 ++--
>  fs/xfs/scrub/trace.h            | 14 +++++++-------
>  fs/xfs/xfs_inode_item.c         |  4 ++--
>  fs/xfs/xfs_inode_item_recover.c |  8 ++++----
>  7 files changed, 23 insertions(+), 23 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 001a4077a7c6..2362cc005cc6 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -1039,8 +1039,8 @@ typedef struct xfs_dinode {
>  	__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*/
> +	__be32		di_nextents32;	/* number of extents in data fork */
> +	__be16		di_nextents16;	/* number of extents in attribute fork*/
>  	__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 */
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 9ed04da2e2b1..65d753e16007 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -313,8 +313,8 @@ 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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
> +	to->di_nextents16 = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));

/me wonders if these should get their own static inline conversion
helpers to set the appropriate fields, like I did for timestamps?

>  	to->di_forkoff = ip->i_forkoff;
>  	to->di_aformat = xfs_ifork_format(ip->i_afp);
>  	to->di_flags = cpu_to_be16(ip->i_diflags);
> @@ -389,11 +389,11 @@ xfs_dfork_nextents(
>  
>  	switch (whichfork) {
>  	case XFS_DATA_FORK:
> -		*nextents = be32_to_cpu(dip->di_nextents);
> +		*nextents = be32_to_cpu(dip->di_nextents32);
>  		break;
>  
>  	case XFS_ATTR_FORK:
> -		*nextents = be16_to_cpu(dip->di_anextents);
> +		*nextents = be16_to_cpu(dip->di_nextents16);
>  		break;
>  
>  	default:
> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> index 0c888f92184e..ca8e4ad8312a 100644
> --- a/fs/xfs/libxfs/xfs_log_format.h
> +++ b/fs/xfs/libxfs/xfs_log_format.h
> @@ -402,8 +402,8 @@ struct xfs_log_dinode {
>  	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 */
> -	xfs_extnum_t	di_nextents;	/* number of extents in data fork */
> -	xfs_aextnum_t	di_anextents;	/* number of extents in attribute fork*/
> +	uint32_t	di_nextents32;	/* number of extents in data fork */
> +	uint16_t	di_nextents16;	/* number of extents in attribute fork*/
>  	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 */
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index 521c8df00990..4d773a16f886 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c
> @@ -736,7 +736,7 @@ xrep_dinode_zap_dfork(
>  {
>  	trace_xrep_dinode_zap_dfork(sc, dip);
>  
> -	dip->di_nextents = 0;
> +	dip->di_nextents32 = 0;
>  
>  	/* Special files always get reset to DEV */
>  	switch (mode & S_IFMT) {
> @@ -823,7 +823,7 @@ xrep_dinode_zap_afork(
>  	trace_xrep_dinode_zap_afork(sc, dip);
>  
>  	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
> -	dip->di_anextents = 0;
> +	dip->di_nextents16 = 0;
>  
>  	dip->di_forkoff = 0;
>  	dip->di_mode = cpu_to_be16(mode & ~0777);
> diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
> index fd03685b1f6b..a0303f692e52 100644
> --- a/fs/xfs/scrub/trace.h
> +++ b/fs/xfs/scrub/trace.h
> @@ -1209,8 +1209,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>  		__field(uint64_t, size)
>  		__field(uint64_t, nblocks)
>  		__field(uint32_t, extsize)
> -		__field(uint32_t, nextents)
> -		__field(uint16_t, anextents)
> +		__field(uint32_t, nextents32)
> +		__field(uint16_t, nextents16)
>  		__field(uint8_t, forkoff)
>  		__field(uint8_t, aformat)
>  		__field(uint16_t, flags)
> @@ -1229,8 +1229,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>  		__entry->size = be64_to_cpu(dip->di_size);
>  		__entry->nblocks = be64_to_cpu(dip->di_nblocks);
>  		__entry->extsize = be32_to_cpu(dip->di_extsize);
> -		__entry->nextents = be32_to_cpu(dip->di_nextents);
> -		__entry->anextents = be16_to_cpu(dip->di_anextents);
> +		__entry->nextents32 = be32_to_cpu(dip->di_nextents32);
> +		__entry->nextents16 = be16_to_cpu(dip->di_nextents16);
>  		__entry->forkoff = dip->di_forkoff;
>  		__entry->aformat = dip->di_aformat;
>  		__entry->flags = be16_to_cpu(dip->di_flags);
> @@ -1238,7 +1238,7 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>  		__entry->flags2 = be64_to_cpu(dip->di_flags2);
>  		__entry->cowextsize = be32_to_cpu(dip->di_cowextsize);
>  	),
> -	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents %u anextents %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
> +	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents32 %u nextents16 %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>  		  __entry->ino,
>  		  __entry->mode,
> @@ -1249,8 +1249,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>  		  __entry->size,
>  		  __entry->nblocks,
>  		  __entry->extsize,
> -		  __entry->nextents,
> -		  __entry->anextents,
> +		  __entry->nextents32,
> +		  __entry->nextents16,
>  		  __entry->forkoff,
>  		  __entry->aformat,
>  		  __entry->flags,
> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
> index 35de30849fcc..f54ce7468ba1 100644
> --- a/fs/xfs/xfs_inode_item.c
> +++ b/fs/xfs/xfs_inode_item.c
> @@ -385,8 +385,8 @@ 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_nextents32 = xfs_ifork_nextents(&ip->i_df);
> +	to->di_nextents16 = 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;
> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
> index 7b79518b6c20..40af9d1265c7 100644
> --- a/fs/xfs/xfs_inode_item_recover.c
> +++ b/fs/xfs/xfs_inode_item_recover.c
> @@ -166,8 +166,8 @@ xfs_log_dinode_to_disk(
>  	to->di_size = cpu_to_be64(from->di_size);
>  	to->di_nblocks = cpu_to_be64(from->di_nblocks);
>  	to->di_extsize = cpu_to_be32(from->di_extsize);
> -	to->di_nextents = cpu_to_be32(from->di_nextents);
> -	to->di_anextents = cpu_to_be16(from->di_anextents);
> +	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
> +	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>  	to->di_forkoff = from->di_forkoff;
>  	to->di_aformat = from->di_aformat;
>  	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
> @@ -332,7 +332,7 @@ xlog_recover_inode_commit_pass2(
>  			goto out_release;
>  		}
>  	}
> -	if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){
> +	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
>  		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
>  				     XFS_ERRLEVEL_LOW, mp, ldip,
>  				     sizeof(*ldip));
> @@ -340,7 +340,7 @@ xlog_recover_inode_commit_pass2(
>  	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
>  	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
>  			__func__, item, dip, bp, in_f->ilf_ino,
> -			ldip->di_nextents + ldip->di_anextents,
> +			ldip->di_nextents32 + ldip->di_nextents16,
>  			ldip->di_nblocks);
>  		error = -EFSCORRUPTED;
>  		goto out_release;
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
  2021-07-26 11:45 ` [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 Chandan Babu R
@ 2021-07-27 22:54   ` Darrick J. Wong
  2021-07-27 23:00     ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 22:54 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:38PM +0530, Chandan Babu R wrote:
> This commit renames XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 to allow a future
> commit to extend bulkstat facility to support 64-bit extent counters. To this
> end, this commit also renames xfs_bulkstat->bs_extents field to
> xfs_bulkstat->bs_extents32.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_fs.h |  4 ++--
>  fs/xfs/xfs_ioctl.c     | 27 ++++++++++++++++++++++-----
>  fs/xfs/xfs_ioctl32.c   |  7 +++++++
>  fs/xfs/xfs_itable.c    |  4 ++--
>  fs/xfs/xfs_itable.h    |  1 +
>  5 files changed, 34 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index 2594fb647384..d760a969599e 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -394,7 +394,7 @@ struct xfs_bulkstat {
>  	uint32_t	bs_extsize_blks; /* extent size hint, blocks	*/
>  
>  	uint32_t	bs_nlink;	/* number of links		*/
> -	uint32_t	bs_extents;	/* number of extents		*/
> +	uint32_t	bs_extents32;	/* number of extents		*/

I wish I'd thought of this when we introduced bulkstat v5 so you
wouldn't have had to do this.

(I might have more to say in the bulkstat v6 patch review.)
Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

>  	uint32_t	bs_aextents;	/* attribute number of extents	*/
>  	uint16_t	bs_version;	/* structure version		*/
>  	uint16_t	bs_forkoff;	/* inode fork offset in bytes	*/
> @@ -853,7 +853,7 @@ struct xfs_scrub_metadata {
>  #define XFS_IOC_FSGEOMETRY_V4	     _IOR ('X', 124, struct xfs_fsop_geom_v4)
>  #define XFS_IOC_GOINGDOWN	     _IOR ('X', 125, uint32_t)
>  #define XFS_IOC_FSGEOMETRY	     _IOR ('X', 126, struct xfs_fsop_geom)
> -#define XFS_IOC_BULKSTAT	     _IOR ('X', 127, struct xfs_bulkstat_req)
> +#define XFS_IOC_BULKSTAT_V5	     _IOR ('X', 127, struct xfs_bulkstat_req)
>  #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
>  /*	FIEXCHANGE_RANGE ----------- hoisted 129	 */
>  /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 2da90f81e6e3..85f45340cb16 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -715,6 +715,8 @@ xfs_fsbulkstat_one_fmt(
>  {
>  	struct xfs_bstat		bs1;
>  
> +	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V1);
> +
>  	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
>  	if (copy_to_user(breq->ubuffer, &bs1, sizeof(bs1)))
>  		return -EFAULT;
> @@ -728,6 +730,8 @@ xfs_fsinumbers_fmt(
>  {
>  	struct xfs_inogrp		ig1;
>  
> +	ASSERT(breq->version == XFS_INUMBERS_VERSION_V1);
> +
>  	xfs_inumbers_to_inogrp(&ig1, igrp);
>  	if (copy_to_user(breq->ubuffer, &ig1, sizeof(struct xfs_inogrp)))
>  		return -EFAULT;
> @@ -787,14 +791,17 @@ xfs_ioc_fsbulkstat(
>  	 */
>  	if (cmd == XFS_IOC_FSINUMBERS) {
>  		breq.startino = lastino ? lastino + 1 : 0;
> +		breq.version = XFS_INUMBERS_VERSION_V1;
>  		error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
>  		lastino = breq.startino - 1;
>  	} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
>  		breq.startino = lastino;
>  		breq.icount = 1;
> +		breq.version = XFS_BULKSTAT_VERSION_V1;
>  		error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
>  	} else {	/* XFS_IOC_FSBULKSTAT */
>  		breq.startino = lastino ? lastino + 1 : 0;
> +		breq.version = XFS_BULKSTAT_VERSION_V1;
>  		error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
>  		lastino = breq.startino - 1;
>  	}
> @@ -819,6 +826,8 @@ xfs_bulkstat_fmt(
>  	struct xfs_ibulk		*breq,
>  	const struct xfs_bulkstat	*bstat)
>  {
> +	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V5);
> +
>  	if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat)))
>  		return -EFAULT;
>  	return xfs_ibulk_advance(breq, sizeof(struct xfs_bulkstat));
> @@ -918,13 +927,15 @@ STATIC int
>  xfs_ioc_bulkstat(
>  	struct file			*file,
>  	unsigned int			cmd,
> -	struct xfs_bulkstat_req __user	*arg)
> +	struct xfs_bulkstat_req __user	*arg,
> +	int				version)
>  {
>  	struct xfs_mount		*mp = XFS_I(file_inode(file))->i_mount;
>  	struct xfs_bulk_ireq		hdr;
>  	struct xfs_ibulk		breq = {
>  		.mp			= mp,
>  		.mnt_userns		= file_mnt_user_ns(file),
> +		.version		= version,
>  	};
>  	int				error;
>  
> @@ -960,6 +971,8 @@ xfs_inumbers_fmt(
>  	struct xfs_ibulk		*breq,
>  	const struct xfs_inumbers	*igrp)
>  {
> +	ASSERT(breq->version == XFS_INUMBERS_VERSION_V5);
> +
>  	if (copy_to_user(breq->ubuffer, igrp, sizeof(struct xfs_inumbers)))
>  		return -EFAULT;
>  	return xfs_ibulk_advance(breq, sizeof(struct xfs_inumbers));
> @@ -970,11 +983,13 @@ STATIC int
>  xfs_ioc_inumbers(
>  	struct xfs_mount		*mp,
>  	unsigned int			cmd,
> -	struct xfs_inumbers_req __user	*arg)
> +	struct xfs_inumbers_req __user	*arg,
> +	int				version)
>  {
>  	struct xfs_bulk_ireq		hdr;
>  	struct xfs_ibulk		breq = {
>  		.mp			= mp,
> +		.version		= version,
>  	};
>  	int				error;
>  
> @@ -1882,10 +1897,12 @@ xfs_file_ioctl(
>  	case XFS_IOC_FSINUMBERS:
>  		return xfs_ioc_fsbulkstat(filp, cmd, arg);
>  
> -	case XFS_IOC_BULKSTAT:
> -		return xfs_ioc_bulkstat(filp, cmd, arg);
> +	case XFS_IOC_BULKSTAT_V5:
> +		return xfs_ioc_bulkstat(filp, cmd, arg,
> +				XFS_BULKSTAT_VERSION_V5);
>  	case XFS_IOC_INUMBERS:
> -		return xfs_ioc_inumbers(mp, cmd, arg);
> +		return xfs_ioc_inumbers(mp, cmd, arg,
> +				XFS_INUMBERS_VERSION_V5);
>  
>  	case XFS_IOC_FSGEOMETRY_V1:
>  		return xfs_ioc_fsgeometry(mp, arg, 3);
> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
> index bef19060f4aa..d9a7abc209b5 100644
> --- a/fs/xfs/xfs_ioctl32.c
> +++ b/fs/xfs/xfs_ioctl32.c
> @@ -88,6 +88,8 @@ xfs_fsinumbers_fmt_compat(
>  	struct xfs_inogrp		ig1;
>  	struct xfs_inogrp		*igrp = &ig1;
>  
> +	ASSERT(breq->version == XFS_INUMBERS_VERSION_V1);
> +
>  	xfs_inumbers_to_inogrp(&ig1, ig);
>  
>  	if (put_user(igrp->xi_startino,   &p32->xi_startino) ||
> @@ -177,6 +179,8 @@ xfs_fsbulkstat_one_fmt_compat(
>  	struct xfs_bstat		bs1;
>  	struct xfs_bstat		*buffer = &bs1;
>  
> +	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V1);
> +
>  	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
>  
>  	if (put_user(buffer->bs_ino,	  &p32->bs_ino)		||
> @@ -293,15 +297,18 @@ xfs_compat_ioc_fsbulkstat(
>  	 */
>  	if (cmd == XFS_IOC_FSINUMBERS_32) {
>  		breq.startino = lastino ? lastino + 1 : 0;
> +		breq.version = XFS_INUMBERS_VERSION_V1;
>  		error = xfs_inumbers(&breq, inumbers_func);
>  		lastino = breq.startino - 1;
>  	} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
>  		breq.startino = lastino;
>  		breq.icount = 1;
> +		breq.version = XFS_BULKSTAT_VERSION_V1;
>  		error = xfs_bulkstat_one(&breq, bs_one_func);
>  		lastino = breq.startino;
>  	} else if (cmd == XFS_IOC_FSBULKSTAT_32) {
>  		breq.startino = lastino ? lastino + 1 : 0;
> +		breq.version = XFS_BULKSTAT_VERSION_V1;
>  		error = xfs_bulkstat(&breq, bs_one_func);
>  		lastino = breq.startino - 1;
>  	} else {
> diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
> index 65c194cdea79..f0daa65e61ff 100644
> --- a/fs/xfs/xfs_itable.c
> +++ b/fs/xfs/xfs_itable.c
> @@ -134,7 +134,7 @@ xfs_bulkstat_one_int(
>  
>  	buf->bs_xflags = xfs_ip2xflags(ip);
>  	buf->bs_extsize_blks = ip->i_extsize;
> -	buf->bs_extents = xfs_ifork_nextents(&ip->i_df);
> +	buf->bs_extents32 = xfs_ifork_nextents(&ip->i_df);
>  	xfs_bulkstat_health(ip, buf);
>  	buf->bs_aextents = xfs_ifork_nextents(ip->i_afp);
>  	buf->bs_forkoff = XFS_IFORK_BOFF(ip);
> @@ -356,7 +356,7 @@ xfs_bulkstat_to_bstat(
>  	bs1->bs_blocks = bstat->bs_blocks;
>  	bs1->bs_xflags = bstat->bs_xflags;
>  	bs1->bs_extsize = XFS_FSB_TO_B(mp, bstat->bs_extsize_blks);
> -	bs1->bs_extents = bstat->bs_extents;
> +	bs1->bs_extents = bstat->bs_extents32;
>  	bs1->bs_gen = bstat->bs_gen;
>  	bs1->bs_projid_lo = bstat->bs_projectid & 0xFFFF;
>  	bs1->bs_forkoff = bstat->bs_forkoff;
> diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
> index f5a13f69883a..ee4d8d0461ca 100644
> --- a/fs/xfs/xfs_itable.h
> +++ b/fs/xfs/xfs_itable.h
> @@ -14,6 +14,7 @@ struct xfs_ibulk {
>  	unsigned int		icount;   /* number of elements in ubuffer */
>  	unsigned int		ocount;   /* number of records returned */
>  	unsigned int		flags;    /* see XFS_IBULK_FLAG_* */
> +	int			version;  /* structure version to be returned */
>  };
>  
>  /* Only iterate within the same AG as startino */
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
  2021-07-27 22:54   ` Darrick J. Wong
@ 2021-07-27 23:00     ` Darrick J. Wong
  2021-07-27 23:17       ` Dave Chinner
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 23:00 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Tue, Jul 27, 2021 at 03:54:00PM -0700, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:38PM +0530, Chandan Babu R wrote:
> > This commit renames XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 to allow a future
> > commit to extend bulkstat facility to support 64-bit extent counters. To this
> > end, this commit also renames xfs_bulkstat->bs_extents field to
> > xfs_bulkstat->bs_extents32.
> > 
> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > ---
> >  fs/xfs/libxfs/xfs_fs.h |  4 ++--
> >  fs/xfs/xfs_ioctl.c     | 27 ++++++++++++++++++++++-----
> >  fs/xfs/xfs_ioctl32.c   |  7 +++++++
> >  fs/xfs/xfs_itable.c    |  4 ++--
> >  fs/xfs/xfs_itable.h    |  1 +
> >  5 files changed, 34 insertions(+), 9 deletions(-)
> > 
> > diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> > index 2594fb647384..d760a969599e 100644
> > --- a/fs/xfs/libxfs/xfs_fs.h
> > +++ b/fs/xfs/libxfs/xfs_fs.h
> > @@ -394,7 +394,7 @@ struct xfs_bulkstat {
> >  	uint32_t	bs_extsize_blks; /* extent size hint, blocks	*/
> >  
> >  	uint32_t	bs_nlink;	/* number of links		*/
> > -	uint32_t	bs_extents;	/* number of extents		*/
> > +	uint32_t	bs_extents32;	/* number of extents		*/
> 
> I wish I'd thought of this when we introduced bulkstat v5 so you
> wouldn't have had to do this.
> 
> (I might have more to say in the bulkstat v6 patch review.)
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Actually, I take that back, I have things to say /now/. :)

Rather than adding a whole new ioctl definition which (I haven't looked
at the xfsprogs changes) likely creates a bunch of churn in userspace,
what if we added a XFS_IBULK_ flag for supporting large extent counts?
There's also quite a bit of reserved padding space in xfs_bulk_ireq, so
perhaps we should define one of those padding u64 as a op-specific flag
field that would be a way to pass bulkstat-specific flags to the
relevant operations.  That way the 64-bit extent counts are merely a
variant on bulkstat v5 instead of a whole new format.

I doubt very many bulkstat users have fully gone over to V5 yet; telling
them we have a V6 already isn't going to be fun... :/

--D

> --D
> 
> >  	uint32_t	bs_aextents;	/* attribute number of extents	*/
> >  	uint16_t	bs_version;	/* structure version		*/
> >  	uint16_t	bs_forkoff;	/* inode fork offset in bytes	*/
> > @@ -853,7 +853,7 @@ struct xfs_scrub_metadata {
> >  #define XFS_IOC_FSGEOMETRY_V4	     _IOR ('X', 124, struct xfs_fsop_geom_v4)
> >  #define XFS_IOC_GOINGDOWN	     _IOR ('X', 125, uint32_t)
> >  #define XFS_IOC_FSGEOMETRY	     _IOR ('X', 126, struct xfs_fsop_geom)
> > -#define XFS_IOC_BULKSTAT	     _IOR ('X', 127, struct xfs_bulkstat_req)
> > +#define XFS_IOC_BULKSTAT_V5	     _IOR ('X', 127, struct xfs_bulkstat_req)
> >  #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
> >  /*	FIEXCHANGE_RANGE ----------- hoisted 129	 */
> >  /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
> > diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> > index 2da90f81e6e3..85f45340cb16 100644
> > --- a/fs/xfs/xfs_ioctl.c
> > +++ b/fs/xfs/xfs_ioctl.c
> > @@ -715,6 +715,8 @@ xfs_fsbulkstat_one_fmt(
> >  {
> >  	struct xfs_bstat		bs1;
> >  
> > +	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V1);
> > +
> >  	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
> >  	if (copy_to_user(breq->ubuffer, &bs1, sizeof(bs1)))
> >  		return -EFAULT;
> > @@ -728,6 +730,8 @@ xfs_fsinumbers_fmt(
> >  {
> >  	struct xfs_inogrp		ig1;
> >  
> > +	ASSERT(breq->version == XFS_INUMBERS_VERSION_V1);
> > +
> >  	xfs_inumbers_to_inogrp(&ig1, igrp);
> >  	if (copy_to_user(breq->ubuffer, &ig1, sizeof(struct xfs_inogrp)))
> >  		return -EFAULT;
> > @@ -787,14 +791,17 @@ xfs_ioc_fsbulkstat(
> >  	 */
> >  	if (cmd == XFS_IOC_FSINUMBERS) {
> >  		breq.startino = lastino ? lastino + 1 : 0;
> > +		breq.version = XFS_INUMBERS_VERSION_V1;
> >  		error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
> >  		lastino = breq.startino - 1;
> >  	} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
> >  		breq.startino = lastino;
> >  		breq.icount = 1;
> > +		breq.version = XFS_BULKSTAT_VERSION_V1;
> >  		error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
> >  	} else {	/* XFS_IOC_FSBULKSTAT */
> >  		breq.startino = lastino ? lastino + 1 : 0;
> > +		breq.version = XFS_BULKSTAT_VERSION_V1;
> >  		error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
> >  		lastino = breq.startino - 1;
> >  	}
> > @@ -819,6 +826,8 @@ xfs_bulkstat_fmt(
> >  	struct xfs_ibulk		*breq,
> >  	const struct xfs_bulkstat	*bstat)
> >  {
> > +	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V5);
> > +
> >  	if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat)))
> >  		return -EFAULT;
> >  	return xfs_ibulk_advance(breq, sizeof(struct xfs_bulkstat));
> > @@ -918,13 +927,15 @@ STATIC int
> >  xfs_ioc_bulkstat(
> >  	struct file			*file,
> >  	unsigned int			cmd,
> > -	struct xfs_bulkstat_req __user	*arg)
> > +	struct xfs_bulkstat_req __user	*arg,
> > +	int				version)
> >  {
> >  	struct xfs_mount		*mp = XFS_I(file_inode(file))->i_mount;
> >  	struct xfs_bulk_ireq		hdr;
> >  	struct xfs_ibulk		breq = {
> >  		.mp			= mp,
> >  		.mnt_userns		= file_mnt_user_ns(file),
> > +		.version		= version,
> >  	};
> >  	int				error;
> >  
> > @@ -960,6 +971,8 @@ xfs_inumbers_fmt(
> >  	struct xfs_ibulk		*breq,
> >  	const struct xfs_inumbers	*igrp)
> >  {
> > +	ASSERT(breq->version == XFS_INUMBERS_VERSION_V5);
> > +
> >  	if (copy_to_user(breq->ubuffer, igrp, sizeof(struct xfs_inumbers)))
> >  		return -EFAULT;
> >  	return xfs_ibulk_advance(breq, sizeof(struct xfs_inumbers));
> > @@ -970,11 +983,13 @@ STATIC int
> >  xfs_ioc_inumbers(
> >  	struct xfs_mount		*mp,
> >  	unsigned int			cmd,
> > -	struct xfs_inumbers_req __user	*arg)
> > +	struct xfs_inumbers_req __user	*arg,
> > +	int				version)
> >  {
> >  	struct xfs_bulk_ireq		hdr;
> >  	struct xfs_ibulk		breq = {
> >  		.mp			= mp,
> > +		.version		= version,
> >  	};
> >  	int				error;
> >  
> > @@ -1882,10 +1897,12 @@ xfs_file_ioctl(
> >  	case XFS_IOC_FSINUMBERS:
> >  		return xfs_ioc_fsbulkstat(filp, cmd, arg);
> >  
> > -	case XFS_IOC_BULKSTAT:
> > -		return xfs_ioc_bulkstat(filp, cmd, arg);
> > +	case XFS_IOC_BULKSTAT_V5:
> > +		return xfs_ioc_bulkstat(filp, cmd, arg,
> > +				XFS_BULKSTAT_VERSION_V5);
> >  	case XFS_IOC_INUMBERS:
> > -		return xfs_ioc_inumbers(mp, cmd, arg);
> > +		return xfs_ioc_inumbers(mp, cmd, arg,
> > +				XFS_INUMBERS_VERSION_V5);
> >  
> >  	case XFS_IOC_FSGEOMETRY_V1:
> >  		return xfs_ioc_fsgeometry(mp, arg, 3);
> > diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
> > index bef19060f4aa..d9a7abc209b5 100644
> > --- a/fs/xfs/xfs_ioctl32.c
> > +++ b/fs/xfs/xfs_ioctl32.c
> > @@ -88,6 +88,8 @@ xfs_fsinumbers_fmt_compat(
> >  	struct xfs_inogrp		ig1;
> >  	struct xfs_inogrp		*igrp = &ig1;
> >  
> > +	ASSERT(breq->version == XFS_INUMBERS_VERSION_V1);
> > +
> >  	xfs_inumbers_to_inogrp(&ig1, ig);
> >  
> >  	if (put_user(igrp->xi_startino,   &p32->xi_startino) ||
> > @@ -177,6 +179,8 @@ xfs_fsbulkstat_one_fmt_compat(
> >  	struct xfs_bstat		bs1;
> >  	struct xfs_bstat		*buffer = &bs1;
> >  
> > +	ASSERT(breq->version == XFS_BULKSTAT_VERSION_V1);
> > +
> >  	xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
> >  
> >  	if (put_user(buffer->bs_ino,	  &p32->bs_ino)		||
> > @@ -293,15 +297,18 @@ xfs_compat_ioc_fsbulkstat(
> >  	 */
> >  	if (cmd == XFS_IOC_FSINUMBERS_32) {
> >  		breq.startino = lastino ? lastino + 1 : 0;
> > +		breq.version = XFS_INUMBERS_VERSION_V1;
> >  		error = xfs_inumbers(&breq, inumbers_func);
> >  		lastino = breq.startino - 1;
> >  	} else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE_32) {
> >  		breq.startino = lastino;
> >  		breq.icount = 1;
> > +		breq.version = XFS_BULKSTAT_VERSION_V1;
> >  		error = xfs_bulkstat_one(&breq, bs_one_func);
> >  		lastino = breq.startino;
> >  	} else if (cmd == XFS_IOC_FSBULKSTAT_32) {
> >  		breq.startino = lastino ? lastino + 1 : 0;
> > +		breq.version = XFS_BULKSTAT_VERSION_V1;
> >  		error = xfs_bulkstat(&breq, bs_one_func);
> >  		lastino = breq.startino - 1;
> >  	} else {
> > diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
> > index 65c194cdea79..f0daa65e61ff 100644
> > --- a/fs/xfs/xfs_itable.c
> > +++ b/fs/xfs/xfs_itable.c
> > @@ -134,7 +134,7 @@ xfs_bulkstat_one_int(
> >  
> >  	buf->bs_xflags = xfs_ip2xflags(ip);
> >  	buf->bs_extsize_blks = ip->i_extsize;
> > -	buf->bs_extents = xfs_ifork_nextents(&ip->i_df);
> > +	buf->bs_extents32 = xfs_ifork_nextents(&ip->i_df);
> >  	xfs_bulkstat_health(ip, buf);
> >  	buf->bs_aextents = xfs_ifork_nextents(ip->i_afp);
> >  	buf->bs_forkoff = XFS_IFORK_BOFF(ip);
> > @@ -356,7 +356,7 @@ xfs_bulkstat_to_bstat(
> >  	bs1->bs_blocks = bstat->bs_blocks;
> >  	bs1->bs_xflags = bstat->bs_xflags;
> >  	bs1->bs_extsize = XFS_FSB_TO_B(mp, bstat->bs_extsize_blks);
> > -	bs1->bs_extents = bstat->bs_extents;
> > +	bs1->bs_extents = bstat->bs_extents32;
> >  	bs1->bs_gen = bstat->bs_gen;
> >  	bs1->bs_projid_lo = bstat->bs_projectid & 0xFFFF;
> >  	bs1->bs_forkoff = bstat->bs_forkoff;
> > diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h
> > index f5a13f69883a..ee4d8d0461ca 100644
> > --- a/fs/xfs/xfs_itable.h
> > +++ b/fs/xfs/xfs_itable.h
> > @@ -14,6 +14,7 @@ struct xfs_ibulk {
> >  	unsigned int		icount;   /* number of elements in ubuffer */
> >  	unsigned int		ocount;   /* number of records returned */
> >  	unsigned int		flags;    /* see XFS_IBULK_FLAG_* */
> > +	int			version;  /* structure version to be returned */
> >  };
> >  
> >  /* Only iterate within the same AG as startino */
> > -- 
> > 2.30.2
> > 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 11/12] xfs: Extend per-inode extent counter widths
  2021-07-26 11:45 ` [PATCH V2 11/12] xfs: Extend per-inode extent counter widths Chandan Babu R
@ 2021-07-27 23:09   ` Darrick J. Wong
  2021-07-28  7:17     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 23:09 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:40PM +0530, Chandan Babu R wrote:
> This commit adds a new 64-bit per-inode data extent counter. However the
> maximum number of extents that a data fork can hold is limited to 2^48
> extents. This feature is available only when
> XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT feature bit is enabled on the
> filesystem. Also, enabling this feature bit causes attr fork extent counter to
> use the 32-bit extent counter that was previously used to hold the data fork
> extent counter. This implies that the attr fork can now occupy a maximum of
> 2^32 extents.
> 
> This commit also exposes the newly introduced XFS_IOC_BULKSTAT_V6 ioctl
> interface to user space.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> ---
>  fs/xfs/libxfs/xfs_bmap.c        |  8 +++-----
>  fs/xfs/libxfs/xfs_format.h      | 27 ++++++++++++++++++++++++---
>  fs/xfs/libxfs/xfs_fs.h          |  1 +
>  fs/xfs/libxfs/xfs_inode_buf.c   | 28 ++++++++++++++++++++++++----
>  fs/xfs/libxfs/xfs_inode_fork.h  | 22 +++++++++++++++++-----
>  fs/xfs/libxfs/xfs_log_format.h  |  3 ++-
>  fs/xfs/scrub/inode_repair.c     | 11 +++++++++--
>  fs/xfs/xfs_inode.c              |  2 +-
>  fs/xfs/xfs_inode_item.c         | 15 +++++++++++++--
>  fs/xfs/xfs_inode_item_recover.c | 25 +++++++++++++++++++------
>  fs/xfs/xfs_ioctl.c              |  3 +++
>  11 files changed, 116 insertions(+), 29 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> index a27d57ea301c..e05898c9acbc 100644
> --- a/fs/xfs/libxfs/xfs_bmap.c
> +++ b/fs/xfs/libxfs/xfs_bmap.c
> @@ -54,18 +54,16 @@ xfs_bmap_compute_maxlevels(
>  	int		whichfork)	/* data or attr fork */
>  {
>  	xfs_extnum_t	maxleafents;	/* max leaf entries possible */
> +	uint64_t	maxblocks;	/* max blocks at this level */

xfs_rfsblock_t?

>  	int		level;		/* btree level */
> -	uint		maxblocks;	/* max blocks at this level */
>  	int		maxrootrecs;	/* max records in root block */
>  	int		minleafrecs;	/* min records in leaf block */
>  	int		minnoderecs;	/* min records in node block */
>  	int		sz;		/* root block size */
>  
>  	/*
> -	 * The maximum number of extents in a file, hence the maximum number of
> -	 * leaf entries, is controlled by the size of the on-disk extent count,
> -	 * either a signed 32-bit number for the data fork, or a signed 16-bit
> -	 * number for the attr fork.
> +	 * The maximum number of extents in a fork, hence the maximum number of
> +	 * leaf entries, is controlled by the size of the on-disk extent count.
>  	 *
>  	 * Note that we can no longer assume that if we are in ATTR1 that the
>  	 * fork offset of all the inodes will be
> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> index 2362cc005cc6..3aa83d75670d 100644
> --- a/fs/xfs/libxfs/xfs_format.h
> +++ b/fs/xfs/libxfs/xfs_format.h
> @@ -485,13 +485,15 @@ xfs_sb_has_ro_compat_feature(
>  #define XFS_SB_FEAT_INCOMPAT_BIGTIME	(1 << 3)	/* large timestamps */
>  #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4)	/* needs xfs_repair */
>  #define XFS_SB_FEAT_INCOMPAT_METADIR	(1 << 5)	/* metadata dir tree */
> -#define XFS_SB_FEAT_INCOMPAT_ALL \
> +#define XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT (1 << 6)	/* 64-bit inode fork extent counter */
> +#define XFS_SB_FEAT_INCOMPAT_ALL		\
>  		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
>  		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
>  		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
>  		 XFS_SB_FEAT_INCOMPAT_BIGTIME| \
>  		 XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \
> -		 XFS_SB_FEAT_INCOMPAT_METADIR)
> +		 XFS_SB_FEAT_INCOMPAT_METADIR| \

Oh hey, this /definitely/ branches off djwong-dev. :)

> +		 XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT)

Hm.  I don't think we're ever going to want to support more than u48
extent counts because that's a lot of memory consumption.  It might be
safe to call this by a shorter name, e.g.

	BIGBMAP?
	SUPERSPARSE?	(no, too long)
	EXT64		(beat that, ext4!)
	NREXT64

I kinda like BIGBMAP since it's actually pronounceable...

>  #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
>  static inline bool
> @@ -591,6 +593,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
>  		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
>  }
>  
> +static inline bool xfs_sb_version_hasextcount_64bit(struct xfs_sb *sbp)
> +{
> +	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
> +		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT);
> +}
> +
>  static inline bool xfs_sb_version_hasrmapbt(struct xfs_sb *sbp)
>  {
>  	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
> @@ -1039,6 +1047,16 @@ typedef struct xfs_dinode {
>  	__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 */
> +
> +	/*
> +	 * On a extcnt64bit filesystem, di_nextents64 holds the data fork
> +	 * extent count, di_nextents32 holds the attr fork extent count,
> +	 * and di_nextents16 must be zero.
> +	 *
> +	 * Otherwise, di_nextents32 holds the data fork extent count,
> +	 * di_nextents16 holds the attr fork extent count, and di_nextents64
> +	 * must be zero.

(See earlier comments about reusing di_pad[6])

> +	 */
>  	__be32		di_nextents32;	/* number of extents in data fork */
>  	__be16		di_nextents16;	/* number of extents in attribute fork*/
>  	__u8		di_forkoff;	/* attr fork offs, <<3 for 64b align */
> @@ -1057,7 +1075,8 @@ typedef struct xfs_dinode {
>  	__be64		di_lsn;		/* flush sequence */
>  	__be64		di_flags2;	/* more random flags */
>  	__be32		di_cowextsize;	/* basic cow extent size for file */
> -	__u8		di_pad2[12];	/* more padding for future expansion */
> +	__u8		di_pad2[4];	/* more padding for future expansion */
> +	__be64		di_nextents64;
>  
>  	/* fields only written to during inode creation */
>  	xfs_timestamp_t	di_crtime;	/* time created */
> @@ -1113,6 +1132,8 @@ enum xfs_dinode_fmt {
>   * Max values for extlen and disk inode's extent counters.
>   */
>  #define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
> +#define XFS_IFORK_EXTCNT_MAXU48	((uint64_t)0xffffffffffff) /* Unsigned 48-bits */
> +#define XFS_IFORK_EXTCNT_MAXU32	((uint32_t)0xffffffff)	/* Unsigned 32-bits */
>  #define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
>  #define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
>  
> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> index 756be4ff5996..57f67445f095 100644
> --- a/fs/xfs/libxfs/xfs_fs.h
> +++ b/fs/xfs/libxfs/xfs_fs.h
> @@ -858,6 +858,7 @@ struct xfs_scrub_metadata {
>  #define XFS_IOC_BULKSTAT_V5	     _IOR ('X', 127, struct xfs_bulkstat_req)
>  #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
>  /*	FIEXCHANGE_RANGE ----------- hoisted 129	 */
> +#define XFS_IOC_BULKSTAT_V6	     _IOR ('X', 130, struct xfs_bulkstat_req)

(See earlier comments about adding flags to xfs_bulk_ireq so we don't
have to rev the ioctl definitions yet again.)

>  /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
>  
>  
> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> index 65d753e16007..28e49394edbb 100644
> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> @@ -291,6 +291,7 @@ xfs_inode_to_disk(
>  	struct xfs_dinode	*to,
>  	xfs_lsn_t		lsn)
>  {
> +	struct xfs_sb		*sbp = &ip->i_mount->m_sb;
>  	struct inode		*inode = VFS_I(ip);
>  
>  	to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
> @@ -313,8 +314,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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
> -	to->di_nextents16 = 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);
> @@ -334,6 +333,19 @@ xfs_inode_to_disk(
>  		to->di_version = 2;
>  		to->di_flushiter = cpu_to_be16(ip->i_flushiter);
>  	}
> +
> +	if (xfs_sb_version_hasextcount_64bit(sbp)) {
> +		to->di_nextents64 = cpu_to_be64(xfs_ifork_nextents(&ip->i_df));
> +		to->di_nextents32 = cpu_to_be32(xfs_ifork_nextents(ip->i_afp));

Hmm, yes, these really should be separate helpers like what we did for
timestamps.

> +		/*
> +		 * xchk_dinode() passes an uninitialized disk inode. Hence,
> +		 * clear di_nextents16 field explicitly.

So fix xchk_dinode.

> +		 */
> +		to->di_nextents16 = cpu_to_be16(0);
> +	} else {
> +		to->di_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
> +		to->di_nextents16 = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
> +	}
>  }
>  
>  static xfs_failaddr_t
> @@ -386,14 +398,22 @@ xfs_dfork_nextents(
>  	xfs_extnum_t		*nextents)
>  {
>  	int			error = 0;
> +	bool			has_64bit_extcnt;
> +
> +	has_64bit_extcnt = xfs_sb_version_hasextcount_64bit(&mp->m_sb);
> +
> +	if (has_64bit_extcnt && dip->di_nextents16 != 0)
> +		return -EFSCORRUPTED;

I think if you follow my suggestions to encode the upper 32/16 bits of
the extent counters in di_pad, the need for error codes (and patch 6) go
away completely.

>  
>  	switch (whichfork) {
>  	case XFS_DATA_FORK:
> -		*nextents = be32_to_cpu(dip->di_nextents32);
> +		*nextents = has_64bit_extcnt ? be64_to_cpu(dip->di_nextents64)
> +			: be32_to_cpu(dip->di_nextents32);
>  		break;
>  
>  	case XFS_ATTR_FORK:
> -		*nextents = be16_to_cpu(dip->di_nextents16);
> +		*nextents = has_64bit_extcnt ? be32_to_cpu(dip->di_nextents32)
> +			: be16_to_cpu(dip->di_nextents16);
>  		break;
>  
>  	default:
> diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
> index 1eda2163603e..ffdd2abcd73c 100644
> --- a/fs/xfs/libxfs/xfs_inode_fork.h
> +++ b/fs/xfs/libxfs/xfs_inode_fork.h
> @@ -21,9 +21,9 @@ struct xfs_ifork {
>  		void		*if_root;	/* extent tree root */
>  		char		*if_data;	/* inline file data */
>  	} if_u1;
> +	xfs_extnum_t		if_nextents;	/* # of extents in this fork */
>  	short			if_broot_bytes;	/* bytes allocated for root */
>  	int8_t			if_format;	/* format of this fork */
> -	xfs_extnum_t		if_nextents;	/* # of extents in this fork */
>  };
>  
>  /*
> @@ -135,10 +135,22 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp)
>  
>  static inline xfs_extnum_t xfs_iext_max(struct xfs_mount *mp, int whichfork)
>  {
> -	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK)
> -		return XFS_IFORK_EXTCNT_MAXS32;
> -	else
> -		return XFS_IFORK_EXTCNT_MAXS16;
> +	bool has_64bit_extcnt = xfs_sb_version_hasextcount_64bit(&mp->m_sb);
> +
> +	switch (whichfork) {
> +	case XFS_DATA_FORK:
> +	case XFS_COW_FORK:
> +		return has_64bit_extcnt ? XFS_IFORK_EXTCNT_MAXU48
> +			: XFS_IFORK_EXTCNT_MAXS32;
> +
> +	case XFS_ATTR_FORK:
> +		return has_64bit_extcnt ? XFS_IFORK_EXTCNT_MAXU32
> +			: XFS_IFORK_EXTCNT_MAXS16;
> +
> +	default:
> +		ASSERT(0);
> +		return 0;
> +	}
>  }
>  
>  struct xfs_ifork *xfs_ifork_alloc(enum xfs_dinode_fmt format,
> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> index ca8e4ad8312a..9b5d64708ed1 100644
> --- a/fs/xfs/libxfs/xfs_log_format.h
> +++ b/fs/xfs/libxfs/xfs_log_format.h
> @@ -420,7 +420,8 @@ struct xfs_log_dinode {
>  	xfs_lsn_t	di_lsn;		/* flush sequence */
>  	uint64_t	di_flags2;	/* more random flags */
>  	uint32_t	di_cowextsize;	/* basic cow extent size for file */
> -	uint8_t		di_pad2[12];	/* more padding for future expansion */
> +	uint8_t		di_pad2[4];	/* more padding for future expansion */
> +	uint64_t	di_nextents64; /* higher part of data fork extent count */

Similarly, I think you should reuse di_pad in the log dinode for the
high bits of the extent count fields.

--D

>  
>  	/* fields only written to during inode creation */
>  	xfs_log_timestamp_t di_crtime;	/* time created */
> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> index 4d773a16f886..dde6b700e891 100644
> --- a/fs/xfs/scrub/inode_repair.c
> +++ b/fs/xfs/scrub/inode_repair.c
> @@ -736,7 +736,10 @@ xrep_dinode_zap_dfork(
>  {
>  	trace_xrep_dinode_zap_dfork(sc, dip);
>  
> -	dip->di_nextents32 = 0;
> +	if (xfs_sb_version_hasextcount_64bit(&sc->mp->m_sb))
> +		dip->di_nextents64 = 0;
> +	else
> +		dip->di_nextents32 = 0;
>  
>  	/* Special files always get reset to DEV */
>  	switch (mode & S_IFMT) {
> @@ -823,7 +826,11 @@ xrep_dinode_zap_afork(
>  	trace_xrep_dinode_zap_afork(sc, dip);
>  
>  	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
> -	dip->di_nextents16 = 0;
> +
> +	if (xfs_sb_version_hasextcount_64bit(&sc->mp->m_sb))
> +		dip->di_nextents32 = 0;
> +	else
> +		dip->di_nextents16 = 0;
>  
>  	dip->di_forkoff = 0;
>  	dip->di_mode = cpu_to_be16(mode & ~0777);
> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
> index 4070fb01350c..19d525093702 100644
> --- a/fs/xfs/xfs_inode.c
> +++ b/fs/xfs/xfs_inode.c
> @@ -2511,7 +2511,7 @@ xfs_iflush(
>  				ip->i_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
>  		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
>  			"%s: detected corrupt incore inode %llu, "
> -			"total extents = %llu nblocks = %lld, ptr "PTR_FMT,
> +			"total extents = %llu, nblocks = %lld, ptr "PTR_FMT,
>  			__func__, ip->i_ino,
>  			ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp),
>  			ip->i_nblocks, ip);
> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
> index f54ce7468ba1..3fa73100484b 100644
> --- a/fs/xfs/xfs_inode_item.c
> +++ b/fs/xfs/xfs_inode_item.c
> @@ -364,6 +364,7 @@ xfs_inode_to_log_dinode(
>  	struct xfs_log_dinode	*to,
>  	xfs_lsn_t		lsn)
>  {
> +	struct xfs_sb		*sbp = &ip->i_mount->m_sb;
>  	struct inode		*inode = VFS_I(ip);
>  
>  	to->di_magic = XFS_DINODE_MAGIC;
> @@ -385,8 +386,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_nextents32 = xfs_ifork_nextents(&ip->i_df);
> -	to->di_nextents16 = 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;
> @@ -402,6 +401,16 @@ xfs_inode_to_log_dinode(
>  		to->di_crtime = xfs_inode_to_log_dinode_ts(ip, ip->i_crtime);
>  		to->di_flags2 = ip->i_diflags2;
>  		to->di_cowextsize = ip->i_cowextsize;
> +		if (xfs_sb_version_hasextcount_64bit(sbp)) {
> +			to->di_nextents64 = xfs_ifork_nextents(&ip->i_df);
> +			to->di_nextents32 = xfs_ifork_nextents(ip->i_afp);
> +			to->di_nextents16 = 0;
> +		} else {
> +			to->di_nextents64 = 0;
> +			to->di_nextents32 = xfs_ifork_nextents(&ip->i_df);
> +			to->di_nextents16 = xfs_ifork_nextents(ip->i_afp);
> +		}
> +
>  		to->di_ino = ip->i_ino;
>  		to->di_lsn = lsn;
>  		memset(to->di_pad2, 0, sizeof(to->di_pad2));
> @@ -410,6 +419,8 @@ xfs_inode_to_log_dinode(
>  	} else {
>  		to->di_version = 2;
>  		to->di_flushiter = ip->i_flushiter;
> +		to->di_nextents32 = xfs_ifork_nextents(&ip->i_df);
> +		to->di_nextents16 = xfs_ifork_nextents(ip->i_afp);
>  	}
>  }
>  
> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
> index 40af9d1265c7..fcf360c03bc1 100644
> --- a/fs/xfs/xfs_inode_item_recover.c
> +++ b/fs/xfs/xfs_inode_item_recover.c
> @@ -166,8 +166,6 @@ xfs_log_dinode_to_disk(
>  	to->di_size = cpu_to_be64(from->di_size);
>  	to->di_nblocks = cpu_to_be64(from->di_nblocks);
>  	to->di_extsize = cpu_to_be32(from->di_extsize);
> -	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
> -	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>  	to->di_forkoff = from->di_forkoff;
>  	to->di_aformat = from->di_aformat;
>  	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
> @@ -181,12 +179,17 @@ xfs_log_dinode_to_disk(
>  							  from->di_crtime);
>  		to->di_flags2 = cpu_to_be64(from->di_flags2);
>  		to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
> +		to->di_nextents64 = cpu_to_be64(from->di_nextents64);
> +		to->di_nextents32 = cpu_to_be32(from->di_nextents32);
> +		to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>  		to->di_ino = cpu_to_be64(from->di_ino);
>  		to->di_lsn = cpu_to_be64(from->di_lsn);
>  		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
>  		uuid_copy(&to->di_uuid, &from->di_uuid);
>  		to->di_flushiter = 0;
>  	} else {
> +		to->di_nextents32 = cpu_to_be32(from->di_nextents32);
> +		to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>  		to->di_flushiter = cpu_to_be16(from->di_flushiter);
>  	}
>  }
> @@ -202,6 +205,8 @@ xlog_recover_inode_commit_pass2(
>  	struct xfs_mount		*mp = log->l_mp;
>  	struct xfs_buf			*bp;
>  	struct xfs_dinode		*dip;
> +	xfs_extnum_t                    nextents;
> +	xfs_aextnum_t                   anextents;
>  	int				len;
>  	char				*src;
>  	char				*dest;
> @@ -332,16 +337,24 @@ xlog_recover_inode_commit_pass2(
>  			goto out_release;
>  		}
>  	}
> -	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
> +
> +	if (xfs_sb_version_hasextcount_64bit(&mp->m_sb)) {
> +		nextents = ldip->di_nextents64;
> +		anextents = ldip->di_nextents32;
> +	} else {
> +		nextents = ldip->di_nextents32;
> +		anextents = ldip->di_nextents16;
> +	}
> +
> +	if (unlikely(nextents + anextents > ldip->di_nblocks)) {
>  		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
>  				     XFS_ERRLEVEL_LOW, mp, ldip,
>  				     sizeof(*ldip));
>  		xfs_alert(mp,
>  	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
> -	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
> +	"dino bp "PTR_FMT", ino %Ld, total extents = %llu, nblocks = %Ld",
>  			__func__, item, dip, bp, in_f->ilf_ino,
> -			ldip->di_nextents32 + ldip->di_nextents16,
> -			ldip->di_nblocks);
> +			nextents + anextents, ldip->di_nblocks);
>  		error = -EFSCORRUPTED;
>  		goto out_release;
>  	}
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 19964b394dc4..2d44aa655f41 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -1901,6 +1901,9 @@ xfs_file_ioctl(
>  	case XFS_IOC_BULKSTAT_V5:
>  		return xfs_ioc_bulkstat(filp, cmd, arg,
>  				XFS_BULKSTAT_VERSION_V5);
> +	case XFS_IOC_BULKSTAT_V6:
> +		return xfs_ioc_bulkstat(filp, cmd, arg,
> +				XFS_BULKSTAT_VERSION_V6);
>  	case XFS_IOC_INUMBERS:
>  		return xfs_ioc_inumbers(mp, cmd, arg,
>  				XFS_INUMBERS_VERSION_V5);
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count
  2021-07-26 11:45 ` [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count Chandan Babu R
@ 2021-07-27 23:10   ` Darrick J. Wong
  2021-07-28  7:23     ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-27 23:10 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:41PM +0530, Chandan Babu R wrote:
> This commit adds a new error tag to allow user space tests to check if V5
> bulkstat ioctl skips reporting inodes with large extent count.
> 
> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>

Keep in mind that each of these injection knobs costs us 4 bytes per
mount.  No particular objections, but I don't know how urgently we need
to do that to test a corner case...

Reviewed-by: Darrick J. Wong <djwong@kernel.org>

--D

> ---
>  fs/xfs/libxfs/xfs_errortag.h | 4 +++-
>  fs/xfs/xfs_error.c           | 3 +++
>  fs/xfs/xfs_itable.c          | 9 ++++++++-
>  3 files changed, 14 insertions(+), 2 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_errortag.h b/fs/xfs/libxfs/xfs_errortag.h
> index f5fa2151e05d..b2c533153737 100644
> --- a/fs/xfs/libxfs/xfs_errortag.h
> +++ b/fs/xfs/libxfs/xfs_errortag.h
> @@ -60,7 +60,8 @@
>  #define XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT		37
>  #define XFS_ERRTAG_AG_RESV_FAIL				38
>  #define XFS_ERRTAG_SWAPEXT_FINISH_ONE			39
> -#define XFS_ERRTAG_MAX					40
> +#define XFS_ERRTAG_BULKSTAT_REDUCE_MAX_IEXTENTS		40
> +#define XFS_ERRTAG_MAX					41
>  
>  /*
>   * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
> @@ -105,5 +106,6 @@
>  #define XFS_RANDOM_BMAP_ALLOC_MINLEN_EXTENT		1
>  #define XFS_RANDOM_AG_RESV_FAIL				1
>  #define XFS_RANDOM_SWAPEXT_FINISH_ONE			1
> +#define XFS_RANDOM_BULKSTAT_REDUCE_MAX_IEXTENTS		1
>  
>  #endif /* __XFS_ERRORTAG_H_ */
> diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c
> index e25b440cbfd3..e2a9446fb025 100644
> --- a/fs/xfs/xfs_error.c
> +++ b/fs/xfs/xfs_error.c
> @@ -58,6 +58,7 @@ static unsigned int xfs_errortag_random_default[] = {
>  	XFS_RANDOM_BMAP_ALLOC_MINLEN_EXTENT,
>  	XFS_RANDOM_AG_RESV_FAIL,
>  	XFS_RANDOM_SWAPEXT_FINISH_ONE,
> +	XFS_RANDOM_BULKSTAT_REDUCE_MAX_IEXTENTS,
>  };
>  
>  struct xfs_errortag_attr {
> @@ -172,6 +173,7 @@ XFS_ERRORTAG_ATTR_RW(reduce_max_iextents,	XFS_ERRTAG_REDUCE_MAX_IEXTENTS);
>  XFS_ERRORTAG_ATTR_RW(bmap_alloc_minlen_extent,	XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT);
>  XFS_ERRORTAG_ATTR_RW(ag_resv_fail, XFS_ERRTAG_AG_RESV_FAIL);
>  XFS_ERRORTAG_ATTR_RW(swapext_finish_one, XFS_RANDOM_SWAPEXT_FINISH_ONE);
> +XFS_ERRORTAG_ATTR_RW(bulkstat_reduce_max_iextents, XFS_ERRTAG_BULKSTAT_REDUCE_MAX_IEXTENTS);
>  
>  static struct attribute *xfs_errortag_attrs[] = {
>  	XFS_ERRORTAG_ATTR_LIST(noerror),
> @@ -214,6 +216,7 @@ static struct attribute *xfs_errortag_attrs[] = {
>  	XFS_ERRORTAG_ATTR_LIST(bmap_alloc_minlen_extent),
>  	XFS_ERRORTAG_ATTR_LIST(ag_resv_fail),
>  	XFS_ERRORTAG_ATTR_LIST(swapext_finish_one),
> +	XFS_ERRORTAG_ATTR_LIST(bulkstat_reduce_max_iextents),
>  	NULL,
>  };
>  
> diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c
> index 8493870a0a87..1b252d1cda9d 100644
> --- a/fs/xfs/xfs_itable.c
> +++ b/fs/xfs/xfs_itable.c
> @@ -20,6 +20,7 @@
>  #include "xfs_icache.h"
>  #include "xfs_health.h"
>  #include "xfs_trans.h"
> +#include "xfs_errortag.h"
>  
>  /*
>   * Bulk Stat
> @@ -143,7 +144,13 @@ xfs_bulkstat_one_int(
>  
>  	nextents = xfs_ifork_nextents(&ip->i_df);
>  	if (bc->breq->version != XFS_BULKSTAT_VERSION_V6) {
> -		if (nextents > XFS_IFORK_EXTCNT_MAXS32) {
> +		xfs_extnum_t max_nextents = XFS_IFORK_EXTCNT_MAXS32;
> +
> +		if (unlikely(XFS_TEST_ERROR(false, mp,
> +				XFS_ERRTAG_BULKSTAT_REDUCE_MAX_IEXTENTS)))
> +			max_nextents = 10;
> +
> +		if (nextents > max_nextents) {
>  			xfs_iunlock(ip, XFS_ILOCK_SHARED);
>  			xfs_irele(ip);
>  			error = -EINVAL;
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
  2021-07-27 23:00     ` Darrick J. Wong
@ 2021-07-27 23:17       ` Dave Chinner
  2021-07-28  6:56         ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Dave Chinner @ 2021-07-27 23:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: Chandan Babu R, linux-xfs

On Tue, Jul 27, 2021 at 04:00:02PM -0700, Darrick J. Wong wrote:
> On Tue, Jul 27, 2021 at 03:54:00PM -0700, Darrick J. Wong wrote:
> > On Mon, Jul 26, 2021 at 05:15:38PM +0530, Chandan Babu R wrote:
> > > This commit renames XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 to allow a future
> > > commit to extend bulkstat facility to support 64-bit extent counters. To this
> > > end, this commit also renames xfs_bulkstat->bs_extents field to
> > > xfs_bulkstat->bs_extents32.
> > > 
> > > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> > > ---
> > >  fs/xfs/libxfs/xfs_fs.h |  4 ++--
> > >  fs/xfs/xfs_ioctl.c     | 27 ++++++++++++++++++++++-----
> > >  fs/xfs/xfs_ioctl32.c   |  7 +++++++
> > >  fs/xfs/xfs_itable.c    |  4 ++--
> > >  fs/xfs/xfs_itable.h    |  1 +
> > >  5 files changed, 34 insertions(+), 9 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
> > > index 2594fb647384..d760a969599e 100644
> > > --- a/fs/xfs/libxfs/xfs_fs.h
> > > +++ b/fs/xfs/libxfs/xfs_fs.h
> > > @@ -394,7 +394,7 @@ struct xfs_bulkstat {
> > >  	uint32_t	bs_extsize_blks; /* extent size hint, blocks	*/
> > >  
> > >  	uint32_t	bs_nlink;	/* number of links		*/
> > > -	uint32_t	bs_extents;	/* number of extents		*/
> > > +	uint32_t	bs_extents32;	/* number of extents		*/
> > 
> > I wish I'd thought of this when we introduced bulkstat v5 so you
> > wouldn't have had to do this.
> > 
> > (I might have more to say in the bulkstat v6 patch review.)
> > Reviewed-by: Darrick J. Wong <djwong@kernel.org>
> 
> Actually, I take that back, I have things to say /now/. :)
> 
> Rather than adding a whole new ioctl definition which (I haven't looked
> at the xfsprogs changes) likely creates a bunch of churn in userspace,
> what if we added a XFS_IBULK_ flag for supporting large extent counts?
> There's also quite a bit of reserved padding space in xfs_bulk_ireq, so
> perhaps we should define one of those padding u64 as a op-specific flag
> field that would be a way to pass bulkstat-specific flags to the
> relevant operations.  That way the 64-bit extent counts are merely a
> variant on bulkstat v5 instead of a whole new format.

Yup, this.

The only reason for creating a new revision of the ioctl is if we've
run out of expansion space in the existing ioctl structures to cater
for new information we want to export to userspace.

Cheers,

Dave.
-- 
Dave Chinner
david@fromorbit.com

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-07-27 22:03     ` Darrick J. Wong
@ 2021-07-28  3:15       ` Chandan Babu R
  2021-08-23  4:18         ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  3:15 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 03:33, Darrick J. Wong wrote:
> On Tue, Jul 27, 2021 at 02:56:11PM -0700, Darrick J. Wong wrote:
>> On Mon, Jul 26, 2021 at 05:15:31PM +0530, Chandan Babu R wrote:
>> > In preparation for introducing larger extent count limits, this commit renames
>> > existing extent count limits based on their signedness and width.
>> > 
>> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> > ---
>> >  fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
>> >  fs/xfs/libxfs/xfs_format.h     | 8 ++++----
>> >  fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
>> >  fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
>> >  fs/xfs/scrub/inode_repair.c    | 2 +-
>> >  5 files changed, 11 insertions(+), 10 deletions(-)
>> > 
>> > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>> > index f3c9a0ebb0a5..8f262405a5b5 100644
>> > --- a/fs/xfs/libxfs/xfs_bmap.c
>> > +++ b/fs/xfs/libxfs/xfs_bmap.c
>> > @@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
>> >  	 * available.
>> >  	 */
>> >  	if (whichfork == XFS_DATA_FORK) {
>> > -		maxleafents = MAXEXTNUM;
>> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
>> 
>> I'm not in love with these names, since they tell me roughly about the
>> size of the constant (which I could glean from the definition) but less
>> about when I would expect to find them.  How about:
>> 
>> #define XFS_MAX_DFORK_NEXTENTS    ((xfs_extnum_t) 0x7FFFFFFF)
>> #define XFS_MAX_AFORK_NEXTENTS    ((xfs_aextnum_t)0x00007FFF)
>
> Or, given that 'DFORK' already means 'ondisk fork', how about:
>
> XFS_MAX_DATA_NEXTENTS
> XFS_MAX_ATTR_NEXTENTS

Yes, I agree. These names are better. I will incorporate your suggestions
before posting V3.

>
> ?
>
> --D
>
>> 
>> and when we get to the iext64 feature (or whatever we end up calling it)
>> then we can define new ones:
>> 
>> #define XFS_MAX_DFORK_NEXTENTS64  ((xfs_extnum_t) 0xFFFFFFFFFFFF)
>> #define XFS_MAX_AFORK_NEXTENTS64  ((xfs_aextnum_t)0x0000FFFFFFFF)
>> 
>> or something like that.
>> 
>> >  		sz = xfs_bmdr_space_calc(MINDBTPTRS);
>> >  	} else {
>> > -		maxleafents = MAXAEXTNUM;
>> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS16;
>> >  		sz = xfs_bmdr_space_calc(MINABTPTRS);
>> >  	}
>> >  	maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
>> > diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> > index 37cca918d2ba..920e3f9c418f 100644
>> > --- a/fs/xfs/libxfs/xfs_format.h
>> > +++ b/fs/xfs/libxfs/xfs_format.h
>> > @@ -1110,11 +1110,11 @@ enum xfs_dinode_fmt {
>> >  	{ XFS_DINODE_FMT_UUID,		"uuid" }
>> >  
>> >  /*
>> > - * Max values for extlen, extnum, aextnum.
>> > + * Max values for extlen and disk inode's extent counters.
>> >   */
>> > -#define	MAXEXTLEN	((uint32_t)0x001fffff)	/* 21 bits */
>> 
>> As for MAXEXTLEN... would you mind tacking a new patch on the end to fix
>> its definition as well?  It /really/ ought to be based on the disk
>> format definitions and not open-coded.
>> 
>> #define XFS_MAX_EXTLEN		((xfs_extlen_t)(1 << BMBT_BLOCKCOUNT_BITLEN) - 1)
>> 
>> --D
>> 
>> > -#define	MAXEXTNUM	((int32_t)0x7fffffff)	/* signed int */
>> > -#define	MAXAEXTNUM	((int16_t)0x7fff)	/* signed short */
>> > +#define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
>> > +#define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
>> > +#define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
>> >  
>> >  /*
>> >   * Inode minimum and maximum sizes.
>> > diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> > index 5625df1ddd95..66d13e8fa420 100644
>> > --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> > +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> > @@ -365,9 +365,9 @@ xfs_dinode_verify_fork(
>> >  		break;
>> >  	case XFS_DINODE_FMT_BTREE:
>> >  		if (whichfork == XFS_ATTR_FORK) {
>> > -			if (di_nextents > MAXAEXTNUM)
>> > +			if (di_nextents > XFS_IFORK_EXTCNT_MAXS16)
>> >  				return __this_address;
>> > -		} else if (di_nextents > MAXEXTNUM) {
>> > +		} else if (di_nextents > XFS_IFORK_EXTCNT_MAXS32) {
>> >  			return __this_address;
>> >  		}
>> >  		break;
>> > diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
>> > index 801a6f7dbd0c..6f4b14d3d381 100644
>> > --- a/fs/xfs/libxfs/xfs_inode_fork.c
>> > +++ b/fs/xfs/libxfs/xfs_inode_fork.c
>> > @@ -736,7 +736,8 @@ xfs_iext_count_may_overflow(
>> >  	if (whichfork == XFS_COW_FORK)
>> >  		return 0;
>> >  
>> > -	max_exts = (whichfork == XFS_ATTR_FORK) ? MAXAEXTNUM : MAXEXTNUM;
>> > +	max_exts = (whichfork == XFS_ATTR_FORK) ?
>> > +		XFS_IFORK_EXTCNT_MAXS16 : XFS_IFORK_EXTCNT_MAXS32;
>> >  
>> >  	if (XFS_TEST_ERROR(false, ip->i_mount, XFS_ERRTAG_REDUCE_MAX_IEXTENTS))
>> >  		max_exts = 10;
>> > diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
>> > index a80cd633fe59..c44f8d06939b 100644
>> > --- a/fs/xfs/scrub/inode_repair.c
>> > +++ b/fs/xfs/scrub/inode_repair.c
>> > @@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
>> >  			return error;
>> >  		if (count >= sc->mp->m_sb.sb_dblocks)
>> >  			return -EFSCORRUPTED;
>> > -		if (nextents >= MAXAEXTNUM)
>> > +		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
>> >  			return -EFSCORRUPTED;
>> >  		ifp->if_nextents = nextents;
>> >  	} else {
>> > -- 
>> > 2.30.2
>> > 


-- 
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper
  2021-07-27 21:58   ` Darrick J. Wong
@ 2021-07-28  3:17     ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  3:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 03:28, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:32PM +0530, Chandan Babu R wrote:
>> xfs_iext_max() returns the maximum number of extents possible for one of
>> data, cow or attribute fork. This helper will be extended further in a
>> future commit when maximum extent counts associated with data/attribute
>> forks are increased.
>> 
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> ---
>>  fs/xfs/libxfs/xfs_bmap.c       | 9 ++++-----
>>  fs/xfs/libxfs/xfs_inode_buf.c  | 8 +++-----
>>  fs/xfs/libxfs/xfs_inode_fork.c | 6 +++---
>>  fs/xfs/libxfs/xfs_inode_fork.h | 8 ++++++++
>>  fs/xfs/scrub/inode_repair.c    | 2 +-
>>  5 files changed, 19 insertions(+), 14 deletions(-)
>> 
>
> <snip>
>
>> diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
>> index cf82be263b48..1eda2163603e 100644
>> --- a/fs/xfs/libxfs/xfs_inode_fork.h
>> +++ b/fs/xfs/libxfs/xfs_inode_fork.h
>> @@ -133,6 +133,14 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp)
>>  	return ifp->if_format;
>>  }
>>  
>> +static inline xfs_extnum_t xfs_iext_max(struct xfs_mount *mp, int whichfork)
>
> xfs_iext_max_nextents() to go with the constants?  "max" on its own is a
> little vague.  I /really/ like this getting cleaned up finally though.
>

Ok. I will rename the function as per your suggestion.

>> +{
>> +	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK)
>> +		return XFS_IFORK_EXTCNT_MAXS32;
>> +	else
>> +		return XFS_IFORK_EXTCNT_MAXS16;
>
> No need for the 'else'.

Sure. I will fix it up.

>
> --D
>
>> +}
>> +
>>  struct xfs_ifork *xfs_ifork_alloc(enum xfs_dinode_fmt format,
>>  				xfs_extnum_t nextents);
>>  struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state);
>> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
>> index c44f8d06939b..a44d7b48c374 100644
>> --- a/fs/xfs/scrub/inode_repair.c
>> +++ b/fs/xfs/scrub/inode_repair.c
>> @@ -1198,7 +1198,7 @@ xrep_inode_blockcounts(
>>  			return error;
>>  		if (count >= sc->mp->m_sb.sb_dblocks)
>>  			return -EFSCORRUPTED;
>> -		if (nextents >= XFS_IFORK_EXTCNT_MAXS16)
>> +		if (nextents >= xfs_iext_max(sc->mp, XFS_ATTR_FORK))
>>  			return -EFSCORRUPTED;
>>  		ifp->if_nextents = nextents;
>>  	} else {
>> -- 
>> 2.30.2
>> 


-- 
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types
  2021-07-27 21:59   ` Darrick J. Wong
@ 2021-07-28  3:38     ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  3:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 03:29, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:33PM +0530, Chandan Babu R wrote:
>> xfs_extnum_t is the type to use to declare variables which have values
>> obtained from xfs_dinode->di_[a]nextents. This commit replaces basic
>> types (e.g. uint32_t) with xfs_extnum_t for such variables.
>>
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>
> Not sure why the structure members change places, but otherwise LGTM.

The re-arrangement of local variables was supposed to happen in the patch
where "xfs_[a]extnum_t" get promoted to larger data types. I will make those
movements happen in that patch.

>
> Reviewed-by: Darrick J. Wong <djwong@kernel.org>

Thanks for the review.

>
> --D
>
>
>> ---
>>  fs/xfs/libxfs/xfs_bmap.c       | 2 +-
>>  fs/xfs/libxfs/xfs_inode_buf.c  | 2 +-
>>  fs/xfs/libxfs/xfs_inode_fork.c | 2 +-
>>  fs/xfs/scrub/inode.c           | 2 +-
>>  fs/xfs/scrub/inode_repair.c    | 2 +-
>>  fs/xfs/xfs_trace.h             | 2 +-
>>  6 files changed, 6 insertions(+), 6 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>> index 282aeb3c0e49..e5d243fd187d 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.c
>> +++ b/fs/xfs/libxfs/xfs_bmap.c
>> @@ -53,9 +53,9 @@ xfs_bmap_compute_maxlevels(
>>  	xfs_mount_t	*mp,		/* file system mount structure */
>>  	int		whichfork)	/* data or attr fork */
>>  {
>> +	xfs_extnum_t	maxleafents;	/* max leaf entries possible */
>>  	int		level;		/* btree level */
>>  	uint		maxblocks;	/* max blocks at this level */
>> -	uint		maxleafents;	/* max leaf entries possible */
>>  	int		maxrootrecs;	/* max records in root block */
>>  	int		minleafrecs;	/* min records in leaf block */
>>  	int		minnoderecs;	/* min records in node block */
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> index 419b92dc6ac8..cba9a38f3270 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> @@ -342,7 +342,7 @@ xfs_dinode_verify_fork(
>>  	struct xfs_mount	*mp,
>>  	int			whichfork)
>>  {
>> -	uint32_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
>> +	xfs_extnum_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
>>  	xfs_extnum_t		max_extents;
>>
>>  	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
>> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
>> index c6856ec95335..a1e40df585a3 100644
>> --- a/fs/xfs/libxfs/xfs_inode_fork.c
>> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
>> @@ -107,7 +107,7 @@ xfs_iformat_extents(
>>  	struct xfs_mount	*mp = ip->i_mount;
>>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>>  	int			state = xfs_bmap_fork_to_state(whichfork);
>> -	int			nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>> +	xfs_extnum_t		nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>>  	int			size = nex * sizeof(xfs_bmbt_rec_t);
>>  	struct xfs_iext_cursor	icur;
>>  	struct xfs_bmbt_rec	*dp;
>> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
>> index e6068590484b..246d11ca133f 100644
>> --- a/fs/xfs/scrub/inode.c
>> +++ b/fs/xfs/scrub/inode.c
>> @@ -219,7 +219,7 @@ xchk_dinode(
>>  	size_t			fork_recs;
>>  	unsigned long long	isize;
>>  	uint64_t		flags2;
>> -	uint32_t		nextents;
>> +	xfs_extnum_t		nextents;
>>  	prid_t			prid;
>>  	uint16_t		flags;
>>  	uint16_t		mode;
>> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
>> index a44d7b48c374..042c7d0bc0f5 100644
>> --- a/fs/xfs/scrub/inode_repair.c
>> +++ b/fs/xfs/scrub/inode_repair.c
>> @@ -597,9 +597,9 @@ xrep_dinode_bad_extents_fork(
>>  {
>>  	struct xfs_bmbt_irec	new;
>>  	struct xfs_bmbt_rec	*dp;
>> +	xfs_extnum_t		nex;
>>  	bool			isrt;
>>  	int			i;
>> -	int			nex;
>>  	int			fork_size;
>>
>>  	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>> diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
>> index affc9b5834fb..5ed11f894f79 100644
>> --- a/fs/xfs/xfs_trace.h
>> +++ b/fs/xfs/xfs_trace.h
>> @@ -2338,7 +2338,7 @@ DECLARE_EVENT_CLASS(xfs_swap_extent_class,
>>  		__field(int, which)
>>  		__field(xfs_ino_t, ino)
>>  		__field(int, format)
>> -		__field(int, nex)
>> +		__field(xfs_extnum_t, nex)
>>  		__field(int, broot_size)
>>  		__field(int, fork_off)
>>  	),
>> --
>> 2.30.2
>>


--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper
  2021-07-27 22:10   ` Darrick J. Wong
@ 2021-07-28  4:06     ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  4:06 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 03:40, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:34PM +0530, Chandan Babu R wrote:
>> This commit replaces the macro XFS_DFORK_NEXTENTS() with the helper function
>> xfs_dfork_nextents(). As of this commit, xfs_dfork_nextents() returns the same
>> value as XFS_DFORK_NEXTENTS(). A future commit which extends inode's extent
>
> Yay fewer shouty macros!
>
>> counter fields will add more logic to this helper.
>>
>> This commit also replaces direct accesses to xfs_dinode->di_[a]nextents
>> with calls to xfs_dfork_nextents().
>>
>> No functional changes have been made.
>>
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> ---
>>  fs/xfs/libxfs/xfs_format.h     |  4 ----
>>  fs/xfs/libxfs/xfs_inode_buf.c  | 41 +++++++++++++++++++++++++++++-----
>>  fs/xfs/libxfs/xfs_inode_buf.h  |  2 ++
>>  fs/xfs/libxfs/xfs_inode_fork.c | 12 ++++++----
>>  fs/xfs/scrub/inode.c           | 19 +++++++++-------
>>  fs/xfs/scrub/inode_repair.c    | 38 +++++++++++++++++++------------
>>  6 files changed, 81 insertions(+), 35 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 920e3f9c418f..001a4077a7c6 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -1166,10 +1166,6 @@ enum xfs_dinode_fmt {
>>  	((w) == XFS_DATA_FORK ? \
>>  		(dip)->di_format : \
>>  		(dip)->di_aformat)
>> -#define XFS_DFORK_NEXTENTS(dip,w) \
>> -	((w) == XFS_DATA_FORK ? \
>> -		be32_to_cpu((dip)->di_nextents) : \
>> -		be16_to_cpu((dip)->di_anextents))
>>
>>  /*
>>   * For block and character special files the 32bit dev_t is stored at the
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> index cba9a38f3270..6bef0757fca4 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> @@ -342,9 +342,11 @@ xfs_dinode_verify_fork(
>>  	struct xfs_mount	*mp,
>>  	int			whichfork)
>>  {
>> -	xfs_extnum_t		di_nextents = XFS_DFORK_NEXTENTS(dip, whichfork);
>> +	xfs_extnum_t		di_nextents;
>>  	xfs_extnum_t		max_extents;
>>
>> +	di_nextents = xfs_dfork_nextents(mp, dip, whichfork);
>> +
>>  	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
>>  	case XFS_DINODE_FMT_LOCAL:
>>  		/*
>> @@ -375,6 +377,31 @@ xfs_dinode_verify_fork(
>>  	return NULL;
>>  }
>>
>> +xfs_extnum_t
>> +xfs_dfork_nextents(
>> +	struct xfs_mount	*mp,
>> +	struct xfs_dinode	*dip,
>> +	int			whichfork)
>> +{
>> +	xfs_extnum_t		nextents = 0;
>> +
>> +	switch (whichfork) {
>> +	case XFS_DATA_FORK:
>> +		nextents = be32_to_cpu(dip->di_nextents);
>> +		break;
>> +
>> +	case XFS_ATTR_FORK:
>> +		nextents = be16_to_cpu(dip->di_anextents);
>> +		break;
>> +
>> +	default:
>> +		ASSERT(0);
>> +		break;
>> +	}
>> +
>> +	return nextents;
>> +}
>
> This could be a static inline function taking the place of
> XFS_DFORK_NEXTENTS instead of another new function with a stack frame,
> etc:
>
> static inline xfs_extnum_t
> xfs_dfork_nextents(
> 	struct xfs_mount	*mp,
> 	struct xfs_dinode	*dip,
> 	int			whichfork)
> {
> 	switch (whichfork) {
> 	case XFS_DATA_FORK:
> 		return be32_to_cpu(dip->di_nextents);
> 	case XFS_ATTR_FORK:
> 		return be16_to_cpu(dip->di_anextents);
> 	default:
> 		ASSERT(0);
> 		return 0;
> 	}
> }
>

I initially tried implementing this as an inline function defined in
xfs_format.h. However, this results in compilation issues since the definition
of 'struct xfs_mount' isn't available.

I could get it working by changing the first argument to 'struct xfs_sb *sbp'
and get each call to pass a pointer to the xfs super block. However that
results in many calls having the first argument mentioned as
"xfs_dfork_nextents(&mp->m_sb, ...);". I think the benefit of saving stack
space beats the inconvenience of having to explicitly write mp->m_sb in calls
to xfs_dfork_nextents().


>> +
>>  static xfs_failaddr_t
>>  xfs_dinode_verify_forkoff(
>>  	struct xfs_dinode	*dip,
>> @@ -474,6 +501,8 @@ xfs_dinode_verify(
>>  	uint16_t		flags;
>>  	uint64_t		flags2;
>>  	uint64_t		di_size;
>> +	xfs_extnum_t            nextents;
>> +	int64_t			nblocks;
>
> xfs_rfsblock_t, since that's the type we use for nblocks in xfs_inode.

Ok. I will fix it.
>
>>
>>  	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
>>  		return __this_address;
>> @@ -504,10 +533,12 @@ xfs_dinode_verify(
>>  	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
>>  		return __this_address;
>>
>> +	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>> +	nextents += xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
>> +	nblocks = be64_to_cpu(dip->di_nblocks);
>> +
>>  	/* Fork checks carried over from xfs_iformat_fork */
>> -	if (mode &&
>> -	    be32_to_cpu(dip->di_nextents) + be16_to_cpu(dip->di_anextents) >
>> -			be64_to_cpu(dip->di_nblocks))
>> +	if (mode && nextents > nblocks)
>>  		return __this_address;
>>
>>  	if (mode && XFS_DFORK_BOFF(dip) > mp->m_sb.sb_inodesize)
>> @@ -564,7 +595,7 @@ xfs_dinode_verify(
>>  		default:
>>  			return __this_address;
>>  		}
>> -		if (dip->di_anextents)
>> +		if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
>>  			return __this_address;
>>  	}
>>
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
>> index a30b7676098a..ea2c35091609 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.h
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
>> @@ -36,6 +36,8 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
>>  xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
>>  		uint32_t cowextsize, uint16_t mode, uint16_t flags,
>>  		uint64_t flags2);
>> +xfs_extnum_t xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
>> +		int whichfork);
>>
>>  static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
>>  {
>> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
>> index a1e40df585a3..38dd2dfc31fa 100644
>> --- a/fs/xfs/libxfs/xfs_inode_fork.c
>> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
>> @@ -107,7 +107,7 @@ xfs_iformat_extents(
>>  	struct xfs_mount	*mp = ip->i_mount;
>>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>>  	int			state = xfs_bmap_fork_to_state(whichfork);
>> -	xfs_extnum_t		nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>> +	xfs_extnum_t		nex = xfs_dfork_nextents(mp, dip, whichfork);
>>  	int			size = nex * sizeof(xfs_bmbt_rec_t);
>>  	struct xfs_iext_cursor	icur;
>>  	struct xfs_bmbt_rec	*dp;
>> @@ -226,6 +226,7 @@ xfs_iformat_data_fork(
>>  	struct xfs_inode	*ip,
>>  	struct xfs_dinode	*dip)
>>  {
>> +	struct xfs_mount	*mp = ip->i_mount;
>>  	struct inode		*inode = VFS_I(ip);
>>  	int			error;
>>
>> @@ -234,7 +235,7 @@ xfs_iformat_data_fork(
>>  	 * depend on it.
>>  	 */
>>  	ip->i_df.if_format = dip->di_format;
>> -	ip->i_df.if_nextents = be32_to_cpu(dip->di_nextents);
>> +	ip->i_df.if_nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>>
>>  	switch (inode->i_mode & S_IFMT) {
>>  	case S_IFIFO:
>> @@ -301,14 +302,17 @@ xfs_iformat_attr_fork(
>>  	struct xfs_inode	*ip,
>>  	struct xfs_dinode	*dip)
>>  {
>> +	struct xfs_mount	*mp = ip->i_mount;
>> +	xfs_extnum_t		nextents;
>
> naextents for consistency?

Ok. I will fix it.

>
>>  	int			error = 0;
>>
>> +	nextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
>> +
>>  	/*
>>  	 * Initialize the extent count early, as the per-format routines may
>>  	 * depend on it.
>>  	 */
>> -	ip->i_afp = xfs_ifork_alloc(dip->di_aformat,
>> -				be16_to_cpu(dip->di_anextents));
>> +	ip->i_afp = xfs_ifork_alloc(dip->di_aformat, nextents);
>>
>>  	switch (ip->i_afp->if_format) {
>>  	case XFS_DINODE_FMT_LOCAL:
>> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
>> index 246d11ca133f..a161dac31a6f 100644
>> --- a/fs/xfs/scrub/inode.c
>> +++ b/fs/xfs/scrub/inode.c
>> @@ -220,6 +220,7 @@ xchk_dinode(
>>  	unsigned long long	isize;
>>  	uint64_t		flags2;
>>  	xfs_extnum_t		nextents;
>> +	xfs_extnum_t		naextents;
>>  	prid_t			prid;
>>  	uint16_t		flags;
>>  	uint16_t		mode;
>> @@ -378,7 +379,7 @@ xchk_dinode(
>>  	xchk_inode_extsize(sc, dip, ino, mode, flags);
>>
>>  	/* di_nextents */
>> -	nextents = be32_to_cpu(dip->di_nextents);
>> +	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>>  	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
>>  	switch (dip->di_format) {
>>  	case XFS_DINODE_FMT_EXTENTS:
>> @@ -395,10 +396,12 @@ xchk_dinode(
>>  		break;
>>  	}
>>
>> +	naextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
>> +
>>  	/* di_forkoff */
>>  	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
>>  		xchk_ino_set_corrupt(sc, ino);
>> -	if (dip->di_anextents != 0 && dip->di_forkoff == 0)
>> +	if (naextents != 0 && dip->di_forkoff == 0)
>>  		xchk_ino_set_corrupt(sc, ino);
>>  	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
>>  		xchk_ino_set_corrupt(sc, ino);
>> @@ -410,19 +413,18 @@ xchk_dinode(
>>  		xchk_ino_set_corrupt(sc, ino);
>>
>>  	/* di_anextents */
>> -	nextents = be16_to_cpu(dip->di_anextents);
>>  	fork_recs =  XFS_DFORK_ASIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
>>  	switch (dip->di_aformat) {
>>  	case XFS_DINODE_FMT_EXTENTS:
>> -		if (nextents > fork_recs)
>> +		if (naextents > fork_recs)
>>  			xchk_ino_set_corrupt(sc, ino);
>>  		break;
>>  	case XFS_DINODE_FMT_BTREE:
>> -		if (nextents <= fork_recs)
>> +		if (naextents <= fork_recs)
>>  			xchk_ino_set_corrupt(sc, ino);
>>  		break;
>>  	default:
>> -		if (nextents != 0)
>> +		if (naextents != 0)
>>  			xchk_ino_set_corrupt(sc, ino);
>>  	}
>>
>> @@ -487,6 +489,7 @@ xchk_inode_xref_bmap(
>>  	struct xfs_scrub	*sc,
>>  	struct xfs_dinode	*dip)
>>  {
>> +	struct xfs_mount	*mp = sc->mp;
>>  	xfs_extnum_t		nextents;
>>  	xfs_filblks_t		count;
>>  	xfs_filblks_t		acount;
>> @@ -500,14 +503,14 @@ xchk_inode_xref_bmap(
>>  			&nextents, &count);
>>  	if (!xchk_should_check_xref(sc, &error, NULL))
>>  		return;
>> -	if (nextents < be32_to_cpu(dip->di_nextents))
>> +	if (nextents < xfs_dfork_nextents(mp, dip, XFS_DATA_FORK))
>>  		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
>>
>>  	error = xfs_bmap_count_blocks(sc->tp, sc->ip, XFS_ATTR_FORK,
>>  			&nextents, &acount);
>>  	if (!xchk_should_check_xref(sc, &error, NULL))
>>  		return;
>> -	if (nextents != be16_to_cpu(dip->di_anextents))
>> +	if (nextents != xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
>>  		xchk_ino_xref_set_corrupt(sc, sc->ip->i_ino);
>>
>>  	/* Check nblocks against the inode. */
>> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
>> index 042c7d0bc0f5..bdb4685923c0 100644
>> --- a/fs/xfs/scrub/inode_repair.c
>> +++ b/fs/xfs/scrub/inode_repair.c
>
> Hey waitaminute, is this based off of djwong-dev??

Increasing data extent counter width also causes the maximum height of BMBT to
increase. This requires that the macro XFS_BTREE_MAXLEVELS be updated with a
larger value. However such a change causes the value of mp->m_rmap_maxlevels
to increase which in turn causes log reservation sizes to increase and hence a
modified XFS driver will fail to mount filesystems created by older versions
of mkfs.xfs.

I based this patchset on top of btree-dynamic-depth branch since it removes
the macro XFS_BTREE_MAXLEVELS and computes mp->m_rmap_maxlevels based on the
size of an AG.

>
>> @@ -602,7 +602,7 @@ xrep_dinode_bad_extents_fork(
>>  	int			i;
>>  	int			fork_size;
>>
>> -	nex = XFS_DFORK_NEXTENTS(dip, whichfork);
>> +	nex = xfs_dfork_nextents(sc->mp, dip, whichfork);
>>  	fork_size = nex * sizeof(struct xfs_bmbt_rec);
>>  	if (fork_size < 0 || fork_size > dfork_size)
>>  		return true;
>> @@ -636,7 +636,7 @@ xrep_dinode_bad_btree_fork(
>>  	int			nrecs;
>>  	int			level;
>>
>> -	if (XFS_DFORK_NEXTENTS(dip, whichfork) <=
>> +	if (xfs_dfork_nextents(sc->mp, dip, whichfork) <=
>>  			dfork_size / sizeof(struct xfs_bmbt_rec))
>>  		return true;
>>
>> @@ -831,12 +831,16 @@ xrep_dinode_ensure_forkoff(
>>  	struct xrep_dinode_stats	*dis)
>>  {
>>  	struct xfs_bmdr_block		*bmdr;
>> +	xfs_extnum_t			anextents, dnextents;
>>  	size_t				bmdr_minsz = xfs_bmdr_space_calc(1);
>>  	unsigned int			lit_sz = XFS_LITINO(sc->mp);
>>  	unsigned int			afork_min, dfork_min;
>>
>>  	trace_xrep_dinode_ensure_forkoff(sc, dip);
>>
>> +	dnextents = xfs_dfork_nextents(sc->mp, dip, XFS_DATA_FORK);
>> +	anextents = xfs_dfork_nextents(sc->mp, dip, XFS_ATTR_FORK);
>> +
>>  	/*
>>  	 * Before calling this function, xrep_dinode_core ensured that both
>>  	 * forks actually fit inside their respective literal areas.  If this
>> @@ -857,15 +861,14 @@ xrep_dinode_ensure_forkoff(
>>  		afork_min = XFS_DFORK_SIZE(dip, sc->mp, XFS_ATTR_FORK);
>>  		break;
>>  	case XFS_DINODE_FMT_EXTENTS:
>> -		if (dip->di_anextents) {
>> +		if (anextents) {
>>  			/*
>>  			 * We must maintain sufficient space to hold the entire
>>  			 * extent map array in the data fork.  Note that we
>>  			 * previously zapped the fork if it had no chance of
>>  			 * fitting in the inode.
>>  			 */
>> -			afork_min = sizeof(struct xfs_bmbt_rec) *
>> -						be16_to_cpu(dip->di_anextents);
>> +			afork_min = sizeof(struct xfs_bmbt_rec) * anextents;
>>  		} else if (dis->attr_extents > 0) {
>>  			/*
>>  			 * The attr fork thinks it has zero extents, but we
>> @@ -908,15 +911,14 @@ xrep_dinode_ensure_forkoff(
>>  		dfork_min = be64_to_cpu(dip->di_size);
>>  		break;
>>  	case XFS_DINODE_FMT_EXTENTS:
>> -		if (dip->di_nextents) {
>> +		if (dnextents) {
>>  			/*
>>  			 * We must maintain sufficient space to hold the entire
>>  			 * extent map array in the data fork.  Note that we
>>  			 * previously zapped the fork if it had no chance of
>>  			 * fitting in the inode.
>>  			 */
>> -			dfork_min = sizeof(struct xfs_bmbt_rec) *
>> -						be32_to_cpu(dip->di_nextents);
>> +			dfork_min = sizeof(struct xfs_bmbt_rec) * dnextents;
>>  		} else if (dis->data_extents > 0 || dis->rt_extents > 0) {
>>  			/*
>>  			 * The data fork thinks it has zero extents, but we
>> @@ -956,7 +958,7 @@ xrep_dinode_ensure_forkoff(
>>  	 * recovery fork, move the attr fork up.
>>  	 */
>>  	if (dip->di_format == XFS_DINODE_FMT_EXTENTS &&
>> -	    dip->di_nextents == 0 &&
>> +	    dnextents == 0 &&
>>  	    (dis->data_extents > 0 || dis->rt_extents > 0) &&
>>  	    bmdr_minsz > XFS_DFORK_DSIZE(dip, sc->mp)) {
>>  		if (bmdr_minsz + afork_min > lit_sz) {
>> @@ -982,7 +984,7 @@ xrep_dinode_ensure_forkoff(
>>  	 * recovery fork, move the attr fork down.
>>  	 */
>>  	if (dip->di_aformat == XFS_DINODE_FMT_EXTENTS &&
>> -	    dip->di_anextents == 0 &&
>> +	    anextents == 0 &&
>>  	    dis->attr_extents > 0 &&
>>  	    bmdr_minsz > XFS_DFORK_ASIZE(dip, sc->mp)) {
>>  		if (dip->di_format == XFS_DINODE_FMT_BTREE) {
>> @@ -1019,6 +1021,9 @@ xrep_dinode_zap_forks(
>>  	struct xfs_dinode		*dip,
>>  	struct xrep_dinode_stats	*dis)
>>  {
>> +	uint64_t			nblocks;
>
> xfs_rfsblock_t.

Sure. I will update it.

--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument
  2021-07-27 22:22   ` Darrick J. Wong
@ 2021-07-28  4:21     ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  4:21 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 03:52, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:35PM +0530, Chandan Babu R wrote:
>> This commit changes xfs_dfork_nextents() to return an error code. The extent
>> count itself is now returned through an out argument. This facility will be
>> used by a future commit to indicate an inconsistent ondisk extent count.
>> 
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> ---
>>  fs/xfs/libxfs/xfs_inode_buf.c  | 29 +++++++----
>>  fs/xfs/libxfs/xfs_inode_buf.h  |  4 +-
>>  fs/xfs/libxfs/xfs_inode_fork.c | 22 ++++++--
>>  fs/xfs/scrub/inode.c           | 94 +++++++++++++++++++++-------------
>>  fs/xfs/scrub/inode_repair.c    | 34 ++++++++----
>>  5 files changed, 119 insertions(+), 64 deletions(-)
>> 
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> index 6bef0757fca4..9ed04da2e2b1 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> @@ -345,7 +345,8 @@ xfs_dinode_verify_fork(
>>  	xfs_extnum_t		di_nextents;
>>  	xfs_extnum_t		max_extents;
>>  
>> -	di_nextents = xfs_dfork_nextents(mp, dip, whichfork);
>> +	if (xfs_dfork_nextents(mp, dip, whichfork, &di_nextents))
>> +		return __this_address;
>>  
>>  	switch (XFS_DFORK_FORMAT(dip, whichfork)) {
>>  	case XFS_DINODE_FMT_LOCAL:
>> @@ -377,29 +378,31 @@ xfs_dinode_verify_fork(
>>  	return NULL;
>>  }
>>  
>> -xfs_extnum_t
>> +int
>>  xfs_dfork_nextents(
>>  	struct xfs_mount	*mp,
>>  	struct xfs_dinode	*dip,
>> -	int			whichfork)
>> +	int			whichfork,
>> +	xfs_extnum_t		*nextents)
>>  {
>> -	xfs_extnum_t		nextents = 0;
>> +	int			error = 0;
>>  
>>  	switch (whichfork) {
>>  	case XFS_DATA_FORK:
>> -		nextents = be32_to_cpu(dip->di_nextents);
>> +		*nextents = be32_to_cpu(dip->di_nextents);
>>  		break;
>>  
>>  	case XFS_ATTR_FORK:
>> -		nextents = be16_to_cpu(dip->di_anextents);
>> +		*nextents = be16_to_cpu(dip->di_anextents);
>>  		break;
>>  
>>  	default:
>>  		ASSERT(0);
>> +		error = -EINVAL;
>
> -EFSCORRUPTED?  We don't have a specific code for "your darn software
> screwed up, hyuck!!" but I guess this will at least get peoples'
> attention.

Ok. I will update this.

>
>>  		break;
>>  	}
>>  
>> -	return nextents;
>> +	return error;
>>  }
>>  
>>  static xfs_failaddr_t
>> @@ -502,6 +505,7 @@ xfs_dinode_verify(
>>  	uint64_t		flags2;
>>  	uint64_t		di_size;
>>  	xfs_extnum_t            nextents;
>> +	xfs_extnum_t            naextents;
>>  	int64_t			nblocks;
>>  
>>  	if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))
>> @@ -533,8 +537,13 @@ xfs_dinode_verify(
>>  	if ((S_ISLNK(mode) || S_ISDIR(mode)) && di_size == 0)
>>  		return __this_address;
>>  
>> -	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>> -	nextents += xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
>> +	if (xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents))
>> +		return __this_address;
>> +
>> +	if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &naextents))
>> +		return __this_address;
>> +
>> +	nextents += naextents;
>>  	nblocks = be64_to_cpu(dip->di_nblocks);
>>  
>>  	/* Fork checks carried over from xfs_iformat_fork */
>> @@ -595,7 +604,7 @@ xfs_dinode_verify(
>>  		default:
>>  			return __this_address;
>>  		}
>> -		if (xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK))
>> +		if (naextents)
>>  			return __this_address;
>>  	}
>>  
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.h b/fs/xfs/libxfs/xfs_inode_buf.h
>> index ea2c35091609..20f796610d46 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.h
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.h
>> @@ -36,8 +36,8 @@ xfs_failaddr_t xfs_inode_validate_extsize(struct xfs_mount *mp,
>>  xfs_failaddr_t xfs_inode_validate_cowextsize(struct xfs_mount *mp,
>>  		uint32_t cowextsize, uint16_t mode, uint16_t flags,
>>  		uint64_t flags2);
>> -xfs_extnum_t xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
>> -		int whichfork);
>> +int xfs_dfork_nextents(struct xfs_mount *mp, struct xfs_dinode *dip,
>> +		int whichfork, xfs_extnum_t *nextents);
>>  
>>  static inline uint64_t xfs_inode_encode_bigtime(struct timespec64 tv)
>>  {
>> diff --git a/fs/xfs/libxfs/xfs_inode_fork.c b/fs/xfs/libxfs/xfs_inode_fork.c
>> index 38dd2dfc31fa..7f7ffe29436d 100644
>> --- a/fs/xfs/libxfs/xfs_inode_fork.c
>> +++ b/fs/xfs/libxfs/xfs_inode_fork.c
>> @@ -107,13 +107,20 @@ xfs_iformat_extents(
>>  	struct xfs_mount	*mp = ip->i_mount;
>>  	struct xfs_ifork	*ifp = XFS_IFORK_PTR(ip, whichfork);
>>  	int			state = xfs_bmap_fork_to_state(whichfork);
>> -	xfs_extnum_t		nex = xfs_dfork_nextents(mp, dip, whichfork);
>> -	int			size = nex * sizeof(xfs_bmbt_rec_t);
>> +	xfs_extnum_t		nex;
>> +	int			size;
>>  	struct xfs_iext_cursor	icur;
>>  	struct xfs_bmbt_rec	*dp;
>>  	struct xfs_bmbt_irec	new;
>> +	int			error;
>>  	int			i;
>>  
>> +	error = xfs_dfork_nextents(mp, dip, whichfork, &nex);
>> +	if (error)
>> +		return error;
>> +
>> +	size = nex * sizeof(xfs_bmbt_rec_t);
>
> sizeof(struct xfs_bmbt_rec);
>
> (Please convert the old typedef usage when possible.)

Sure. I will go through the patchset and update relevant code.

>
>> +
>>  	/*
>>  	 * If the number of extents is unreasonable, then something is wrong and
>>  	 * we just bail out rather than crash in kmem_alloc() or memcpy() below.
>> @@ -235,7 +242,10 @@ xfs_iformat_data_fork(
>>  	 * depend on it.
>>  	 */
>>  	ip->i_df.if_format = dip->di_format;
>> -	ip->i_df.if_nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>> +	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK,
>> +			&ip->i_df.if_nextents);
>> +	if (error)
>> +		return error;
>>  
>>  	switch (inode->i_mode & S_IFMT) {
>>  	case S_IFIFO:
>> @@ -304,9 +314,11 @@ xfs_iformat_attr_fork(
>>  {
>>  	struct xfs_mount	*mp = ip->i_mount;
>>  	xfs_extnum_t		nextents;
>> -	int			error = 0;
>> +	int			error;
>>  
>> -	nextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
>> +	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &nextents);
>> +	if (error)
>> +		return error;
>>  
>>  	/*
>>  	 * Initialize the extent count early, as the per-format routines may
>> diff --git a/fs/xfs/scrub/inode.c b/fs/xfs/scrub/inode.c
>> index a161dac31a6f..e9dc3749ea08 100644
>> --- a/fs/xfs/scrub/inode.c
>> +++ b/fs/xfs/scrub/inode.c
>> @@ -208,6 +208,44 @@ xchk_dinode_nsec(
>>  		xchk_ino_set_corrupt(sc, ino);
>>  }
>>  
>> +STATIC void
>> +xchk_dinode_fork_recs(
>> +	struct xfs_scrub	*sc,
>> +	struct xfs_dinode	*dip,
>> +	xfs_ino_t		ino,
>> +	xfs_extnum_t		nextents,
>> +	int			whichfork)
>> +{
>> +	struct xfs_mount	*mp = sc->mp;
>> +	size_t			fork_recs;
>> +	unsigned char		format;
>> +
>> +	if (whichfork == XFS_DATA_FORK) {
>> +		fork_recs =  XFS_DFORK_DSIZE(dip, mp)
>> +			/ sizeof(struct xfs_bmbt_rec);
>> +		format = dip->di_format;
>> +	} else if (whichfork == XFS_ATTR_FORK) {
>> +		fork_recs =  XFS_DFORK_ASIZE(dip, mp)
>> +			/ sizeof(struct xfs_bmbt_rec);
>> +		format = dip->di_aformat;
>> +	}
>
> 	fork_recs = XFS_DFORK_SIZE(dip, mp, whichfork);
> 	format = XFS_DFORK_FORMAT(dip, whichfork);
>
> ?

I agree. This increases readability of code.

>
>> +
>> +	switch (format) {
>> +	case XFS_DINODE_FMT_EXTENTS:
>> +		if (nextents > fork_recs)
>> +			xchk_ino_set_corrupt(sc, ino);
>> +		break;
>> +	case XFS_DINODE_FMT_BTREE:
>> +		if (nextents <= fork_recs)
>> +			xchk_ino_set_corrupt(sc, ino);
>> +		break;
>> +	default:
>> +		if (nextents != 0)
>> +			xchk_ino_set_corrupt(sc, ino);
>> +		break;
>> +	}
>> +}
>> +
>>  /* Scrub all the ondisk inode fields. */
>>  STATIC void
>>  xchk_dinode(
>> @@ -216,7 +254,6 @@ xchk_dinode(
>>  	xfs_ino_t		ino)
>>  {
>>  	struct xfs_mount	*mp = sc->mp;
>> -	size_t			fork_recs;
>>  	unsigned long long	isize;
>>  	uint64_t		flags2;
>>  	xfs_extnum_t		nextents;
>> @@ -224,6 +261,7 @@ xchk_dinode(
>>  	prid_t			prid;
>>  	uint16_t		flags;
>>  	uint16_t		mode;
>> +	int			error;
>>  
>>  	flags = be16_to_cpu(dip->di_flags);
>>  	if (dip->di_version >= 3)
>> @@ -379,33 +417,22 @@ xchk_dinode(
>>  	xchk_inode_extsize(sc, dip, ino, mode, flags);
>>  
>>  	/* di_nextents */
>> -	nextents = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK);
>> -	fork_recs =  XFS_DFORK_DSIZE(dip, mp) / sizeof(struct xfs_bmbt_rec);
>> -	switch (dip->di_format) {
>> -	case XFS_DINODE_FMT_EXTENTS:
>> -		if (nextents > fork_recs)
>> -			xchk_ino_set_corrupt(sc, ino);
>> -		break;
>> -	case XFS_DINODE_FMT_BTREE:
>> -		if (nextents <= fork_recs)
>> -			xchk_ino_set_corrupt(sc, ino);
>> -		break;
>> -	default:
>> -		if (nextents != 0)
>> -			xchk_ino_set_corrupt(sc, ino);
>> -		break;
>> -	}
>> -
>> -	naextents = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK);
>> +	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents);
>> +	if (error)
>> +		xchk_ino_set_corrupt(sc, ino);
>> +	else
>
> 	error = xfs_dfork_nextents(mp, dip, XFS_DATA_FORK, &nextents);
> 	if (error) {
> 		xchk_ino_set_corrupt(sc, ino);
> 		return;
> 	}
> 	xchk_dinode_fork_recs(sc, dip, ino, nextents, XFS_DATA_FORK);
>
> At this point you might as well return; you have sufficient information
> to generate the corruption report for userspace.

Ok. I will update.

>
>> +		xchk_dinode_fork_recs(sc, dip, ino, nextents, XFS_DATA_FORK);
>>  
>>  	/* di_forkoff */
>>  	if (XFS_DFORK_APTR(dip) >= (char *)dip + mp->m_sb.sb_inodesize)
>>  		xchk_ino_set_corrupt(sc, ino);
>> -	if (naextents != 0 && dip->di_forkoff == 0)
>> -		xchk_ino_set_corrupt(sc, ino);
>>  	if (dip->di_forkoff == 0 && dip->di_aformat != XFS_DINODE_FMT_EXTENTS)
>>  		xchk_ino_set_corrupt(sc, ino);
>>  
>> +	error = xfs_dfork_nextents(mp, dip, XFS_ATTR_FORK, &naextents);
>> +	if (error || (naextents != 0 && dip->di_forkoff == 0))
>> +		xchk_ino_set_corrupt(sc, ino);
>
> Please keep these separate so that the debug tracepoints can capture
> them as separate corruption sources.  Also, if xfs_dfork_nextents
> returns an error, you might as well return since we have enough data to
> generate the corruption report.
>

Ok. I will update this as well.

> (The rest of the scrub and repair code changes look good, btw.)

Thanks for the review.

-- 
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width
  2021-07-27 22:50   ` Darrick J. Wong
@ 2021-07-28  5:48     ` Chandan Babu R
  2021-07-28 19:04       ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  5:48 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 04:20, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:36PM +0530, Chandan Babu R wrote:
>> This commit renames extent counter fields in "struct xfs_dinode" and "struct
>> xfs_log_dinode" based on the width of the fields. As of this commit, the
>> 32-bit field will be used to count data fork extents and the 16-bit field will
>> be used to count attr fork extents.
>
> I totally had the preconceived notion that you were going to make the
> existing fields the 'lo' bits and then add six bytes of 'hi' field to
> the ondisk inode for the space you need.
>
> Instead, I see that in the new scheme, the the space where di_anextents
> is becomes unused, the space where di_nextents is now becomes the attr
> fork extent count, and you allocate another 8 bytes at the end of the
> ondisk inode for the data fork extent count.
>

To be precise, the patch allocates 8 bytes for data fork extent counter from
xfs_dinode->di_pad2[].

> Hm.  That /is/ clever in that we don't have to split bits between

This method was originally suggested by Dave. Please see the discussion at
https://lore.kernel.org/linux-xfs/20200903225145.GG12131@dread.disaster.area/.
Also, I do agree with his suggestion since the space freed by the old 16-bit
attr fork extent counter can be reused by a new feature.

> fields, but the downside is that if you want to upgrade existing
> filesystems, you'd either have to rewrite every inode in the entire
> filesystem, or introduce a di_flags2 bit to signal that this inode
> actually has the extended counters.  It also uses 8 bytes at the end of
> the ondisk inode structure.

IMHO, I don't think it is possible to upgrade existing filesystems. Increasing
per-inode extent counter values has the following cascading effect,
1. The maximum height of a BMBT tree increases.
2. Log reservation calculations which are a function of maximum BMBT height
   will see an increase in their values.
3. This might cause log space on existing filesystem instances to be small
   enough to make it impossible for new XFS driver to mount them.

Please correct me if my understanding is wrong.

>
> I think if we adjust the design a little bit we can enable the upgrade
> use case and reuse existing empty space in the ondisk inode.  Notice
> that there are six bytes of di_pad available in the middle of the inode
> record?  What do you think about putting the upper fields there?  The
> middle of the struct then looks like this:
>
> 	__be32		di_nextentshi;	/* upper 32-bits of di_nextents */
> 	__be16		di_naextentshi;	/* upper 16-bits of di_naextents */
> 	__be16		di_flushiter;	/* incremented on flush */
> 	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_nextentslo;	/* number of extents in data fork */
> 	__be16		di_anextentslo;	/* number of extents in attribute fork*/
>
> And your xfs_dfork_extents function looks like:
>
> 	case XFS_DATA_FORK:
> 		return (xfs_extnum_t)be32_to_cpu(dip->di_nextentshi) << 32 |
> 				     be32_to_cpu(dip->di_nextentslo);
> 	case XFS_ATTR_FORK:
> 		return (xfs_extnum_t)be16_to_cpu(dip->di_naextentshi) << 16 |
> 				     be16_to_cpu(dip->di_naextentslo);
>
> The pad fields are supposed to be zero, and upgrading now is no more
> effort than tapping into the existing xfs_repair upgrader code to add
> the EXTCOUNT64 feature flag.
>
> --D
>
>>
>> This change is done to enable a future commit to introduce a new 64-bit extent
>> counter field.
>>
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> ---
>>  fs/xfs/libxfs/xfs_format.h      |  4 ++--
>>  fs/xfs/libxfs/xfs_inode_buf.c   |  8 ++++----
>>  fs/xfs/libxfs/xfs_log_format.h  |  4 ++--
>>  fs/xfs/scrub/inode_repair.c     |  4 ++--
>>  fs/xfs/scrub/trace.h            | 14 +++++++-------
>>  fs/xfs/xfs_inode_item.c         |  4 ++--
>>  fs/xfs/xfs_inode_item_recover.c |  8 ++++----
>>  7 files changed, 23 insertions(+), 23 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 001a4077a7c6..2362cc005cc6 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -1039,8 +1039,8 @@ typedef struct xfs_dinode {
>>  	__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*/
>> +	__be32		di_nextents32;	/* number of extents in data fork */
>> +	__be16		di_nextents16;	/* number of extents in attribute fork*/
>>  	__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 */
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> index 9ed04da2e2b1..65d753e16007 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> @@ -313,8 +313,8 @@ 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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
>> +	to->di_nextents16 = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
>
> /me wonders if these should get their own static inline conversion
> helpers to set the appropriate fields, like I did for timestamps?
>
>>  	to->di_forkoff = ip->i_forkoff;
>>  	to->di_aformat = xfs_ifork_format(ip->i_afp);
>>  	to->di_flags = cpu_to_be16(ip->i_diflags);
>> @@ -389,11 +389,11 @@ xfs_dfork_nextents(
>>
>>  	switch (whichfork) {
>>  	case XFS_DATA_FORK:
>> -		*nextents = be32_to_cpu(dip->di_nextents);
>> +		*nextents = be32_to_cpu(dip->di_nextents32);
>>  		break;
>>
>>  	case XFS_ATTR_FORK:
>> -		*nextents = be16_to_cpu(dip->di_anextents);
>> +		*nextents = be16_to_cpu(dip->di_nextents16);
>>  		break;
>>
>>  	default:
>> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
>> index 0c888f92184e..ca8e4ad8312a 100644
>> --- a/fs/xfs/libxfs/xfs_log_format.h
>> +++ b/fs/xfs/libxfs/xfs_log_format.h
>> @@ -402,8 +402,8 @@ struct xfs_log_dinode {
>>  	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 */
>> -	xfs_extnum_t	di_nextents;	/* number of extents in data fork */
>> -	xfs_aextnum_t	di_anextents;	/* number of extents in attribute fork*/
>> +	uint32_t	di_nextents32;	/* number of extents in data fork */
>> +	uint16_t	di_nextents16;	/* number of extents in attribute fork*/
>>  	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 */
>> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
>> index 521c8df00990..4d773a16f886 100644
>> --- a/fs/xfs/scrub/inode_repair.c
>> +++ b/fs/xfs/scrub/inode_repair.c
>> @@ -736,7 +736,7 @@ xrep_dinode_zap_dfork(
>>  {
>>  	trace_xrep_dinode_zap_dfork(sc, dip);
>>
>> -	dip->di_nextents = 0;
>> +	dip->di_nextents32 = 0;
>>
>>  	/* Special files always get reset to DEV */
>>  	switch (mode & S_IFMT) {
>> @@ -823,7 +823,7 @@ xrep_dinode_zap_afork(
>>  	trace_xrep_dinode_zap_afork(sc, dip);
>>
>>  	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
>> -	dip->di_anextents = 0;
>> +	dip->di_nextents16 = 0;
>>
>>  	dip->di_forkoff = 0;
>>  	dip->di_mode = cpu_to_be16(mode & ~0777);
>> diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
>> index fd03685b1f6b..a0303f692e52 100644
>> --- a/fs/xfs/scrub/trace.h
>> +++ b/fs/xfs/scrub/trace.h
>> @@ -1209,8 +1209,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>>  		__field(uint64_t, size)
>>  		__field(uint64_t, nblocks)
>>  		__field(uint32_t, extsize)
>> -		__field(uint32_t, nextents)
>> -		__field(uint16_t, anextents)
>> +		__field(uint32_t, nextents32)
>> +		__field(uint16_t, nextents16)
>>  		__field(uint8_t, forkoff)
>>  		__field(uint8_t, aformat)
>>  		__field(uint16_t, flags)
>> @@ -1229,8 +1229,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>>  		__entry->size = be64_to_cpu(dip->di_size);
>>  		__entry->nblocks = be64_to_cpu(dip->di_nblocks);
>>  		__entry->extsize = be32_to_cpu(dip->di_extsize);
>> -		__entry->nextents = be32_to_cpu(dip->di_nextents);
>> -		__entry->anextents = be16_to_cpu(dip->di_anextents);
>> +		__entry->nextents32 = be32_to_cpu(dip->di_nextents32);
>> +		__entry->nextents16 = be16_to_cpu(dip->di_nextents16);
>>  		__entry->forkoff = dip->di_forkoff;
>>  		__entry->aformat = dip->di_aformat;
>>  		__entry->flags = be16_to_cpu(dip->di_flags);
>> @@ -1238,7 +1238,7 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>>  		__entry->flags2 = be64_to_cpu(dip->di_flags2);
>>  		__entry->cowextsize = be32_to_cpu(dip->di_cowextsize);
>>  	),
>> -	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents %u anextents %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
>> +	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents32 %u nextents16 %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
>>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
>>  		  __entry->ino,
>>  		  __entry->mode,
>> @@ -1249,8 +1249,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
>>  		  __entry->size,
>>  		  __entry->nblocks,
>>  		  __entry->extsize,
>> -		  __entry->nextents,
>> -		  __entry->anextents,
>> +		  __entry->nextents32,
>> +		  __entry->nextents16,
>>  		  __entry->forkoff,
>>  		  __entry->aformat,
>>  		  __entry->flags,
>> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
>> index 35de30849fcc..f54ce7468ba1 100644
>> --- a/fs/xfs/xfs_inode_item.c
>> +++ b/fs/xfs/xfs_inode_item.c
>> @@ -385,8 +385,8 @@ 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_nextents32 = xfs_ifork_nextents(&ip->i_df);
>> +	to->di_nextents16 = 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;
>> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
>> index 7b79518b6c20..40af9d1265c7 100644
>> --- a/fs/xfs/xfs_inode_item_recover.c
>> +++ b/fs/xfs/xfs_inode_item_recover.c
>> @@ -166,8 +166,8 @@ xfs_log_dinode_to_disk(
>>  	to->di_size = cpu_to_be64(from->di_size);
>>  	to->di_nblocks = cpu_to_be64(from->di_nblocks);
>>  	to->di_extsize = cpu_to_be32(from->di_extsize);
>> -	to->di_nextents = cpu_to_be32(from->di_nextents);
>> -	to->di_anextents = cpu_to_be16(from->di_anextents);
>> +	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
>> +	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>>  	to->di_forkoff = from->di_forkoff;
>>  	to->di_aformat = from->di_aformat;
>>  	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
>> @@ -332,7 +332,7 @@ xlog_recover_inode_commit_pass2(
>>  			goto out_release;
>>  		}
>>  	}
>> -	if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){
>> +	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
>>  		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
>>  				     XFS_ERRLEVEL_LOW, mp, ldip,
>>  				     sizeof(*ldip));
>> @@ -340,7 +340,7 @@ xlog_recover_inode_commit_pass2(
>>  	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
>>  	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
>>  			__func__, item, dip, bp, in_f->ilf_ino,
>> -			ldip->di_nextents + ldip->di_anextents,
>> +			ldip->di_nextents32 + ldip->di_nextents16,
>>  			ldip->di_nblocks);
>>  		error = -EFSCORRUPTED;
>>  		goto out_release;
>> --
>> 2.30.2
>>


--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
  2021-07-27 23:17       ` Dave Chinner
@ 2021-07-28  6:56         ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  6:56 UTC (permalink / raw)
  To: Dave Chinner; +Cc: Darrick J. Wong, linux-xfs

On 28 Jul 2021 at 04:47, Dave Chinner wrote:
> On Tue, Jul 27, 2021 at 04:00:02PM -0700, Darrick J. Wong wrote:
>> On Tue, Jul 27, 2021 at 03:54:00PM -0700, Darrick J. Wong wrote:
>> > On Mon, Jul 26, 2021 at 05:15:38PM +0530, Chandan Babu R wrote:
>> > > This commit renames XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 to allow a future
>> > > commit to extend bulkstat facility to support 64-bit extent counters. To this
>> > > end, this commit also renames xfs_bulkstat->bs_extents field to
>> > > xfs_bulkstat->bs_extents32.
>> > >
>> > > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> > > ---
>> > >  fs/xfs/libxfs/xfs_fs.h |  4 ++--
>> > >  fs/xfs/xfs_ioctl.c     | 27 ++++++++++++++++++++++-----
>> > >  fs/xfs/xfs_ioctl32.c   |  7 +++++++
>> > >  fs/xfs/xfs_itable.c    |  4 ++--
>> > >  fs/xfs/xfs_itable.h    |  1 +
>> > >  5 files changed, 34 insertions(+), 9 deletions(-)
>> > >
>> > > diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>> > > index 2594fb647384..d760a969599e 100644
>> > > --- a/fs/xfs/libxfs/xfs_fs.h
>> > > +++ b/fs/xfs/libxfs/xfs_fs.h
>> > > @@ -394,7 +394,7 @@ struct xfs_bulkstat {
>> > >  	uint32_t	bs_extsize_blks; /* extent size hint, blocks	*/
>> > >
>> > >  	uint32_t	bs_nlink;	/* number of links		*/
>> > > -	uint32_t	bs_extents;	/* number of extents		*/
>> > > +	uint32_t	bs_extents32;	/* number of extents		*/
>> >
>> > I wish I'd thought of this when we introduced bulkstat v5 so you
>> > wouldn't have had to do this.
>> >
>> > (I might have more to say in the bulkstat v6 patch review.)
>> > Reviewed-by: Darrick J. Wong <djwong@kernel.org>
>>
>> Actually, I take that back, I have things to say /now/. :)
>>
>> Rather than adding a whole new ioctl definition which (I haven't looked
>> at the xfsprogs changes) likely creates a bunch of churn in userspace,
>> what if we added a XFS_IBULK_ flag for supporting large extent counts?
>> There's also quite a bit of reserved padding space in xfs_bulk_ireq, so
>> perhaps we should define one of those padding u64 as a op-specific flag
>> field that would be a way to pass bulkstat-specific flags to the
>> relevant operations.  That way the 64-bit extent counts are merely a
>> variant on bulkstat v5 instead of a whole new format.
>
> Yup, this.
>
> The only reason for creating a new revision of the ioctl is if we've
> run out of expansion space in the existing ioctl structures to cater
> for new information we want to export to userspace.
>

Thanks for the suggestion. I will make the relevant changes before posting the
next version of the patchset.

--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 11/12] xfs: Extend per-inode extent counter widths
  2021-07-27 23:09   ` Darrick J. Wong
@ 2021-07-28  7:17     ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  7:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 04:39, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:40PM +0530, Chandan Babu R wrote:
>> This commit adds a new 64-bit per-inode data extent counter. However the
>> maximum number of extents that a data fork can hold is limited to 2^48
>> extents. This feature is available only when
>> XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT feature bit is enabled on the
>> filesystem. Also, enabling this feature bit causes attr fork extent counter to
>> use the 32-bit extent counter that was previously used to hold the data fork
>> extent counter. This implies that the attr fork can now occupy a maximum of
>> 2^32 extents.
>>
>> This commit also exposes the newly introduced XFS_IOC_BULKSTAT_V6 ioctl
>> interface to user space.
>>
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>> ---
>>  fs/xfs/libxfs/xfs_bmap.c        |  8 +++-----
>>  fs/xfs/libxfs/xfs_format.h      | 27 ++++++++++++++++++++++++---
>>  fs/xfs/libxfs/xfs_fs.h          |  1 +
>>  fs/xfs/libxfs/xfs_inode_buf.c   | 28 ++++++++++++++++++++++++----
>>  fs/xfs/libxfs/xfs_inode_fork.h  | 22 +++++++++++++++++-----
>>  fs/xfs/libxfs/xfs_log_format.h  |  3 ++-
>>  fs/xfs/scrub/inode_repair.c     | 11 +++++++++--
>>  fs/xfs/xfs_inode.c              |  2 +-
>>  fs/xfs/xfs_inode_item.c         | 15 +++++++++++++--
>>  fs/xfs/xfs_inode_item_recover.c | 25 +++++++++++++++++++------
>>  fs/xfs/xfs_ioctl.c              |  3 +++
>>  11 files changed, 116 insertions(+), 29 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>> index a27d57ea301c..e05898c9acbc 100644
>> --- a/fs/xfs/libxfs/xfs_bmap.c
>> +++ b/fs/xfs/libxfs/xfs_bmap.c
>> @@ -54,18 +54,16 @@ xfs_bmap_compute_maxlevels(
>>  	int		whichfork)	/* data or attr fork */
>>  {
>>  	xfs_extnum_t	maxleafents;	/* max leaf entries possible */
>> +	uint64_t	maxblocks;	/* max blocks at this level */
>
> xfs_rfsblock_t?

Ok. I will update that.

>
>>  	int		level;		/* btree level */
>> -	uint		maxblocks;	/* max blocks at this level */
>>  	int		maxrootrecs;	/* max records in root block */
>>  	int		minleafrecs;	/* min records in leaf block */
>>  	int		minnoderecs;	/* min records in node block */
>>  	int		sz;		/* root block size */
>>
>>  	/*
>> -	 * The maximum number of extents in a file, hence the maximum number of
>> -	 * leaf entries, is controlled by the size of the on-disk extent count,
>> -	 * either a signed 32-bit number for the data fork, or a signed 16-bit
>> -	 * number for the attr fork.
>> +	 * The maximum number of extents in a fork, hence the maximum number of
>> +	 * leaf entries, is controlled by the size of the on-disk extent count.
>>  	 *
>>  	 * Note that we can no longer assume that if we are in ATTR1 that the
>>  	 * fork offset of all the inodes will be
>> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
>> index 2362cc005cc6..3aa83d75670d 100644
>> --- a/fs/xfs/libxfs/xfs_format.h
>> +++ b/fs/xfs/libxfs/xfs_format.h
>> @@ -485,13 +485,15 @@ xfs_sb_has_ro_compat_feature(
>>  #define XFS_SB_FEAT_INCOMPAT_BIGTIME	(1 << 3)	/* large timestamps */
>>  #define XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR (1 << 4)	/* needs xfs_repair */
>>  #define XFS_SB_FEAT_INCOMPAT_METADIR	(1 << 5)	/* metadata dir tree */
>> -#define XFS_SB_FEAT_INCOMPAT_ALL \
>> +#define XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT (1 << 6)	/* 64-bit inode fork extent counter */
>> +#define XFS_SB_FEAT_INCOMPAT_ALL		\
>>  		(XFS_SB_FEAT_INCOMPAT_FTYPE|	\
>>  		 XFS_SB_FEAT_INCOMPAT_SPINODES|	\
>>  		 XFS_SB_FEAT_INCOMPAT_META_UUID| \
>>  		 XFS_SB_FEAT_INCOMPAT_BIGTIME| \
>>  		 XFS_SB_FEAT_INCOMPAT_NEEDSREPAIR| \
>> -		 XFS_SB_FEAT_INCOMPAT_METADIR)
>> +		 XFS_SB_FEAT_INCOMPAT_METADIR| \
>
> Oh hey, this /definitely/ branches off djwong-dev. :)
>
>> +		 XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT)
>
> Hm.  I don't think we're ever going to want to support more than u48
> extent counts because that's a lot of memory consumption.  It might be
> safe to call this by a shorter name, e.g.
>
> 	BIGBMAP?
> 	SUPERSPARSE?	(no, too long)
> 	EXT64		(beat that, ext4!)

:)

> 	NREXT64
>
> I kinda like BIGBMAP since it's actually pronounceable...

Dave had suggested
(https://lore.kernel.org/linux-xfs/20200903225145.GG12131@dread.disaster.area/)
that "field widths" be used to identify the feature since,
1. The feature name would convey the width of the field.
2. Naming a new extension in the future will be easier.

I agree with the reasoning given by him.

So may be NREXT64 suggested by you would strike the right balance.

>
>>  #define XFS_SB_FEAT_INCOMPAT_UNKNOWN	~XFS_SB_FEAT_INCOMPAT_ALL
>>  static inline bool
>> @@ -591,6 +593,12 @@ static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp)
>>  		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID);
>>  }
>>
>> +static inline bool xfs_sb_version_hasextcount_64bit(struct xfs_sb *sbp)
>> +{
>> +	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
>> +		(sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_EXTCOUNT_64BIT);
>> +}
>> +
>>  static inline bool xfs_sb_version_hasrmapbt(struct xfs_sb *sbp)
>>  {
>>  	return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) &&
>> @@ -1039,6 +1047,16 @@ typedef struct xfs_dinode {
>>  	__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 */
>> +
>> +	/*
>> +	 * On a extcnt64bit filesystem, di_nextents64 holds the data fork
>> +	 * extent count, di_nextents32 holds the attr fork extent count,
>> +	 * and di_nextents16 must be zero.
>> +	 *
>> +	 * Otherwise, di_nextents32 holds the data fork extent count,
>> +	 * di_nextents16 holds the attr fork extent count, and di_nextents64
>> +	 * must be zero.
>
> (See earlier comments about reusing di_pad[6])
>
>> +	 */
>>  	__be32		di_nextents32;	/* number of extents in data fork */
>>  	__be16		di_nextents16;	/* number of extents in attribute fork*/
>>  	__u8		di_forkoff;	/* attr fork offs, <<3 for 64b align */
>> @@ -1057,7 +1075,8 @@ typedef struct xfs_dinode {
>>  	__be64		di_lsn;		/* flush sequence */
>>  	__be64		di_flags2;	/* more random flags */
>>  	__be32		di_cowextsize;	/* basic cow extent size for file */
>> -	__u8		di_pad2[12];	/* more padding for future expansion */
>> +	__u8		di_pad2[4];	/* more padding for future expansion */
>> +	__be64		di_nextents64;
>>
>>  	/* fields only written to during inode creation */
>>  	xfs_timestamp_t	di_crtime;	/* time created */
>> @@ -1113,6 +1132,8 @@ enum xfs_dinode_fmt {
>>   * Max values for extlen and disk inode's extent counters.
>>   */
>>  #define	MAXEXTLEN		((uint32_t)0x1fffff) /* 21 bits */
>> +#define XFS_IFORK_EXTCNT_MAXU48	((uint64_t)0xffffffffffff) /* Unsigned 48-bits */
>> +#define XFS_IFORK_EXTCNT_MAXU32	((uint32_t)0xffffffff)	/* Unsigned 32-bits */
>>  #define XFS_IFORK_EXTCNT_MAXS32 ((int32_t)0x7fffffff)  /* Signed 32-bits */
>>  #define XFS_IFORK_EXTCNT_MAXS16 ((int16_t)0x7fff)      /* Signed 16-bits */
>>
>> diff --git a/fs/xfs/libxfs/xfs_fs.h b/fs/xfs/libxfs/xfs_fs.h
>> index 756be4ff5996..57f67445f095 100644
>> --- a/fs/xfs/libxfs/xfs_fs.h
>> +++ b/fs/xfs/libxfs/xfs_fs.h
>> @@ -858,6 +858,7 @@ struct xfs_scrub_metadata {
>>  #define XFS_IOC_BULKSTAT_V5	     _IOR ('X', 127, struct xfs_bulkstat_req)
>>  #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
>>  /*	FIEXCHANGE_RANGE ----------- hoisted 129	 */
>> +#define XFS_IOC_BULKSTAT_V6	     _IOR ('X', 130, struct xfs_bulkstat_req)
>
> (See earlier comments about adding flags to xfs_bulk_ireq so we don't
> have to rev the ioctl definitions yet again.)

Sure. I will fix this.

>
>>  /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
>>
>>
>> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
>> index 65d753e16007..28e49394edbb 100644
>> --- a/fs/xfs/libxfs/xfs_inode_buf.c
>> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
>> @@ -291,6 +291,7 @@ xfs_inode_to_disk(
>>  	struct xfs_dinode	*to,
>>  	xfs_lsn_t		lsn)
>>  {
>> +	struct xfs_sb		*sbp = &ip->i_mount->m_sb;
>>  	struct inode		*inode = VFS_I(ip);
>>
>>  	to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC);
>> @@ -313,8 +314,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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
>> -	to->di_nextents16 = 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);
>> @@ -334,6 +333,19 @@ xfs_inode_to_disk(
>>  		to->di_version = 2;
>>  		to->di_flushiter = cpu_to_be16(ip->i_flushiter);
>>  	}
>> +
>> +	if (xfs_sb_version_hasextcount_64bit(sbp)) {
>> +		to->di_nextents64 = cpu_to_be64(xfs_ifork_nextents(&ip->i_df));
>> +		to->di_nextents32 = cpu_to_be32(xfs_ifork_nextents(ip->i_afp));
>
> Hmm, yes, these really should be separate helpers like what we did for
> timestamps.

Ok. I will make the changes.

>
>> +		/*
>> +		 * xchk_dinode() passes an uninitialized disk inode. Hence,
>> +		 * clear di_nextents16 field explicitly.
>
> So fix xchk_dinode.

Ok. Will do that.

>
>> +		 */
>> +		to->di_nextents16 = cpu_to_be16(0);
>> +	} else {
>> +		to->di_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
>> +		to->di_nextents16 = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
>> +	}
>>  }
>>
>>  static xfs_failaddr_t
>> @@ -386,14 +398,22 @@ xfs_dfork_nextents(
>>  	xfs_extnum_t		*nextents)
>>  {
>>  	int			error = 0;
>> +	bool			has_64bit_extcnt;
>> +
>> +	has_64bit_extcnt = xfs_sb_version_hasextcount_64bit(&mp->m_sb);
>> +
>> +	if (has_64bit_extcnt && dip->di_nextents16 != 0)
>> +		return -EFSCORRUPTED;
>
> I think if you follow my suggestions to encode the upper 32/16 bits of
> the extent counters in di_pad, the need for error codes (and patch 6) go
> away completely.
>
>>
>>  	switch (whichfork) {
>>  	case XFS_DATA_FORK:
>> -		*nextents = be32_to_cpu(dip->di_nextents32);
>> +		*nextents = has_64bit_extcnt ? be64_to_cpu(dip->di_nextents64)
>> +			: be32_to_cpu(dip->di_nextents32);
>>  		break;
>>
>>  	case XFS_ATTR_FORK:
>> -		*nextents = be16_to_cpu(dip->di_nextents16);
>> +		*nextents = has_64bit_extcnt ? be32_to_cpu(dip->di_nextents32)
>> +			: be16_to_cpu(dip->di_nextents16);
>>  		break;
>>
>>  	default:
>> diff --git a/fs/xfs/libxfs/xfs_inode_fork.h b/fs/xfs/libxfs/xfs_inode_fork.h
>> index 1eda2163603e..ffdd2abcd73c 100644
>> --- a/fs/xfs/libxfs/xfs_inode_fork.h
>> +++ b/fs/xfs/libxfs/xfs_inode_fork.h
>> @@ -21,9 +21,9 @@ struct xfs_ifork {
>>  		void		*if_root;	/* extent tree root */
>>  		char		*if_data;	/* inline file data */
>>  	} if_u1;
>> +	xfs_extnum_t		if_nextents;	/* # of extents in this fork */
>>  	short			if_broot_bytes;	/* bytes allocated for root */
>>  	int8_t			if_format;	/* format of this fork */
>> -	xfs_extnum_t		if_nextents;	/* # of extents in this fork */
>>  };
>>
>>  /*
>> @@ -135,10 +135,22 @@ static inline int8_t xfs_ifork_format(struct xfs_ifork *ifp)
>>
>>  static inline xfs_extnum_t xfs_iext_max(struct xfs_mount *mp, int whichfork)
>>  {
>> -	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK)
>> -		return XFS_IFORK_EXTCNT_MAXS32;
>> -	else
>> -		return XFS_IFORK_EXTCNT_MAXS16;
>> +	bool has_64bit_extcnt = xfs_sb_version_hasextcount_64bit(&mp->m_sb);
>> +
>> +	switch (whichfork) {
>> +	case XFS_DATA_FORK:
>> +	case XFS_COW_FORK:
>> +		return has_64bit_extcnt ? XFS_IFORK_EXTCNT_MAXU48
>> +			: XFS_IFORK_EXTCNT_MAXS32;
>> +
>> +	case XFS_ATTR_FORK:
>> +		return has_64bit_extcnt ? XFS_IFORK_EXTCNT_MAXU32
>> +			: XFS_IFORK_EXTCNT_MAXS16;
>> +
>> +	default:
>> +		ASSERT(0);
>> +		return 0;
>> +	}
>>  }
>>
>>  struct xfs_ifork *xfs_ifork_alloc(enum xfs_dinode_fmt format,
>> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
>> index ca8e4ad8312a..9b5d64708ed1 100644
>> --- a/fs/xfs/libxfs/xfs_log_format.h
>> +++ b/fs/xfs/libxfs/xfs_log_format.h
>> @@ -420,7 +420,8 @@ struct xfs_log_dinode {
>>  	xfs_lsn_t	di_lsn;		/* flush sequence */
>>  	uint64_t	di_flags2;	/* more random flags */
>>  	uint32_t	di_cowextsize;	/* basic cow extent size for file */
>> -	uint8_t		di_pad2[12];	/* more padding for future expansion */
>> +	uint8_t		di_pad2[4];	/* more padding for future expansion */
>> +	uint64_t	di_nextents64; /* higher part of data fork extent count */
>
> Similarly, I think you should reuse di_pad in the log dinode for the
> high bits of the extent count fields.
>
> --D
>
>>
>>  	/* fields only written to during inode creation */
>>  	xfs_log_timestamp_t di_crtime;	/* time created */
>> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
>> index 4d773a16f886..dde6b700e891 100644
>> --- a/fs/xfs/scrub/inode_repair.c
>> +++ b/fs/xfs/scrub/inode_repair.c
>> @@ -736,7 +736,10 @@ xrep_dinode_zap_dfork(
>>  {
>>  	trace_xrep_dinode_zap_dfork(sc, dip);
>>
>> -	dip->di_nextents32 = 0;
>> +	if (xfs_sb_version_hasextcount_64bit(&sc->mp->m_sb))
>> +		dip->di_nextents64 = 0;
>> +	else
>> +		dip->di_nextents32 = 0;
>>
>>  	/* Special files always get reset to DEV */
>>  	switch (mode & S_IFMT) {
>> @@ -823,7 +826,11 @@ xrep_dinode_zap_afork(
>>  	trace_xrep_dinode_zap_afork(sc, dip);
>>
>>  	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
>> -	dip->di_nextents16 = 0;
>> +
>> +	if (xfs_sb_version_hasextcount_64bit(&sc->mp->m_sb))
>> +		dip->di_nextents32 = 0;
>> +	else
>> +		dip->di_nextents16 = 0;
>>
>>  	dip->di_forkoff = 0;
>>  	dip->di_mode = cpu_to_be16(mode & ~0777);
>> diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
>> index 4070fb01350c..19d525093702 100644
>> --- a/fs/xfs/xfs_inode.c
>> +++ b/fs/xfs/xfs_inode.c
>> @@ -2511,7 +2511,7 @@ xfs_iflush(
>>  				ip->i_nblocks, mp, XFS_ERRTAG_IFLUSH_5)) {
>>  		xfs_alert_tag(mp, XFS_PTAG_IFLUSH,
>>  			"%s: detected corrupt incore inode %llu, "
>> -			"total extents = %llu nblocks = %lld, ptr "PTR_FMT,
>> +			"total extents = %llu, nblocks = %lld, ptr "PTR_FMT,
>>  			__func__, ip->i_ino,
>>  			ip->i_df.if_nextents + xfs_ifork_nextents(ip->i_afp),
>>  			ip->i_nblocks, ip);
>> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
>> index f54ce7468ba1..3fa73100484b 100644
>> --- a/fs/xfs/xfs_inode_item.c
>> +++ b/fs/xfs/xfs_inode_item.c
>> @@ -364,6 +364,7 @@ xfs_inode_to_log_dinode(
>>  	struct xfs_log_dinode	*to,
>>  	xfs_lsn_t		lsn)
>>  {
>> +	struct xfs_sb		*sbp = &ip->i_mount->m_sb;
>>  	struct inode		*inode = VFS_I(ip);
>>
>>  	to->di_magic = XFS_DINODE_MAGIC;
>> @@ -385,8 +386,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_nextents32 = xfs_ifork_nextents(&ip->i_df);
>> -	to->di_nextents16 = 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;
>> @@ -402,6 +401,16 @@ xfs_inode_to_log_dinode(
>>  		to->di_crtime = xfs_inode_to_log_dinode_ts(ip, ip->i_crtime);
>>  		to->di_flags2 = ip->i_diflags2;
>>  		to->di_cowextsize = ip->i_cowextsize;
>> +		if (xfs_sb_version_hasextcount_64bit(sbp)) {
>> +			to->di_nextents64 = xfs_ifork_nextents(&ip->i_df);
>> +			to->di_nextents32 = xfs_ifork_nextents(ip->i_afp);
>> +			to->di_nextents16 = 0;
>> +		} else {
>> +			to->di_nextents64 = 0;
>> +			to->di_nextents32 = xfs_ifork_nextents(&ip->i_df);
>> +			to->di_nextents16 = xfs_ifork_nextents(ip->i_afp);
>> +		}
>> +
>>  		to->di_ino = ip->i_ino;
>>  		to->di_lsn = lsn;
>>  		memset(to->di_pad2, 0, sizeof(to->di_pad2));
>> @@ -410,6 +419,8 @@ xfs_inode_to_log_dinode(
>>  	} else {
>>  		to->di_version = 2;
>>  		to->di_flushiter = ip->i_flushiter;
>> +		to->di_nextents32 = xfs_ifork_nextents(&ip->i_df);
>> +		to->di_nextents16 = xfs_ifork_nextents(ip->i_afp);
>>  	}
>>  }
>>
>> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
>> index 40af9d1265c7..fcf360c03bc1 100644
>> --- a/fs/xfs/xfs_inode_item_recover.c
>> +++ b/fs/xfs/xfs_inode_item_recover.c
>> @@ -166,8 +166,6 @@ xfs_log_dinode_to_disk(
>>  	to->di_size = cpu_to_be64(from->di_size);
>>  	to->di_nblocks = cpu_to_be64(from->di_nblocks);
>>  	to->di_extsize = cpu_to_be32(from->di_extsize);
>> -	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
>> -	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>>  	to->di_forkoff = from->di_forkoff;
>>  	to->di_aformat = from->di_aformat;
>>  	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
>> @@ -181,12 +179,17 @@ xfs_log_dinode_to_disk(
>>  							  from->di_crtime);
>>  		to->di_flags2 = cpu_to_be64(from->di_flags2);
>>  		to->di_cowextsize = cpu_to_be32(from->di_cowextsize);
>> +		to->di_nextents64 = cpu_to_be64(from->di_nextents64);
>> +		to->di_nextents32 = cpu_to_be32(from->di_nextents32);
>> +		to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>>  		to->di_ino = cpu_to_be64(from->di_ino);
>>  		to->di_lsn = cpu_to_be64(from->di_lsn);
>>  		memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2));
>>  		uuid_copy(&to->di_uuid, &from->di_uuid);
>>  		to->di_flushiter = 0;
>>  	} else {
>> +		to->di_nextents32 = cpu_to_be32(from->di_nextents32);
>> +		to->di_nextents16 = cpu_to_be16(from->di_nextents16);
>>  		to->di_flushiter = cpu_to_be16(from->di_flushiter);
>>  	}
>>  }
>> @@ -202,6 +205,8 @@ xlog_recover_inode_commit_pass2(
>>  	struct xfs_mount		*mp = log->l_mp;
>>  	struct xfs_buf			*bp;
>>  	struct xfs_dinode		*dip;
>> +	xfs_extnum_t                    nextents;
>> +	xfs_aextnum_t                   anextents;
>>  	int				len;
>>  	char				*src;
>>  	char				*dest;
>> @@ -332,16 +337,24 @@ xlog_recover_inode_commit_pass2(
>>  			goto out_release;
>>  		}
>>  	}
>> -	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
>> +
>> +	if (xfs_sb_version_hasextcount_64bit(&mp->m_sb)) {
>> +		nextents = ldip->di_nextents64;
>> +		anextents = ldip->di_nextents32;
>> +	} else {
>> +		nextents = ldip->di_nextents32;
>> +		anextents = ldip->di_nextents16;
>> +	}
>> +
>> +	if (unlikely(nextents + anextents > ldip->di_nblocks)) {
>>  		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
>>  				     XFS_ERRLEVEL_LOW, mp, ldip,
>>  				     sizeof(*ldip));
>>  		xfs_alert(mp,
>>  	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
>> -	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
>> +	"dino bp "PTR_FMT", ino %Ld, total extents = %llu, nblocks = %Ld",
>>  			__func__, item, dip, bp, in_f->ilf_ino,
>> -			ldip->di_nextents32 + ldip->di_nextents16,
>> -			ldip->di_nblocks);
>> +			nextents + anextents, ldip->di_nblocks);
>>  		error = -EFSCORRUPTED;
>>  		goto out_release;
>>  	}
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index 19964b394dc4..2d44aa655f41 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -1901,6 +1901,9 @@ xfs_file_ioctl(
>>  	case XFS_IOC_BULKSTAT_V5:
>>  		return xfs_ioc_bulkstat(filp, cmd, arg,
>>  				XFS_BULKSTAT_VERSION_V5);
>> +	case XFS_IOC_BULKSTAT_V6:
>> +		return xfs_ioc_bulkstat(filp, cmd, arg,
>> +				XFS_BULKSTAT_VERSION_V6);
>>  	case XFS_IOC_INUMBERS:
>>  		return xfs_ioc_inumbers(mp, cmd, arg,
>>  				XFS_INUMBERS_VERSION_V5);
>> --
>> 2.30.2
>>


--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count
  2021-07-27 23:10   ` Darrick J. Wong
@ 2021-07-28  7:23     ` Chandan Babu R
  2021-07-28  7:38       ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  7:23 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 04:40, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:41PM +0530, Chandan Babu R wrote:
>> This commit adds a new error tag to allow user space tests to check if V5
>> bulkstat ioctl skips reporting inodes with large extent count.
>>
>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>
> Keep in mind that each of these injection knobs costs us 4 bytes per
> mount.  No particular objections, but I don't know how urgently we need
> to do that to test a corner case...
>

How about using the existing error tag XFS_RANDOM_REDUCE_MAX_IEXTENTS instead
of creating a new one? XFS_RANDOM_REDUCE_MAX_IEXTENTS conveys the meaning that
we use a pseudo max data/attr fork extent count. IMHO this fits into the
bulkstat testing use case where we use a pseudo max data fork extent count.

--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count
  2021-07-28  7:23     ` Chandan Babu R
@ 2021-07-28  7:38       ` Chandan Babu R
  2021-07-28 19:06         ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-07-28  7:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 12:53, Chandan Babu R wrote:
> On 28 Jul 2021 at 04:40, Darrick J. Wong wrote:
>> On Mon, Jul 26, 2021 at 05:15:41PM +0530, Chandan Babu R wrote:
>>> This commit adds a new error tag to allow user space tests to check if V5
>>> bulkstat ioctl skips reporting inodes with large extent count.
>>>
>>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>>
>> Keep in mind that each of these injection knobs costs us 4 bytes per
>> mount.  No particular objections, but I don't know how urgently we need
>> to do that to test a corner case...
>>
>
> How about using the existing error tag XFS_RANDOM_REDUCE_MAX_IEXTENTS instead
> of creating a new one? XFS_RANDOM_REDUCE_MAX_IEXTENTS conveys the meaning that
> we use a pseudo max data/attr fork extent count. IMHO this fits into the
> bulkstat testing use case where we use a pseudo max data fork extent count.

Sorry, I actually meant to refer to XFS_ERRTAG_REDUCE_MAX_IEXTENTS instead of
XFS_RANDOM_REDUCE_MAX_IEXTENTS.

-- 
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width
  2021-07-28  5:48     ` Chandan Babu R
@ 2021-07-28 19:04       ` Darrick J. Wong
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-28 19:04 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Wed, Jul 28, 2021 at 11:18:23AM +0530, Chandan Babu R wrote:
> On 28 Jul 2021 at 04:20, Darrick J. Wong wrote:
> > On Mon, Jul 26, 2021 at 05:15:36PM +0530, Chandan Babu R wrote:
> >> This commit renames extent counter fields in "struct xfs_dinode" and "struct
> >> xfs_log_dinode" based on the width of the fields. As of this commit, the
> >> 32-bit field will be used to count data fork extents and the 16-bit field will
> >> be used to count attr fork extents.
> >
> > I totally had the preconceived notion that you were going to make the
> > existing fields the 'lo' bits and then add six bytes of 'hi' field to
> > the ondisk inode for the space you need.
> >
> > Instead, I see that in the new scheme, the the space where di_anextents
> > is becomes unused, the space where di_nextents is now becomes the attr
> > fork extent count, and you allocate another 8 bytes at the end of the
> > ondisk inode for the data fork extent count.
> >
> 
> To be precise, the patch allocates 8 bytes for data fork extent counter from
> xfs_dinode->di_pad2[].

<Nod>

> > Hm.  That /is/ clever in that we don't have to split bits between
> 
> This method was originally suggested by Dave. Please see the discussion at
> https://lore.kernel.org/linux-xfs/20200903225145.GG12131@dread.disaster.area/.
> Also, I do agree with his suggestion since the space freed by the old 16-bit
> attr fork extent counter can be reused by a new feature.

Ah, ok, this was a direct request from Dave, who doesn't want us to
split fields in the inode core.  All right, that's a fair request (side
eye at still unfixed ext4 bit splitting timestamp mess).

I don't like the di_nextents{16,32,64} naming though -- that tells us
about the size of the field, which we already know from the type.
However, I don't know if tagged anonymous union structs are the answer?

	__be32		di_extsize;
	union {
		struct {
			/* classic data/attr extent counts */
			__be32	di_nextents;
			__be16	di_naextents;
		};
		struct {
			/* attr extents under NREXT64 */
			__be32	di_naextents_nr64;
			__be16	di_pad3;
		};
	};
	__u8		di_forkoff;
	...
	__be64		di_nextents_nr64;

This is nice in the sense that it makes reviewing code easier:

	if (xfs_sb_version_hasnrext64(mp))
		fubar = be64_to_cpu(dip->di_nextents_nr64);
	else
		fubar = be32_to_cpu(dip->di_nextents);

OTOH you've already done all the work to encapsulate this particular
detail for upper levels of XFS, which means that outside of
xfs_inode_buf.c everyone else will just do:

	fubar = xfs_dfork_nrextents(dip, XFS_DATA_FORK);

Yeah, ok.  I'm convinced this is acceptable.

> > fields, but the downside is that if you want to upgrade existing
> > filesystems, you'd either have to rewrite every inode in the entire
> > filesystem, or introduce a di_flags2 bit to signal that this inode
> > actually has the extended counters.  It also uses 8 bytes at the end of
> > the ondisk inode structure.
> 
> IMHO, I don't think it is possible to upgrade existing filesystems. Increasing
> per-inode extent counter values has the following cascading effect,
> 1. The maximum height of a BMBT tree increases.
> 2. Log reservation calculations which are a function of maximum BMBT height
>    will see an increase in their values.
> 3. This might cause log space on existing filesystem instances to be small
>    enough to make it impossible for new XFS driver to mount them.
> 
> Please correct me if my understanding is wrong.

It's possible to check the log size prior to upgrading the filesystem:
https://git.kernel.org/pub/scm/linux/kernel/git/djwong/xfsprogs-dev.git/commit/?h=upgrade-older-features

See the first parts of check_new_v5_geometry().

We have to decide now if the initial design for this feature should
include an inode flag to tell us how to switch on the fields, because
that's the critical piece needed to enable upgrading.

Do people care about the ability to upgrade to nrext64?  This isn't
quite like y2038 support where we have a hard requirement to upgrade
old filesystems.  Thoughts?  Anyone?

--D

> 
> >
> > I think if we adjust the design a little bit we can enable the upgrade
> > use case and reuse existing empty space in the ondisk inode.  Notice
> > that there are six bytes of di_pad available in the middle of the inode
> > record?  What do you think about putting the upper fields there?  The
> > middle of the struct then looks like this:
> >
> > 	__be32		di_nextentshi;	/* upper 32-bits of di_nextents */
> > 	__be16		di_naextentshi;	/* upper 16-bits of di_naextents */
> > 	__be16		di_flushiter;	/* incremented on flush */
> > 	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_nextentslo;	/* number of extents in data fork */
> > 	__be16		di_anextentslo;	/* number of extents in attribute fork*/
> >
> > And your xfs_dfork_extents function looks like:
> >
> > 	case XFS_DATA_FORK:
> > 		return (xfs_extnum_t)be32_to_cpu(dip->di_nextentshi) << 32 |
> > 				     be32_to_cpu(dip->di_nextentslo);
> > 	case XFS_ATTR_FORK:
> > 		return (xfs_extnum_t)be16_to_cpu(dip->di_naextentshi) << 16 |
> > 				     be16_to_cpu(dip->di_naextentslo);
> >
> > The pad fields are supposed to be zero, and upgrading now is no more
> > effort than tapping into the existing xfs_repair upgrader code to add
> > the EXTCOUNT64 feature flag.
> >
> > --D
> >
> >>
> >> This change is done to enable a future commit to introduce a new 64-bit extent
> >> counter field.
> >>
> >> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> >> ---
> >>  fs/xfs/libxfs/xfs_format.h      |  4 ++--
> >>  fs/xfs/libxfs/xfs_inode_buf.c   |  8 ++++----
> >>  fs/xfs/libxfs/xfs_log_format.h  |  4 ++--
> >>  fs/xfs/scrub/inode_repair.c     |  4 ++--
> >>  fs/xfs/scrub/trace.h            | 14 +++++++-------
> >>  fs/xfs/xfs_inode_item.c         |  4 ++--
> >>  fs/xfs/xfs_inode_item_recover.c |  8 ++++----
> >>  7 files changed, 23 insertions(+), 23 deletions(-)
> >>
> >> diff --git a/fs/xfs/libxfs/xfs_format.h b/fs/xfs/libxfs/xfs_format.h
> >> index 001a4077a7c6..2362cc005cc6 100644
> >> --- a/fs/xfs/libxfs/xfs_format.h
> >> +++ b/fs/xfs/libxfs/xfs_format.h
> >> @@ -1039,8 +1039,8 @@ typedef struct xfs_dinode {
> >>  	__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*/
> >> +	__be32		di_nextents32;	/* number of extents in data fork */
> >> +	__be16		di_nextents16;	/* number of extents in attribute fork*/
> >>  	__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 */
> >> diff --git a/fs/xfs/libxfs/xfs_inode_buf.c b/fs/xfs/libxfs/xfs_inode_buf.c
> >> index 9ed04da2e2b1..65d753e16007 100644
> >> --- a/fs/xfs/libxfs/xfs_inode_buf.c
> >> +++ b/fs/xfs/libxfs/xfs_inode_buf.c
> >> @@ -313,8 +313,8 @@ 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_nextents32 = cpu_to_be32(xfs_ifork_nextents(&ip->i_df));
> >> +	to->di_nextents16 = cpu_to_be16(xfs_ifork_nextents(ip->i_afp));
> >
> > /me wonders if these should get their own static inline conversion
> > helpers to set the appropriate fields, like I did for timestamps?
> >
> >>  	to->di_forkoff = ip->i_forkoff;
> >>  	to->di_aformat = xfs_ifork_format(ip->i_afp);
> >>  	to->di_flags = cpu_to_be16(ip->i_diflags);
> >> @@ -389,11 +389,11 @@ xfs_dfork_nextents(
> >>
> >>  	switch (whichfork) {
> >>  	case XFS_DATA_FORK:
> >> -		*nextents = be32_to_cpu(dip->di_nextents);
> >> +		*nextents = be32_to_cpu(dip->di_nextents32);
> >>  		break;
> >>
> >>  	case XFS_ATTR_FORK:
> >> -		*nextents = be16_to_cpu(dip->di_anextents);
> >> +		*nextents = be16_to_cpu(dip->di_nextents16);
> >>  		break;
> >>
> >>  	default:
> >> diff --git a/fs/xfs/libxfs/xfs_log_format.h b/fs/xfs/libxfs/xfs_log_format.h
> >> index 0c888f92184e..ca8e4ad8312a 100644
> >> --- a/fs/xfs/libxfs/xfs_log_format.h
> >> +++ b/fs/xfs/libxfs/xfs_log_format.h
> >> @@ -402,8 +402,8 @@ struct xfs_log_dinode {
> >>  	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 */
> >> -	xfs_extnum_t	di_nextents;	/* number of extents in data fork */
> >> -	xfs_aextnum_t	di_anextents;	/* number of extents in attribute fork*/
> >> +	uint32_t	di_nextents32;	/* number of extents in data fork */
> >> +	uint16_t	di_nextents16;	/* number of extents in attribute fork*/
> >>  	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 */
> >> diff --git a/fs/xfs/scrub/inode_repair.c b/fs/xfs/scrub/inode_repair.c
> >> index 521c8df00990..4d773a16f886 100644
> >> --- a/fs/xfs/scrub/inode_repair.c
> >> +++ b/fs/xfs/scrub/inode_repair.c
> >> @@ -736,7 +736,7 @@ xrep_dinode_zap_dfork(
> >>  {
> >>  	trace_xrep_dinode_zap_dfork(sc, dip);
> >>
> >> -	dip->di_nextents = 0;
> >> +	dip->di_nextents32 = 0;
> >>
> >>  	/* Special files always get reset to DEV */
> >>  	switch (mode & S_IFMT) {
> >> @@ -823,7 +823,7 @@ xrep_dinode_zap_afork(
> >>  	trace_xrep_dinode_zap_afork(sc, dip);
> >>
> >>  	dip->di_aformat = XFS_DINODE_FMT_EXTENTS;
> >> -	dip->di_anextents = 0;
> >> +	dip->di_nextents16 = 0;
> >>
> >>  	dip->di_forkoff = 0;
> >>  	dip->di_mode = cpu_to_be16(mode & ~0777);
> >> diff --git a/fs/xfs/scrub/trace.h b/fs/xfs/scrub/trace.h
> >> index fd03685b1f6b..a0303f692e52 100644
> >> --- a/fs/xfs/scrub/trace.h
> >> +++ b/fs/xfs/scrub/trace.h
> >> @@ -1209,8 +1209,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
> >>  		__field(uint64_t, size)
> >>  		__field(uint64_t, nblocks)
> >>  		__field(uint32_t, extsize)
> >> -		__field(uint32_t, nextents)
> >> -		__field(uint16_t, anextents)
> >> +		__field(uint32_t, nextents32)
> >> +		__field(uint16_t, nextents16)
> >>  		__field(uint8_t, forkoff)
> >>  		__field(uint8_t, aformat)
> >>  		__field(uint16_t, flags)
> >> @@ -1229,8 +1229,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
> >>  		__entry->size = be64_to_cpu(dip->di_size);
> >>  		__entry->nblocks = be64_to_cpu(dip->di_nblocks);
> >>  		__entry->extsize = be32_to_cpu(dip->di_extsize);
> >> -		__entry->nextents = be32_to_cpu(dip->di_nextents);
> >> -		__entry->anextents = be16_to_cpu(dip->di_anextents);
> >> +		__entry->nextents32 = be32_to_cpu(dip->di_nextents32);
> >> +		__entry->nextents16 = be16_to_cpu(dip->di_nextents16);
> >>  		__entry->forkoff = dip->di_forkoff;
> >>  		__entry->aformat = dip->di_aformat;
> >>  		__entry->flags = be16_to_cpu(dip->di_flags);
> >> @@ -1238,7 +1238,7 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
> >>  		__entry->flags2 = be64_to_cpu(dip->di_flags2);
> >>  		__entry->cowextsize = be32_to_cpu(dip->di_cowextsize);
> >>  	),
> >> -	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents %u anextents %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
> >> +	TP_printk("dev %d:%d ino 0x%llx mode 0x%x version %u format %u uid %u gid %u size %llu nblocks %llu extsize %u nextents32 %u nextents16 %u forkoff %u aformat %u flags 0x%x gen 0x%x flags2 0x%llx cowextsize %u",
> >>  		  MAJOR(__entry->dev), MINOR(__entry->dev),
> >>  		  __entry->ino,
> >>  		  __entry->mode,
> >> @@ -1249,8 +1249,8 @@ DECLARE_EVENT_CLASS(xrep_dinode_class,
> >>  		  __entry->size,
> >>  		  __entry->nblocks,
> >>  		  __entry->extsize,
> >> -		  __entry->nextents,
> >> -		  __entry->anextents,
> >> +		  __entry->nextents32,
> >> +		  __entry->nextents16,
> >>  		  __entry->forkoff,
> >>  		  __entry->aformat,
> >>  		  __entry->flags,
> >> diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c
> >> index 35de30849fcc..f54ce7468ba1 100644
> >> --- a/fs/xfs/xfs_inode_item.c
> >> +++ b/fs/xfs/xfs_inode_item.c
> >> @@ -385,8 +385,8 @@ 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_nextents32 = xfs_ifork_nextents(&ip->i_df);
> >> +	to->di_nextents16 = 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;
> >> diff --git a/fs/xfs/xfs_inode_item_recover.c b/fs/xfs/xfs_inode_item_recover.c
> >> index 7b79518b6c20..40af9d1265c7 100644
> >> --- a/fs/xfs/xfs_inode_item_recover.c
> >> +++ b/fs/xfs/xfs_inode_item_recover.c
> >> @@ -166,8 +166,8 @@ xfs_log_dinode_to_disk(
> >>  	to->di_size = cpu_to_be64(from->di_size);
> >>  	to->di_nblocks = cpu_to_be64(from->di_nblocks);
> >>  	to->di_extsize = cpu_to_be32(from->di_extsize);
> >> -	to->di_nextents = cpu_to_be32(from->di_nextents);
> >> -	to->di_anextents = cpu_to_be16(from->di_anextents);
> >> +	to->di_nextents32 = cpu_to_be32(from->di_nextents32);
> >> +	to->di_nextents16 = cpu_to_be16(from->di_nextents16);
> >>  	to->di_forkoff = from->di_forkoff;
> >>  	to->di_aformat = from->di_aformat;
> >>  	to->di_dmevmask = cpu_to_be32(from->di_dmevmask);
> >> @@ -332,7 +332,7 @@ xlog_recover_inode_commit_pass2(
> >>  			goto out_release;
> >>  		}
> >>  	}
> >> -	if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){
> >> +	if (unlikely(ldip->di_nextents32 + ldip->di_nextents16 > ldip->di_nblocks)) {
> >>  		XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)",
> >>  				     XFS_ERRLEVEL_LOW, mp, ldip,
> >>  				     sizeof(*ldip));
> >> @@ -340,7 +340,7 @@ xlog_recover_inode_commit_pass2(
> >>  	"%s: Bad inode log record, rec ptr "PTR_FMT", dino ptr "PTR_FMT", "
> >>  	"dino bp "PTR_FMT", ino %Ld, total extents = %d, nblocks = %Ld",
> >>  			__func__, item, dip, bp, in_f->ilf_ino,
> >> -			ldip->di_nextents + ldip->di_anextents,
> >> +			ldip->di_nextents32 + ldip->di_nextents16,
> >>  			ldip->di_nblocks);
> >>  		error = -EFSCORRUPTED;
> >>  		goto out_release;
> >> --
> >> 2.30.2
> >>
> 
> 
> --
> chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count
  2021-07-28  7:38       ` Chandan Babu R
@ 2021-07-28 19:06         ` Darrick J. Wong
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-28 19:06 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Wed, Jul 28, 2021 at 01:08:35PM +0530, Chandan Babu R wrote:
> On 28 Jul 2021 at 12:53, Chandan Babu R wrote:
> > On 28 Jul 2021 at 04:40, Darrick J. Wong wrote:
> >> On Mon, Jul 26, 2021 at 05:15:41PM +0530, Chandan Babu R wrote:
> >>> This commit adds a new error tag to allow user space tests to check if V5
> >>> bulkstat ioctl skips reporting inodes with large extent count.
> >>>
> >>> Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> >>
> >> Keep in mind that each of these injection knobs costs us 4 bytes per
> >> mount.  No particular objections, but I don't know how urgently we need
> >> to do that to test a corner case...
> >>
> >
> > How about using the existing error tag XFS_RANDOM_REDUCE_MAX_IEXTENTS instead
> > of creating a new one? XFS_RANDOM_REDUCE_MAX_IEXTENTS conveys the meaning that
> > we use a pseudo max data/attr fork extent count. IMHO this fits into the
> > bulkstat testing use case where we use a pseudo max data fork extent count.
> 
> Sorry, I actually meant to refer to XFS_ERRTAG_REDUCE_MAX_IEXTENTS instead of
> XFS_RANDOM_REDUCE_MAX_IEXTENTS.

Works for me!

--D

> 
> -- 
> chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 00/12] xfs: Extend per-inode extent counters
  2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
                   ` (11 preceding siblings ...)
  2021-07-26 11:45 ` [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count Chandan Babu R
@ 2021-07-28 21:27 ` Darrick J. Wong
  2021-07-29  6:40   ` Chandan Babu R
  12 siblings, 1 reply; 45+ messages in thread
From: Darrick J. Wong @ 2021-07-28 21:27 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Jul 26, 2021 at 05:15:29PM +0530, Chandan Babu R wrote:
> The commit xfs: fix inode fork extent count overflow
> (3f8a4f1d876d3e3e49e50b0396eaffcc4ba71b08) mentions that 10 billion
> data fork extents should be possible to create. However the
> corresponding on-disk field has a signed 32-bit type. Hence this
> patchset extends the per-inode data extent counter to 64 bits out of
> which 48 bits are used to store the extent count. 

A few other random notes that don't fit anywhere:

If you decide to enable upgrades by adding an XFS_DIFLAG2 to indicate
that a particular file has large extent counts, I think you can copy the
same mechanisms that the DIFLAG2_BIGTIME flag uses as a template.  I
think you'd need an extra bit of logic in xfs_trans_log_inode to turn on
the feature bit and move the n*extents fields around if either extent
count exceeds the old limits.

Please export the NREXT64 feature flag via an XFS_FSOP_GEOM flag so that
userspace can detect support for having a lot of extents.  This will
make it easy for libfrog to figure out that it should set the "send
large extent counts" bulkstat flag.  It'll also make it easier to
perform feature detection in fstests.

--D

> Also, XFS has an attr fork extent counter which is 16 bits wide. A
> workload which,
> 1. Creates 1 million 255-byte sized xattrs,
> 2. Deletes 50% of these xattrs in an alternating manner,
> 3. Tries to insert 400,000 new 255-byte sized xattrs
>    causes the xattr extent counter to overflow.
> 
> Dave tells me that there are instances where a single file has more
> than 100 million hardlinks. With parent pointers being stored in
> xattrs, we will overflow the signed 16-bits wide xattr extent counter
> when large number of hardlinks are created. Hence this patchset
> extends the on-disk field to 32-bits.
> 
> The following changes are made to accomplish this,
> 1. A new incompat superblock flag to prevent older kernels from mounting
>    the filesystem. This flag has to be set during mkfs time.
> 2. A new 64-bit inode field is created to hold the data extent
>    counter.
> 3. The existing 32-bit inode data extent counter will be used to hold
>    the attr fork extent counter.
> 
> The patchset has been tested by executing xfstests with the following
> mkfs.xfs options,
> 1. -m crc=0 -b size=1k
> 2. -m crc=0 -b size=4k
> 3. -m crc=0 -b size=512
> 4. -m rmapbt=1,reflink=1 -b size=1k
> 5. -m rmapbt=1,reflink=1 -b size=4k
> 
> Each of the above test scenarios were executed on the following
> combinations (For V4 FS test scenario, the last combination
> i.e. "Patched (enable extcnt64bit)", was omitted).
> |-------------------------------+-----------|
> | Xfsprogs                      | Kernel    |
> |-------------------------------+-----------|
> | Unpatched                     | Patched   |
> | Patched (disable extcnt64bit) | Unpatched |
> | Patched (disable extcnt64bit) | Patched   |
> | Patched (enable extcnt64bit)  | Patched   |
> |-------------------------------+-----------|
> 
> I have also written a test (yet to be converted into xfstests format)
> to check if the correct extent counter fields are updated with/without
> the new incompat flag. I have also fixed some of the existing fstests
> to work with the new extent counter fields.
> 
> Increasing data extent counter width also causes the maximum height of
> BMBT to increase. This requires that the macro XFS_BTREE_MAXLEVELS be
> updated with a larger value. However such a change causes the value of
> mp->m_rmap_maxlevels to increase which in turn causes log reservation
> sizes to increase and hence a modified XFS driver will fail to mount
> filesystems created by older versions of mkfs.xfs.
> 
> Hence this patchset is built on top of Darrick's btree-dynamic-depth
> branch which removes the macro XFS_BTREE_MAXLEVELS and computes
> mp->m_rmap_maxlevels based on the size of an AG.
> 
> These patches can also be obtained from
> https://github.com/chandanr/linux.git at branch
> xfs-incompat-extend-extcnt-v2.
> 
> I will be posting the changes associated with xfsprogs separately.
> 
> Changelog:
> V1 -> V2:
> 1. Rebase patches on top of Darrick's btree-dynamic-depth branch.
> 2. Add new bulkstat ioctl version to support 64-bit data fork extent
>    counter field.
> 3. Introduce new error tag to verify if the old bulkstat ioctls skip
>    reporting inodes with large data fork extent counters.
> 
> Chandan Babu R (12):
>   xfs: Move extent count limits to xfs_format.h
>   xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32,
>     XFS_IFORK_EXTCNT_MAXS16
>   xfs: Introduce xfs_iext_max() helper
>   xfs: Use xfs_extnum_t instead of basic data types
>   xfs: Introduce xfs_dfork_nextents() helper
>   xfs: xfs_dfork_nextents: Return extent count via an out argument
>   xfs: Rename inode's extent counter fields based on their width
>   xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits
>     respectively
>   xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
>   xfs: Enable bulkstat ioctl to support 64-bit extent counters
>   xfs: Extend per-inode extent counter widths
>   xfs: Error tag to test if v5 bulkstat skips inodes with large extent
>     count
> 
>  fs/xfs/libxfs/xfs_bmap.c        | 21 +++----
>  fs/xfs/libxfs/xfs_errortag.h    |  4 +-
>  fs/xfs/libxfs/xfs_format.h      | 42 +++++++++++---
>  fs/xfs/libxfs/xfs_fs.h          |  9 ++-
>  fs/xfs/libxfs/xfs_inode_buf.c   | 82 ++++++++++++++++++++++++----
>  fs/xfs/libxfs/xfs_inode_buf.h   |  2 +
>  fs/xfs/libxfs/xfs_inode_fork.c  | 35 +++++++++---
>  fs/xfs/libxfs/xfs_inode_fork.h  | 22 +++++++-
>  fs/xfs/libxfs/xfs_log_format.h  |  7 ++-
>  fs/xfs/libxfs/xfs_types.h       | 11 +---
>  fs/xfs/scrub/attr_repair.c      |  2 +-
>  fs/xfs/scrub/inode.c            | 97 ++++++++++++++++++++-------------
>  fs/xfs/scrub/inode_repair.c     | 71 +++++++++++++++++-------
>  fs/xfs/scrub/trace.h            | 16 +++---
>  fs/xfs/xfs_error.c              |  3 +
>  fs/xfs/xfs_inode.c              |  4 +-
>  fs/xfs/xfs_inode_item.c         | 15 ++++-
>  fs/xfs/xfs_inode_item_recover.c | 25 +++++++--
>  fs/xfs/xfs_ioctl.c              | 33 +++++++++--
>  fs/xfs/xfs_ioctl32.c            |  7 +++
>  fs/xfs/xfs_itable.c             | 35 ++++++++++--
>  fs/xfs/xfs_itable.h             |  1 +
>  fs/xfs/xfs_trace.h              |  6 +-
>  23 files changed, 402 insertions(+), 148 deletions(-)
> 
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 00/12] xfs: Extend per-inode extent counters
  2021-07-28 21:27 ` [PATCH V2 00/12] xfs: Extend per-inode extent counters Darrick J. Wong
@ 2021-07-29  6:40   ` Chandan Babu R
  0 siblings, 0 replies; 45+ messages in thread
From: Chandan Babu R @ 2021-07-29  6:40 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 29 Jul 2021 at 02:57, Darrick J. Wong wrote:
> On Mon, Jul 26, 2021 at 05:15:29PM +0530, Chandan Babu R wrote:
>> The commit xfs: fix inode fork extent count overflow
>> (3f8a4f1d876d3e3e49e50b0396eaffcc4ba71b08) mentions that 10 billion
>> data fork extents should be possible to create. However the
>> corresponding on-disk field has a signed 32-bit type. Hence this
>> patchset extends the per-inode data extent counter to 64 bits out of
>> which 48 bits are used to store the extent count.
>
> A few other random notes that don't fit anywhere:
>
> If you decide to enable upgrades by adding an XFS_DIFLAG2 to indicate
> that a particular file has large extent counts, I think you can copy the
> same mechanisms that the DIFLAG2_BIGTIME flag uses as a template.  I
> think you'd need an extra bit of logic in xfs_trans_log_inode to turn on
> the feature bit and move the n*extents fields around if either extent
> count exceeds the old limits.
>

Ok. I will start implementing the upgrade feature unless objections are raised
by other developers.

> Please export the NREXT64 feature flag via an XFS_FSOP_GEOM flag so that
> userspace can detect support for having a lot of extents.  This will
> make it easy for libfrog to figure out that it should set the "send
> large extent counts" bulkstat flag.  It'll also make it easier to
> perform feature detection in fstests.

Sure. I will implement this as well.

Thanks for the suggestions.

>
> --D
>
>> Also, XFS has an attr fork extent counter which is 16 bits wide. A
>> workload which,
>> 1. Creates 1 million 255-byte sized xattrs,
>> 2. Deletes 50% of these xattrs in an alternating manner,
>> 3. Tries to insert 400,000 new 255-byte sized xattrs
>>    causes the xattr extent counter to overflow.
>>
>> Dave tells me that there are instances where a single file has more
>> than 100 million hardlinks. With parent pointers being stored in
>> xattrs, we will overflow the signed 16-bits wide xattr extent counter
>> when large number of hardlinks are created. Hence this patchset
>> extends the on-disk field to 32-bits.
>>
>> The following changes are made to accomplish this,
>> 1. A new incompat superblock flag to prevent older kernels from mounting
>>    the filesystem. This flag has to be set during mkfs time.
>> 2. A new 64-bit inode field is created to hold the data extent
>>    counter.
>> 3. The existing 32-bit inode data extent counter will be used to hold
>>    the attr fork extent counter.
>>
>> The patchset has been tested by executing xfstests with the following
>> mkfs.xfs options,
>> 1. -m crc=0 -b size=1k
>> 2. -m crc=0 -b size=4k
>> 3. -m crc=0 -b size=512
>> 4. -m rmapbt=1,reflink=1 -b size=1k
>> 5. -m rmapbt=1,reflink=1 -b size=4k
>>
>> Each of the above test scenarios were executed on the following
>> combinations (For V4 FS test scenario, the last combination
>> i.e. "Patched (enable extcnt64bit)", was omitted).
>> |-------------------------------+-----------|
>> | Xfsprogs                      | Kernel    |
>> |-------------------------------+-----------|
>> | Unpatched                     | Patched   |
>> | Patched (disable extcnt64bit) | Unpatched |
>> | Patched (disable extcnt64bit) | Patched   |
>> | Patched (enable extcnt64bit)  | Patched   |
>> |-------------------------------+-----------|
>>
>> I have also written a test (yet to be converted into xfstests format)
>> to check if the correct extent counter fields are updated with/without
>> the new incompat flag. I have also fixed some of the existing fstests
>> to work with the new extent counter fields.
>>
>> Increasing data extent counter width also causes the maximum height of
>> BMBT to increase. This requires that the macro XFS_BTREE_MAXLEVELS be
>> updated with a larger value. However such a change causes the value of
>> mp->m_rmap_maxlevels to increase which in turn causes log reservation
>> sizes to increase and hence a modified XFS driver will fail to mount
>> filesystems created by older versions of mkfs.xfs.
>>
>> Hence this patchset is built on top of Darrick's btree-dynamic-depth
>> branch which removes the macro XFS_BTREE_MAXLEVELS and computes
>> mp->m_rmap_maxlevels based on the size of an AG.
>>
>> These patches can also be obtained from
>> https://github.com/chandanr/linux.git at branch
>> xfs-incompat-extend-extcnt-v2.
>>
>> I will be posting the changes associated with xfsprogs separately.
>>
>> Changelog:
>> V1 -> V2:
>> 1. Rebase patches on top of Darrick's btree-dynamic-depth branch.
>> 2. Add new bulkstat ioctl version to support 64-bit data fork extent
>>    counter field.
>> 3. Introduce new error tag to verify if the old bulkstat ioctls skip
>>    reporting inodes with large data fork extent counters.
>>
>> Chandan Babu R (12):
>>   xfs: Move extent count limits to xfs_format.h
>>   xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32,
>>     XFS_IFORK_EXTCNT_MAXS16
>>   xfs: Introduce xfs_iext_max() helper
>>   xfs: Use xfs_extnum_t instead of basic data types
>>   xfs: Introduce xfs_dfork_nextents() helper
>>   xfs: xfs_dfork_nextents: Return extent count via an out argument
>>   xfs: Rename inode's extent counter fields based on their width
>>   xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits
>>     respectively
>>   xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5
>>   xfs: Enable bulkstat ioctl to support 64-bit extent counters
>>   xfs: Extend per-inode extent counter widths
>>   xfs: Error tag to test if v5 bulkstat skips inodes with large extent
>>     count
>>
>>  fs/xfs/libxfs/xfs_bmap.c        | 21 +++----
>>  fs/xfs/libxfs/xfs_errortag.h    |  4 +-
>>  fs/xfs/libxfs/xfs_format.h      | 42 +++++++++++---
>>  fs/xfs/libxfs/xfs_fs.h          |  9 ++-
>>  fs/xfs/libxfs/xfs_inode_buf.c   | 82 ++++++++++++++++++++++++----
>>  fs/xfs/libxfs/xfs_inode_buf.h   |  2 +
>>  fs/xfs/libxfs/xfs_inode_fork.c  | 35 +++++++++---
>>  fs/xfs/libxfs/xfs_inode_fork.h  | 22 +++++++-
>>  fs/xfs/libxfs/xfs_log_format.h  |  7 ++-
>>  fs/xfs/libxfs/xfs_types.h       | 11 +---
>>  fs/xfs/scrub/attr_repair.c      |  2 +-
>>  fs/xfs/scrub/inode.c            | 97 ++++++++++++++++++++-------------
>>  fs/xfs/scrub/inode_repair.c     | 71 +++++++++++++++++-------
>>  fs/xfs/scrub/trace.h            | 16 +++---
>>  fs/xfs/xfs_error.c              |  3 +
>>  fs/xfs/xfs_inode.c              |  4 +-
>>  fs/xfs/xfs_inode_item.c         | 15 ++++-
>>  fs/xfs/xfs_inode_item_recover.c | 25 +++++++--
>>  fs/xfs/xfs_ioctl.c              | 33 +++++++++--
>>  fs/xfs/xfs_ioctl32.c            |  7 +++
>>  fs/xfs/xfs_itable.c             | 35 ++++++++++--
>>  fs/xfs/xfs_itable.h             |  1 +
>>  fs/xfs/xfs_trace.h              |  6 +-
>>  23 files changed, 402 insertions(+), 148 deletions(-)
>>
>> --
>> 2.30.2
>>

--
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-07-28  3:15       ` Chandan Babu R
@ 2021-08-23  4:18         ` Chandan Babu R
  2021-08-23  7:17           ` Chandan Babu R
  0 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-08-23  4:18 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 28 Jul 2021 at 08:45, Chandan Babu R wrote:
> On 28 Jul 2021 at 03:33, Darrick J. Wong wrote:
>> On Tue, Jul 27, 2021 at 02:56:11PM -0700, Darrick J. Wong wrote:
>>> On Mon, Jul 26, 2021 at 05:15:31PM +0530, Chandan Babu R wrote:
>>> > In preparation for introducing larger extent count limits, this commit renames
>>> > existing extent count limits based on their signedness and width.
>>> > 
>>> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>>> > ---
>>> >  fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
>>> >  fs/xfs/libxfs/xfs_format.h     | 8 ++++----
>>> >  fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
>>> >  fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
>>> >  fs/xfs/scrub/inode_repair.c    | 2 +-
>>> >  5 files changed, 11 insertions(+), 10 deletions(-)
>>> > 
>>> > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>>> > index f3c9a0ebb0a5..8f262405a5b5 100644
>>> > --- a/fs/xfs/libxfs/xfs_bmap.c
>>> > +++ b/fs/xfs/libxfs/xfs_bmap.c
>>> > @@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
>>> >  	 * available.
>>> >  	 */
>>> >  	if (whichfork == XFS_DATA_FORK) {
>>> > -		maxleafents = MAXEXTNUM;
>>> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
>>> 
>>> I'm not in love with these names, since they tell me roughly about the
>>> size of the constant (which I could glean from the definition) but less
>>> about when I would expect to find them.  How about:
>>> 
>>> #define XFS_MAX_DFORK_NEXTENTS    ((xfs_extnum_t) 0x7FFFFFFF)
>>> #define XFS_MAX_AFORK_NEXTENTS    ((xfs_aextnum_t)0x00007FFF)
>>
>> Or, given that 'DFORK' already means 'ondisk fork', how about:
>>
>> XFS_MAX_DATA_NEXTENTS
>> XFS_MAX_ATTR_NEXTENTS
>
> Yes, I agree. These names are better. I will incorporate your suggestions
> before posting V3.
>

Using XFS_MAX_[ATTR|DATA]_NEXTENTS won't be feasible later in the patch series
since the maximum extent count for the two inode forks depend on whether
XFS_SB_FEAT_INCOMPAT_NREXT64 feature bit is set or not. With the incompat
feature bit set, extent counts for attr and data forks can have maximum values
of (2^32 - 1) and (2^48 - 1) respectively. With the incompat feature bit not
set, extent counts for attr and data forks can have maximum values of (2^15 -
1) and (2^31 - 1) respectively.

Also, xfs_iext_max_nextents() (an inline function introduced in the next patch
in this series) abstracts away the logic of determining the maximum extent
count for an inode fork.

-- 
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-08-23  4:18         ` Chandan Babu R
@ 2021-08-23  7:17           ` Chandan Babu R
  2021-08-23 18:16             ` Darrick J. Wong
  0 siblings, 1 reply; 45+ messages in thread
From: Chandan Babu R @ 2021-08-23  7:17 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 23 Aug 2021 at 09:48, Chandan Babu R wrote:
> On 28 Jul 2021 at 08:45, Chandan Babu R wrote:
>> On 28 Jul 2021 at 03:33, Darrick J. Wong wrote:
>>> On Tue, Jul 27, 2021 at 02:56:11PM -0700, Darrick J. Wong wrote:
>>>> On Mon, Jul 26, 2021 at 05:15:31PM +0530, Chandan Babu R wrote:
>>>> > In preparation for introducing larger extent count limits, this commit renames
>>>> > existing extent count limits based on their signedness and width.
>>>> > 
>>>> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
>>>> > ---
>>>> >  fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
>>>> >  fs/xfs/libxfs/xfs_format.h     | 8 ++++----
>>>> >  fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
>>>> >  fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
>>>> >  fs/xfs/scrub/inode_repair.c    | 2 +-
>>>> >  5 files changed, 11 insertions(+), 10 deletions(-)
>>>> > 
>>>> > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
>>>> > index f3c9a0ebb0a5..8f262405a5b5 100644
>>>> > --- a/fs/xfs/libxfs/xfs_bmap.c
>>>> > +++ b/fs/xfs/libxfs/xfs_bmap.c
>>>> > @@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
>>>> >  	 * available.
>>>> >  	 */
>>>> >  	if (whichfork == XFS_DATA_FORK) {
>>>> > -		maxleafents = MAXEXTNUM;
>>>> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
>>>> 
>>>> I'm not in love with these names, since they tell me roughly about the
>>>> size of the constant (which I could glean from the definition) but less
>>>> about when I would expect to find them.  How about:
>>>> 
>>>> #define XFS_MAX_DFORK_NEXTENTS    ((xfs_extnum_t) 0x7FFFFFFF)
>>>> #define XFS_MAX_AFORK_NEXTENTS    ((xfs_aextnum_t)0x00007FFF)
>>>
>>> Or, given that 'DFORK' already means 'ondisk fork', how about:
>>>
>>> XFS_MAX_DATA_NEXTENTS
>>> XFS_MAX_ATTR_NEXTENTS
>>
>> Yes, I agree. These names are better. I will incorporate your suggestions
>> before posting V3.
>>
>
> Using XFS_MAX_[ATTR|DATA]_NEXTENTS won't be feasible later in the patch series
> since the maximum extent count for the two inode forks depend on whether
> XFS_SB_FEAT_INCOMPAT_NREXT64 feature bit is set or not. With the incompat
> feature bit set, extent counts for attr and data forks can have maximum values
> of (2^32 - 1) and (2^48 - 1) respectively. With the incompat feature bit not
> set, extent counts for attr and data forks can have maximum values of (2^15 -
> 1) and (2^31 - 1) respectively.
>
> Also, xfs_iext_max_nextents() (an inline function introduced in the next patch
> in this series) abstracts away the logic of determining the maximum extent
> count for an inode fork.

I think introducing xfs_iext_max_nextents() before renaming the max extent
counter macros would reduce proliferation of XFS_IFORK_EXTCNT_MAX* macros
across the source code. If you are ok with it, I will reorder the current
patch and the next patch.

-- 
chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

* Re: [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16
  2021-08-23  7:17           ` Chandan Babu R
@ 2021-08-23 18:16             ` Darrick J. Wong
  0 siblings, 0 replies; 45+ messages in thread
From: Darrick J. Wong @ 2021-08-23 18:16 UTC (permalink / raw)
  To: Chandan Babu R; +Cc: linux-xfs

On Mon, Aug 23, 2021 at 12:47:43PM +0530, Chandan Babu R wrote:
> On 23 Aug 2021 at 09:48, Chandan Babu R wrote:
> > On 28 Jul 2021 at 08:45, Chandan Babu R wrote:
> >> On 28 Jul 2021 at 03:33, Darrick J. Wong wrote:
> >>> On Tue, Jul 27, 2021 at 02:56:11PM -0700, Darrick J. Wong wrote:
> >>>> On Mon, Jul 26, 2021 at 05:15:31PM +0530, Chandan Babu R wrote:
> >>>> > In preparation for introducing larger extent count limits, this commit renames
> >>>> > existing extent count limits based on their signedness and width.
> >>>> > 
> >>>> > Signed-off-by: Chandan Babu R <chandanrlinux@gmail.com>
> >>>> > ---
> >>>> >  fs/xfs/libxfs/xfs_bmap.c       | 4 ++--
> >>>> >  fs/xfs/libxfs/xfs_format.h     | 8 ++++----
> >>>> >  fs/xfs/libxfs/xfs_inode_buf.c  | 4 ++--
> >>>> >  fs/xfs/libxfs/xfs_inode_fork.c | 3 ++-
> >>>> >  fs/xfs/scrub/inode_repair.c    | 2 +-
> >>>> >  5 files changed, 11 insertions(+), 10 deletions(-)
> >>>> > 
> >>>> > diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
> >>>> > index f3c9a0ebb0a5..8f262405a5b5 100644
> >>>> > --- a/fs/xfs/libxfs/xfs_bmap.c
> >>>> > +++ b/fs/xfs/libxfs/xfs_bmap.c
> >>>> > @@ -76,10 +76,10 @@ xfs_bmap_compute_maxlevels(
> >>>> >  	 * available.
> >>>> >  	 */
> >>>> >  	if (whichfork == XFS_DATA_FORK) {
> >>>> > -		maxleafents = MAXEXTNUM;
> >>>> > +		maxleafents = XFS_IFORK_EXTCNT_MAXS32;
> >>>> 
> >>>> I'm not in love with these names, since they tell me roughly about the
> >>>> size of the constant (which I could glean from the definition) but less
> >>>> about when I would expect to find them.  How about:
> >>>> 
> >>>> #define XFS_MAX_DFORK_NEXTENTS    ((xfs_extnum_t) 0x7FFFFFFF)
> >>>> #define XFS_MAX_AFORK_NEXTENTS    ((xfs_aextnum_t)0x00007FFF)
> >>>
> >>> Or, given that 'DFORK' already means 'ondisk fork', how about:
> >>>
> >>> XFS_MAX_DATA_NEXTENTS
> >>> XFS_MAX_ATTR_NEXTENTS
> >>
> >> Yes, I agree. These names are better. I will incorporate your suggestions
> >> before posting V3.
> >>
> >
> > Using XFS_MAX_[ATTR|DATA]_NEXTENTS won't be feasible later in the patch series
> > since the maximum extent count for the two inode forks depend on whether
> > XFS_SB_FEAT_INCOMPAT_NREXT64 feature bit is set or not. With the incompat
> > feature bit set, extent counts for attr and data forks can have maximum values
> > of (2^32 - 1) and (2^48 - 1) respectively. With the incompat feature bit not
> > set, extent counts for attr and data forks can have maximum values of (2^15 -
> > 1) and (2^31 - 1) respectively.
> >
> > Also, xfs_iext_max_nextents() (an inline function introduced in the next patch
> > in this series) abstracts away the logic of determining the maximum extent
> > count for an inode fork.
> 
> I think introducing xfs_iext_max_nextents() before renaming the max extent
> counter macros would reduce proliferation of XFS_IFORK_EXTCNT_MAX* macros
> across the source code. If you are ok with it, I will reorder the current
> patch and the next patch.

Sounds good to me. :)

--D

> -- 
> chandan

^ permalink raw reply	[flat|nested] 45+ messages in thread

end of thread, other threads:[~2021-08-23 18:16 UTC | newest]

Thread overview: 45+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-26 11:45 [PATCH V2 00/12] xfs: Extend per-inode extent counters Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 01/12] xfs: Move extent count limits to xfs_format.h Chandan Babu R
2021-07-26 18:00   ` Darrick J. Wong
2021-07-27  8:07     ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 02/12] xfs: Rename MAXEXTNUM, MAXAEXTNUM to XFS_IFORK_EXTCNT_MAXS32, XFS_IFORK_EXTCNT_MAXS16 Chandan Babu R
2021-07-27 21:56   ` Darrick J. Wong
2021-07-27 22:03     ` Darrick J. Wong
2021-07-28  3:15       ` Chandan Babu R
2021-08-23  4:18         ` Chandan Babu R
2021-08-23  7:17           ` Chandan Babu R
2021-08-23 18:16             ` Darrick J. Wong
2021-07-26 11:45 ` [PATCH V2 03/12] xfs: Introduce xfs_iext_max() helper Chandan Babu R
2021-07-27 21:58   ` Darrick J. Wong
2021-07-28  3:17     ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 04/12] xfs: Use xfs_extnum_t instead of basic data types Chandan Babu R
2021-07-27 21:59   ` Darrick J. Wong
2021-07-28  3:38     ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 05/12] xfs: Introduce xfs_dfork_nextents() helper Chandan Babu R
2021-07-27 22:10   ` Darrick J. Wong
2021-07-28  4:06     ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 06/12] xfs: xfs_dfork_nextents: Return extent count via an out argument Chandan Babu R
2021-07-27 22:22   ` Darrick J. Wong
2021-07-28  4:21     ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 07/12] xfs: Rename inode's extent counter fields based on their width Chandan Babu R
2021-07-27 22:50   ` Darrick J. Wong
2021-07-28  5:48     ` Chandan Babu R
2021-07-28 19:04       ` Darrick J. Wong
2021-07-26 11:45 ` [PATCH V2 08/12] xfs: Promote xfs_extnum_t and xfs_aextnum_t to 64 and 32-bits respectively Chandan Babu R
2021-07-27 22:29   ` Darrick J. Wong
2021-07-26 11:45 ` [PATCH V2 09/12] xfs: Rename XFS_IOC_BULKSTAT to XFS_IOC_BULKSTAT_V5 Chandan Babu R
2021-07-27 22:54   ` Darrick J. Wong
2021-07-27 23:00     ` Darrick J. Wong
2021-07-27 23:17       ` Dave Chinner
2021-07-28  6:56         ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 10/12] xfs: Enable bulkstat ioctl to support 64-bit extent counters Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 11/12] xfs: Extend per-inode extent counter widths Chandan Babu R
2021-07-27 23:09   ` Darrick J. Wong
2021-07-28  7:17     ` Chandan Babu R
2021-07-26 11:45 ` [PATCH V2 12/12] xfs: Error tag to test if v5 bulkstat skips inodes with large extent count Chandan Babu R
2021-07-27 23:10   ` Darrick J. Wong
2021-07-28  7:23     ` Chandan Babu R
2021-07-28  7:38       ` Chandan Babu R
2021-07-28 19:06         ` Darrick J. Wong
2021-07-28 21:27 ` [PATCH V2 00/12] xfs: Extend per-inode extent counters Darrick J. Wong
2021-07-29  6:40   ` Chandan Babu R

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).