public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 7/8] xfs_db: convert rtbitmap geometry
  2022-12-30 22:19 [PATCHSET v1.0 0/8] xfs_db: debug realtime geometry Darrick J. Wong
@ 2022-12-30 22:19 ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2022-12-30 22:19 UTC (permalink / raw)
  To: djwong, cem; +Cc: linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

Teach the rtconvert command to be able to convert realtime blocks and
extents to locations within the rt bitmap.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/convert.c      |   38 ++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   10 ++++++++++
 2 files changed, 48 insertions(+)


diff --git a/db/convert.c b/db/convert.c
index 811bac00f71..691361604ee 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -30,6 +30,10 @@
 	((uint64_t)(x) << mp->m_sb.sb_blocklog)
 #define rtx_to_rtblock(x)	\
 	((uint64_t)(x) * mp->m_sb.sb_rextsize)
+#define rbmblock_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock(xfs_rbmblock_to_rtx(mp, (uint64_t)x)))
+#define rbmword_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock((uint64_t)(x) << XFS_NBWORDLOG))
 
 typedef enum {
 	CT_NONE = -1,
@@ -46,6 +50,8 @@ typedef enum {
 	CT_INOOFF,		/* byte offset in inode */
 	CT_RTBLOCK,		/* realtime block */
 	CT_RTX,			/* realtime extent */
+	CT_RBMBLOCK,		/* block within rt bitmap */
+	CT_RBMWORD,		/* word within rt bitmap */
 	NCTS
 } ctype_t;
 
@@ -68,6 +74,8 @@ typedef union {
 	int		inooff;
 	xfs_rtblock_t	rtblock;
 	xfs_rtblock_t	rtx;
+	xfs_fileoff_t	rbmblock;
+	unsigned int	rbmword;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
@@ -94,6 +102,8 @@ static const char	*inooff_names[] = { "inooff", "inodeoff", NULL };
 
 static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
 static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
+static const char	*rbmblock_names[] = { "rbmblock", "rbmb", NULL };
+static const char	*rbmword_names[] = { "rbmword", "rbmw", NULL };
 
 static const ctydesc_t	ctydescs[NCTS] = {
 	[CT_AGBLOCK] = {
@@ -167,6 +177,14 @@ static const ctydesc_t	ctydescs_rt[NCTS] = {
 		.allowed = M(BBOFF)|M(BLKOFF),
 		.names   = rtx_names,
 	},
+	[CT_RBMBLOCK] = {
+		.allowed = M(RBMWORD),
+		.names   = rbmblock_names,
+	},
+	[CT_RBMWORD] = {
+		.allowed = M(RBMBLOCK),
+		.names   = rbmword_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
@@ -207,6 +225,10 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return rtblock_to_bytes(val->rtblock);
 	case CT_RTX:
 		return rtblock_to_bytes(rtx_to_rtblock(val->rtx));
+	case CT_RBMBLOCK:
+		return rbmblock_to_bytes(val->rbmblock);
+	case CT_RBMWORD:
+		return rbmword_to_bytes(val->rbmword);
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -308,6 +330,8 @@ convert_f(int argc, char **argv)
 		break;
 	case CT_RTBLOCK:
 	case CT_RTX:
+	case CT_RBMBLOCK:
+	case CT_RBMWORD:
 		/* shouldn't get here */
 		ASSERT(0);
 		break;
@@ -397,6 +421,14 @@ rtconvert_f(int argc, char **argv)
 	case CT_RTX:
 		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT) / mp->m_sb.sb_rextsize;
 		break;
+	case CT_RBMBLOCK:
+		v = xfs_rtx_to_rbmblock(mp, xfs_rtb_to_rtxt(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
+	case CT_RBMWORD:
+		v = xfs_rtx_to_rbmword(mp, xfs_rtb_to_rtxt(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
 	case CT_AGBLOCK:
 	case CT_AGINO:
 	case CT_AGNUMBER:
@@ -474,6 +506,12 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_RTX:
 		val->rtx = (xfs_rtblock_t)v;
 		break;
+	case CT_RBMBLOCK:
+		val->rbmblock = (xfs_fileoff_t)v;
+		break;
+	case CT_RBMWORD:
+		val->rbmword = (unsigned int)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 40ff7de335e..65d1a65b75f 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -999,6 +999,16 @@ command)
 or
 .B rtextent
 (realtime extent)
+.HP
+.B rbmblock
+or
+.B rbmb
+(realtime bitmap block)
+.HP
+.B rbmword
+or
+.B rbmw
+(32-bit word within a realtime bitmap block)
 .PD
 .RE
 .IP


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

* [PATCH 7/8] xfs_db: convert rtbitmap geometry
  2023-12-31 19:52 [PATCHSET v2.0 03/17] xfs_db: debug realtime geometry Darrick J. Wong
@ 2023-12-31 23:46 ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2023-12-31 23:46 UTC (permalink / raw)
  To: cem, djwong; +Cc: linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

Teach the rtconvert command to be able to convert realtime blocks and
extents to locations within the rt bitmap.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/convert.c      |   40 ++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   10 ++++++++++
 2 files changed, 50 insertions(+)


diff --git a/db/convert.c b/db/convert.c
index 811bac00f71..35e71f8a442 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -30,6 +30,10 @@
 	((uint64_t)(x) << mp->m_sb.sb_blocklog)
 #define rtx_to_rtblock(x)	\
 	((uint64_t)(x) * mp->m_sb.sb_rextsize)
+#define rbmblock_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock(xfs_rbmblock_to_rtx(mp, (uint64_t)x)))
+#define rbmword_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock((uint64_t)(x) << XFS_NBWORDLOG))
 
 typedef enum {
 	CT_NONE = -1,
@@ -46,6 +50,8 @@ typedef enum {
 	CT_INOOFF,		/* byte offset in inode */
 	CT_RTBLOCK,		/* realtime block */
 	CT_RTX,			/* realtime extent */
+	CT_RBMBLOCK,		/* block within rt bitmap */
+	CT_RBMWORD,		/* word within rt bitmap */
 	NCTS
 } ctype_t;
 
@@ -68,6 +74,8 @@ typedef union {
 	int		inooff;
 	xfs_rtblock_t	rtblock;
 	xfs_rtblock_t	rtx;
+	xfs_fileoff_t	rbmblock;
+	unsigned int	rbmword;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
@@ -94,6 +102,8 @@ static const char	*inooff_names[] = { "inooff", "inodeoff", NULL };
 
 static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
 static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
+static const char	*rbmblock_names[] = { "rbmblock", "rbmb", NULL };
+static const char	*rbmword_names[] = { "rbmword", "rbmw", NULL };
 
 static const ctydesc_t	ctydescs[NCTS] = {
 	[CT_AGBLOCK] = {
@@ -167,6 +177,14 @@ static const ctydesc_t	ctydescs_rt[NCTS] = {
 		.allowed = M(BBOFF)|M(BLKOFF),
 		.names   = rtx_names,
 	},
+	[CT_RBMBLOCK] = {
+		.allowed = M(RBMWORD),
+		.names   = rbmblock_names,
+	},
+	[CT_RBMWORD] = {
+		.allowed = M(RBMBLOCK),
+		.names   = rbmword_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
@@ -207,6 +225,10 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return rtblock_to_bytes(val->rtblock);
 	case CT_RTX:
 		return rtblock_to_bytes(rtx_to_rtblock(val->rtx));
+	case CT_RBMBLOCK:
+		return rbmblock_to_bytes(val->rbmblock);
+	case CT_RBMWORD:
+		return rbmword_to_bytes(val->rbmword);
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -308,6 +330,8 @@ convert_f(int argc, char **argv)
 		break;
 	case CT_RTBLOCK:
 	case CT_RTX:
+	case CT_RBMBLOCK:
+	case CT_RBMWORD:
 		/* shouldn't get here */
 		ASSERT(0);
 		break;
@@ -397,6 +421,16 @@ rtconvert_f(int argc, char **argv)
 	case CT_RTX:
 		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT) / mp->m_sb.sb_rextsize;
 		break;
+	case CT_RBMBLOCK:
+		v = xfs_rtx_to_rbmblock(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
+	case CT_RBMWORD:
+		v = xfs_rtx_to_rbmword(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
 	case CT_AGBLOCK:
 	case CT_AGINO:
 	case CT_AGNUMBER:
@@ -474,6 +508,12 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_RTX:
 		val->rtx = (xfs_rtblock_t)v;
 		break;
+	case CT_RBMBLOCK:
+		val->rbmblock = (xfs_fileoff_t)v;
+		break;
+	case CT_RBMWORD:
+		val->rbmword = (unsigned int)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index dc0bbfc9ac9..a1ea21162b5 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1098,6 +1098,16 @@ command)
 or
 .B rtextent
 (realtime extent)
+.HP
+.B rbmblock
+or
+.B rbmb
+(realtime bitmap block)
+.HP
+.B rbmword
+or
+.B rbmw
+(32-bit word within a realtime bitmap block)
 .PD
 .RE
 .IP


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

* [PATCHBOMB] xfsprogs: utility changes for 6.12
@ 2024-10-25  6:26 Darrick J. Wong
  2024-10-25  6:31 ` Darrick J. Wong
                   ` (5 more replies)
  0 siblings, 6 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:26 UTC (permalink / raw)
  To: Andrey Albershteyn; +Cc: xfs, Christoph Hellwig

Hi Andrey,

Here are all the changes to the xfsprogs utilities that I'd like to get
in for 6.12.  First we add support for the new exchange-range ioctl,
then wire up xfs_db support for realtime volumes in preparation for
future rt modernization.  Then there's some refactoring of mkfs, and a
bug fix for xfs_scrub_all.

None of these patches are reviewed.

--D

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

* Re: [PATCHBOMB] xfsprogs: utility changes for 6.12
  2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
@ 2024-10-25  6:31 ` Darrick J. Wong
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:31 UTC (permalink / raw)
  To: Andrey Albershteyn; +Cc: xfs, Christoph Hellwig

On Thu, Oct 24, 2024 at 11:26:02PM -0700, Darrick J. Wong wrote:
> Hi Andrey,
> 
> Here are all the changes to the xfsprogs utilities that I'd like to get
> in for 6.12.  First we add support for the new exchange-range ioctl,
> then wire up xfs_db support for realtime volumes in preparation for
> future rt modernization.  Then there's some refactoring of mkfs, and a
> bug fix for xfs_scrub_all.

And this is commitrange, not exchangerange.  We already did
exchangerange.

> None of these patches are reviewed.

Heh, sending patches too late at night after a too busy week.  Some of
these patches are reviewed; here are the ones that aren't:

[PATCHSET v31.2 1/5] xfsprogs: atomic file content commits
  [PATCH 1/7] man: document file range commit ioctls
  [PATCH 2/7] libfrog: add support for commit range ioctl family
  [PATCH 3/7] libxfs: remove unused xfs_inode fields
  [PATCH 4/7] libxfs: validate inumber in xfs_iget
  [PATCH 5/7] xfs_fsr: port to new file exchange library function
  [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange
  [PATCH 7/7] xfs_io: add atomic file update commands to exercise file
[PATCHSET v2.6 2/5] xfs_db: debug realtime geometry
  [PATCH 1/8] xfs_db: support passing the realtime device to the
  [PATCH 2/8] xfs_db: report the realtime device when associated with
  [PATCH 3/8] xfs_db: make the daddr command target the realtime device
  [PATCH 4/8] xfs_db: access realtime file blocks
  [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents
  [PATCH 6/8] xfs_db: enable conversion of rt space units
  [PATCH 7/8] xfs_db: convert rtbitmap geometry
  [PATCH 8/8] xfs_db: convert rtsummary geometry
[PATCHSET v2.6 3/5] xfs_metadump: support external devices
  [PATCH 1/1] xfs_db: allow setting current address to log blocks
[PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers
  [PATCH 1/6] xfs_repair: checking rt free space metadata must happen
[PATCHSET v31.2 5/5] xfs_scrub_all: bug fix for 6.12
  [PATCH 1/1] xfs_scrub_all: wait for services to start activating

--D

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

* [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits
  2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
  2024-10-25  6:31 ` Darrick J. Wong
@ 2024-10-25  6:31 ` Darrick J. Wong
  2024-10-25  6:32   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
                     ` (6 more replies)
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
                   ` (3 subsequent siblings)
  5 siblings, 7 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:31 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

Hi all,

This series creates XFS_IOC_START_COMMIT and XFS_IOC_COMMIT_RANGE ioctls
to perform the exchange only if the target file has not been changed
since a given sampling point.

This new functionality uses the mechanism underlying EXCHANGE_RANGE to
stage and commit file updates such that reader programs will see either
the old contents or the new contents in their entirety, with no chance
of torn writes.  A successful call completion guarantees that the new
contents will be seen even if the system fails.  The pair of ioctls
allows userspace to perform what amounts to a compare and exchange
operation on entire file contents.

Note that there are ongoing arguments in the community about how best to
implement some sort of file data write counter that nfsd could also use
to signal invalidations to clients.  Until such a thing is implemented,
this patch will rely on ctime/mtime updates.

If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.

Comments and questions are, as always, welcome.

kernel git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfs-linux.git/log/?h=atomic-file-commits-6.12

xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=atomic-file-commits-6.12
---
Commits in this patchset:
 * man: document file range commit ioctls
 * libfrog: add support for commit range ioctl family
 * libxfs: remove unused xfs_inode fields
 * libxfs: validate inumber in xfs_iget
 * xfs_fsr: port to new file exchange library function
 * xfs_io: add a commitrange option to the exchangerange command
 * xfs_io: add atomic file update commands to exercise file commit range
---
 fsr/xfs_fsr.c                     |   74 +++----
 include/xfs_inode.h               |    4 
 io/exchrange.c                    |  390 +++++++++++++++++++++++++++++++++++++
 io/io.h                           |    4 
 io/open.c                         |   27 ++-
 libfrog/file_exchange.c           |  194 ++++++++++++++++++
 libfrog/file_exchange.h           |   10 +
 libxfs/inode.c                    |    2 
 man/man2/ioctl_xfs_commit_range.2 |  296 ++++++++++++++++++++++++++++
 man/man2/ioctl_xfs_fsgeometry.2   |    2 
 man/man2/ioctl_xfs_start_commit.2 |    1 
 man/man8/xfs_io.8                 |   35 +++
 12 files changed, 983 insertions(+), 56 deletions(-)
 create mode 100644 man/man2/ioctl_xfs_commit_range.2
 create mode 100644 man/man2/ioctl_xfs_start_commit.2


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

* [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry
  2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
  2024-10-25  6:31 ` Darrick J. Wong
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
@ 2024-10-25  6:31 ` Darrick J. Wong
  2024-10-25  6:34   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
                     ` (7 more replies)
  2024-10-25  6:31 ` [PATCHSET v2.6 3/5] xfs_metadump: support external devices Darrick J. Wong
                   ` (2 subsequent siblings)
  5 siblings, 8 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:31 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

Hi all,

Before we start modernizing the realtime device, let's first make a few
improvements to the XFS debugger to make our lives easier.  First up is
making it so that users can point the debugger at the block device
containing the realtime section, and augmenting the io cursor code to be
able to read blocks from the rt device.  Next, we add a new geometry
conversion command (rtconvert) to make it easier to go back and forth
between rt blocks, rt extents, and the corresponding locations within
the rt bitmap and summary files.

If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.

Comments and questions are, as always, welcome.

xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=debug-realtime-geometry-6.12
---
Commits in this patchset:
 * xfs_db: support passing the realtime device to the debugger
 * xfs_db: report the realtime device when associated with each io cursor
 * xfs_db: make the daddr command target the realtime device
 * xfs_db: access realtime file blocks
 * xfs_db: access arbitrary realtime blocks and extents
 * xfs_db: enable conversion of rt space units
 * xfs_db: convert rtbitmap geometry
 * xfs_db: convert rtsummary geometry
---
 db/block.c        |  167 +++++++++++++++++++++-
 db/convert.c      |  409 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 db/faddr.c        |    4 -
 db/init.c         |    7 +
 db/io.c           |   39 ++++-
 db/io.h           |    3 
 db/xfs_admin.sh   |    4 -
 man/man8/xfs_db.8 |  129 +++++++++++++++++
 8 files changed, 722 insertions(+), 40 deletions(-)


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

* [PATCHSET v2.6 3/5] xfs_metadump: support external devices
  2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
                   ` (2 preceding siblings ...)
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
@ 2024-10-25  6:31 ` Darrick J. Wong
  2024-10-25  6:36   ` [PATCH 1/1] xfs_db: allow setting current address to log blocks Darrick J. Wong
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
  2024-10-25  6:32 ` [PATCHSET v31.2 5/5] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
  5 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:31 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

Hi all,

This series augments the xfs_metadump and xfs_mdrestore utilities to
capture the contents of an external log in a metadump, and restore it on
the other end.  This will enable better debugging analysis of broken
filesystems, since it will now be possible to capture external log data.
This is a prequisite for the rt groups feature, since we'll also need to
capture the rt superblocks written to the rt device.

This also means we can capture the contents of external logs for better
analysis by support staff.

If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.

Comments and questions are, as always, welcome.

xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=metadump-external-devices-6.12
---
Commits in this patchset:
 * xfs_db: allow setting current address to log blocks
---
 db/block.c        |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 man/man8/xfs_db.8 |   17 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)


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

* [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers
  2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
                   ` (3 preceding siblings ...)
  2024-10-25  6:31 ` [PATCHSET v2.6 3/5] xfs_metadump: support external devices Darrick J. Wong
@ 2024-10-25  6:32 ` Darrick J. Wong
  2024-10-25  6:36   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
                     ` (5 more replies)
  2024-10-25  6:32 ` [PATCHSET v31.2 5/5] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
  5 siblings, 6 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:32 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, linux-xfs, hch

Hi all,

Use the new rtfile helpers to create the rt bitmap and summary files instead of
duplicating the logic that the in-kernel growfs already had.

If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.

Comments and questions are, as always, welcome.

xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=misc-use-rtbitmap-helpers-6.12
---
Commits in this patchset:
 * xfs_repair: checking rt free space metadata must happen during phase 4
 * xfs_repair: use xfs_validate_rt_geometry
 * mkfs: remove a pointless rtfreesp_init forward declaration
 * mkfs: use xfs_rtfile_initialize_blocks
 * xfs_repair: use libxfs_rtfile_initialize_blocks
 * xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino
---
 libxfs/libxfs_api_defs.h |    2 
 mkfs/proto.c             |  107 +++--------------
 repair/phase4.c          |    7 +
 repair/phase5.c          |    6 -
 repair/phase6.c          |  284 +++++++---------------------------------------
 repair/sb.c              |   40 ------
 repair/xfs_repair.c      |    3 
 7 files changed, 73 insertions(+), 376 deletions(-)


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

* [PATCHSET v31.2 5/5] xfs_scrub_all: bug fix for 6.12
  2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
                   ` (4 preceding siblings ...)
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
@ 2024-10-25  6:32 ` Darrick J. Wong
  2024-10-25  6:38   ` [PATCH 1/1] xfs_scrub_all: wait for services to start activating Darrick J. Wong
  5 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:32 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, linux-xfs, hch

Hi all,

Fix a problem with xfs_scrub_all mistakenly thinking that a service finished
before it really did.

If you're going to start using this code, I strongly recommend pulling
from my git trees, which are linked below.

Comments and questions are, as always, welcome.

xfsprogs git tree:
https://git.kernel.org/cgit/linux/kernel/git/djwong/xfsprogs-dev.git/log/?h=scrub-fixes-6.12
---
Commits in this patchset:
 * xfs_scrub_all: wait for services to start activating
---
 scrub/xfs_scrub_all.in |   52 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)


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

* [PATCH 1/7] man: document file range commit ioctls
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
@ 2024-10-25  6:32   ` Darrick J. Wong
  2024-10-28  8:31     ` Christoph Hellwig
  2024-10-25  6:32   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
                     ` (5 subsequent siblings)
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:32 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Document the two new ioctls to support committing arbitrary dirty data
ranges of two files.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 man/man2/ioctl_xfs_commit_range.2 |  296 +++++++++++++++++++++++++++++++++++++
 man/man2/ioctl_xfs_fsgeometry.2   |    2 
 man/man2/ioctl_xfs_start_commit.2 |    1 
 3 files changed, 298 insertions(+), 1 deletion(-)
 create mode 100644 man/man2/ioctl_xfs_commit_range.2
 create mode 100644 man/man2/ioctl_xfs_start_commit.2


diff --git a/man/man2/ioctl_xfs_commit_range.2 b/man/man2/ioctl_xfs_commit_range.2
new file mode 100644
index 00000000000000..3244e52c3e0946
--- /dev/null
+++ b/man/man2/ioctl_xfs_commit_range.2
@@ -0,0 +1,296 @@
+.\" Copyright (c) 2020-2024 Oracle.  All rights reserved.
+.\"
+.\" %%%LICENSE_START(GPLv2+_DOC_FULL)
+.\" This is free documentation; you can redistribute it and/or
+.\" modify it under the terms of the GNU General Public License as
+.\" published by the Free Software Foundation; either version 2 of
+.\" the License, or (at your option) any later version.
+.\"
+.\" The GNU General Public License's references to "object code"
+.\" and "executables" are to be interpreted as the output of any
+.\" document formatting or typesetting system, including
+.\" intermediate and printed output.
+.\"
+.\" This manual is distributed in the hope that it will be useful,
+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+.\" GNU General Public License for more details.
+.\"
+.\" You should have received a copy of the GNU General Public
+.\" License along with this manual; if not, see
+.\" <http://www.gnu.org/licenses/>.
+.\" %%%LICENSE_END
+.TH IOCTL-XFS-COMMIT-RANGE 2  2024-02-18 "XFS"
+.SH NAME
+ioctl_xfs_start_commit \- prepare to exchange the contents of two files
+ioctl_xfs_commit_range \- conditionally exchange the contents of parts of two files
+.SH SYNOPSIS
+.br
+.B #include <sys/ioctl.h>
+.br
+.B #include <xfs/xfs_fs.h>
+.PP
+.BI "int ioctl(int " file2_fd ", XFS_IOC_START_COMMIT, struct xfs_commit_range *" arg );
+.PP
+.BI "int ioctl(int " file2_fd ", XFS_IOC_COMMIT_RANGE, struct xfs_commit_range *" arg );
+.SH DESCRIPTION
+Given a range of bytes in a first file
+.B file1_fd
+and a second range of bytes in a second file
+.BR file2_fd ,
+this
+.BR ioctl (2)
+exchanges the contents of the two ranges if
+.B file2_fd
+passes certain freshness criteria.
+
+Before exchanging the contents, the program must call the
+.B XFS_IOC_START_COMMIT
+ioctl to sample freshness data for
+.BR file2_fd .
+If the sampled metadata does not match the file metadata at commit time,
+.B XFS_IOC_COMMIT_RANGE
+will return
+.BR EBUSY .
+.PP
+Exchanges are atomic with regards to concurrent file operations.
+Implementations must guarantee that readers see either the old contents or the
+new contents in their entirety, even if the system fails.
+.PP
+The system call parameters are conveyed in structures of the following form:
+.PP
+.in +4n
+.EX
+struct xfs_commit_range {
+    __s32    file1_fd;
+    __u32    pad;
+    __u64    file1_offset;
+    __u64    file2_offset;
+    __u64    length;
+    __u64    flags;
+    __u64    file2_freshness[5];
+};
+.EE
+.in
+.PP
+The field
+.I pad
+must be zero.
+.PP
+The fields
+.IR file1_fd ", " file1_offset ", and " length
+define the first range of bytes to be exchanged.
+.PP
+The fields
+.IR file2_fd ", " file2_offset ", and " length
+define the second range of bytes to be exchanged.
+.PP
+The field
+.I file2_freshness
+is an opaque field whose contents are determined by the kernel.
+These file attributes are used to confirm that
+.B file2_fd
+has not changed by another thread since the current thread began staging its
+own update.
+.PP
+Both files must be from the same filesystem mount.
+If the two file descriptors represent the same file, the byte ranges must not
+overlap.
+Most disk-based filesystems require that the starts of both ranges must be
+aligned to the file block size.
+If this is the case, the ends of the ranges must also be so aligned unless the
+.B XFS_EXCHANGE_RANGE_TO_EOF
+flag is set.
+
+.PP
+The field
+.I flags
+control the behavior of the exchange operation.
+.RS 0.4i
+.TP
+.B XFS_EXCHANGE_RANGE_TO_EOF
+Ignore the
+.I length
+parameter.
+All bytes in
+.I file1_fd
+from
+.I file1_offset
+to EOF are moved to
+.IR file2_fd ,
+and file2's size is set to
+.RI ( file2_offset "+(" file1_length - file1_offset )).
+Meanwhile, all bytes in file2 from
+.I file2_offset
+to EOF are moved to file1 and file1's size is set to
+.RI ( file1_offset "+(" file2_length - file2_offset )).
+.TP
+.B XFS_EXCHANGE_RANGE_DSYNC
+Ensure that all modified in-core data in both file ranges and all metadata
+updates pertaining to the exchange operation are flushed to persistent storage
+before the call returns.
+Opening either file descriptor with
+.BR O_SYNC " or " O_DSYNC
+will have the same effect.
+.TP
+.B XFS_EXCHANGE_RANGE_FILE1_WRITTEN
+Only exchange sub-ranges of
+.I file1_fd
+that are known to contain data written by application software.
+Each sub-range may be expanded (both upwards and downwards) to align with the
+file allocation unit.
+For files on the data device, this is one filesystem block.
+For files on the realtime device, this is the realtime extent size.
+This facility can be used to implement fast atomic scatter-gather writes of any
+complexity for software-defined storage targets if all writes are aligned to
+the file allocation unit.
+.TP
+.B XFS_EXCHANGE_RANGE_DRY_RUN
+Check the parameters and the feasibility of the operation, but do not change
+anything.
+.RE
+.PP
+.SH RETURN VALUE
+On error, \-1 is returned, and
+.I errno
+is set to indicate the error.
+.PP
+.SH ERRORS
+Error codes can be one of, but are not limited to, the following:
+.TP
+.B EBADF
+.IR file1_fd
+is not open for reading and writing or is open for append-only writes; or
+.IR file2_fd
+is not open for reading and writing or is open for append-only writes.
+.TP
+.B EBUSY
+The file2 inode number and timestamps supplied do not match
+.IR file2_fd .
+.TP
+.B EINVAL
+The parameters are not correct for these files.
+This error can also appear if either file descriptor represents
+a device, FIFO, or socket.
+Disk filesystems generally require the offset and length arguments
+to be aligned to the fundamental block sizes of both files.
+.TP
+.B EIO
+An I/O error occurred.
+.TP
+.B EISDIR
+One of the files is a directory.
+.TP
+.B ENOMEM
+The kernel was unable to allocate sufficient memory to perform the
+operation.
+.TP
+.B ENOSPC
+There is not enough free space in the filesystem exchange the contents safely.
+.TP
+.B EOPNOTSUPP
+The filesystem does not support exchanging bytes between the two
+files.
+.TP
+.B EPERM
+.IR file1_fd " or " file2_fd
+are immutable.
+.TP
+.B ETXTBSY
+One of the files is a swap file.
+.TP
+.B EUCLEAN
+The filesystem is corrupt.
+.TP
+.B EXDEV
+.IR file1_fd " and " file2_fd
+are not on the same mounted filesystem.
+.SH CONFORMING TO
+This API is XFS-specific.
+.SH USE CASES
+.PP
+Several use cases are imagined for this system call.
+Coordination between multiple threads is performed by the kernel.
+.PP
+The first is a filesystem defragmenter, which copies the contents of a file
+into another file and wishes to exchange the space mappings of the two files,
+provided that the original file has not changed.
+.PP
+An example program might look like this:
+.PP
+.in +4n
+.EX
+int fd = open("/some/file", O_RDWR);
+int temp_fd = open("/some", O_TMPFILE | O_RDWR);
+struct stat sb;
+struct xfs_commit_range args = {
+    .flags = XFS_EXCHANGE_RANGE_TO_EOF,
+};
+
+/* gather file2's freshness information */
+ioctl(fd, XFS_IOC_START_COMMIT, &args);
+fstat(fd, &sb);
+
+/* make a fresh copy of the file with terrible alignment to avoid reflink */
+clone_file_range(fd, NULL, temp_fd, NULL, 1, 0);
+clone_file_range(fd, NULL, temp_fd, NULL, sb.st_size - 1, 0);
+
+/* commit the entire update */
+args.file1_fd = temp_fd;
+ret = ioctl(fd, XFS_IOC_COMMIT_RANGE, &args);
+if (ret && errno == EBUSY)
+    printf("file changed while defrag was underway\\n");
+.EE
+.in
+.PP
+The second is a data storage program that wants to commit non-contiguous updates
+to a file atomically.
+This program cannot coordinate updates to the file and therefore relies on the
+kernel to reject the COMMIT_RANGE command if the file has been updated by
+someone else.
+This can be done by creating a temporary file, calling
+.BR FICLONE (2)
+to share the contents, and staging the updates into the temporary file.
+The
+.B FULL_FILES
+flag is recommended for this purpose.
+The temporary file can be deleted or punched out afterwards.
+.PP
+An example program might look like this:
+.PP
+.in +4n
+.EX
+int fd = open("/some/file", O_RDWR);
+int temp_fd = open("/some", O_TMPFILE | O_RDWR);
+struct xfs_commit_range args = {
+    .flags = XFS_EXCHANGE_RANGE_TO_EOF,
+};
+
+/* gather file2's freshness information */
+ioctl(fd, XFS_IOC_START_COMMIT, &args);
+
+ioctl(temp_fd, FICLONE, fd);
+
+/* append 1MB of records */
+lseek(temp_fd, 0, SEEK_END);
+write(temp_fd, data1, 1000000);
+
+/* update record index */
+pwrite(temp_fd, data1, 600, 98765);
+pwrite(temp_fd, data2, 320, 54321);
+pwrite(temp_fd, data2, 15, 0);
+
+/* commit the entire update */
+args.file1_fd = temp_fd;
+ret = ioctl(fd, XFS_IOC_COMMIT_RANGE, &args);
+if (ret && errno == EBUSY)
+    printf("file changed before commit; will roll back\\n");
+.EE
+.in
+.B
+.SH NOTES
+.PP
+Some filesystems may limit the amount of data or the number of extents that can
+be exchanged in a single call.
+.SH SEE ALSO
+.BR ioctl (2)
diff --git a/man/man2/ioctl_xfs_fsgeometry.2 b/man/man2/ioctl_xfs_fsgeometry.2
index 54fd89390883c1..db7698fa922b87 100644
--- a/man/man2/ioctl_xfs_fsgeometry.2
+++ b/man/man2/ioctl_xfs_fsgeometry.2
@@ -212,7 +212,7 @@ .SH FILESYSTEM FEATURE FLAGS
 .B XFS_FSOP_GEOM_FLAGS_REFLINK
 Filesystem supports sharing blocks between files.
 .TP
-.B XFS_FSOP_GEOM_FLAGS_EXCHRANGE
+.B XFS_FSOP_GEOM_FLAGS_EXCHANGE_RANGE
 Filesystem can exchange file contents atomically via XFS_IOC_EXCHANGE_RANGE.
 .RE
 .SH XFS METADATA HEALTH REPORTING
diff --git a/man/man2/ioctl_xfs_start_commit.2 b/man/man2/ioctl_xfs_start_commit.2
new file mode 100644
index 00000000000000..f11410120f698d
--- /dev/null
+++ b/man/man2/ioctl_xfs_start_commit.2
@@ -0,0 +1 @@
+.so man2/ioctl_xfs_commit_range.2


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

* [PATCH 2/7] libfrog: add support for commit range ioctl family
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
  2024-10-25  6:32   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
@ 2024-10-25  6:32   ` Darrick J. Wong
  2024-10-28  8:32     ` Christoph Hellwig
  2024-10-25  6:33   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
                     ` (4 subsequent siblings)
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:32 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Add some library code to support the new file range commit ioctls.  This
will be used to test the atomic file commit functionality in fstests.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libfrog/file_exchange.c |  194 +++++++++++++++++++++++++++++++++++++++++++++++
 libfrog/file_exchange.h |   10 ++
 2 files changed, 204 insertions(+)


diff --git a/libfrog/file_exchange.c b/libfrog/file_exchange.c
index 29fdc17e598ce4..e6c3f486b0ffdc 100644
--- a/libfrog/file_exchange.c
+++ b/libfrog/file_exchange.c
@@ -50,3 +50,197 @@ xfrog_exchangerange(
 
 	return 0;
 }
+
+/*
+ * Prepare for committing a file contents exchange if nobody changes file2 in
+ * the meantime by asking the kernel to sample file2's change attributes.
+ *
+ * Returns 0 for success or a negative errno.
+ */
+int
+xfrog_commitrange_prep(
+	struct xfs_commit_range		*xcr,
+	int				file2_fd,
+	off_t				file2_offset,
+	int				file1_fd,
+	off_t				file1_offset,
+	uint64_t			length)
+{
+	int				ret;
+
+	memset(xcr, 0, sizeof(*xcr));
+
+	xcr->file1_fd			= file1_fd;
+	xcr->file1_offset		= file1_offset;
+	xcr->length			= length;
+	xcr->file2_offset		= file2_offset;
+
+	ret = ioctl(file2_fd, XFS_IOC_START_COMMIT, xcr);
+	if (ret)
+		return -errno;
+
+	return 0;
+}
+
+/*
+ * Execute an exchange-commit operation.  Returns 0 for success or a negative
+ * errno.
+ */
+int
+xfrog_commitrange(
+	int				file2_fd,
+	struct xfs_commit_range		*xcr,
+	uint64_t			flags)
+{
+	int				ret;
+
+	xcr->flags = flags;
+
+	ret = ioctl(file2_fd, XFS_IOC_COMMIT_RANGE, xcr);
+	if (ret)
+		return -errno;
+
+	return 0;
+}
+
+/* Opaque freshness blob for XFS_IOC_COMMIT_RANGE */
+struct xfs_commit_range_fresh {
+	xfs_fsid_t	fsid;		/* m_fixedfsid */
+	__u64		file2_ino;	/* inode number */
+	__s64		file2_mtime;	/* modification time */
+	__s64		file2_ctime;	/* change time */
+	__s32		file2_mtime_nsec; /* mod time, nsec */
+	__s32		file2_ctime_nsec; /* change time, nsec */
+	__u32		file2_gen;	/* inode generation */
+	__u32		magic;		/* zero */
+};
+
+/* magic flag to force use of swapext */
+#define XCR_SWAPEXT_MAGIC	0x43524150	/* CRAP */
+
+/*
+ * Import file2 freshness information for a XFS_IOC_SWAPEXT call from bulkstat
+ * information.  We can skip the fsid and file2_gen members because old swapext
+ * did not verify those things.
+ */
+static void
+xfrog_swapext_prep(
+	struct xfs_commit_range		*xdf,
+	const struct xfs_bulkstat	*file2_stat)
+{
+	struct xfs_commit_range_fresh	*f;
+
+	f = (struct xfs_commit_range_fresh *)&xdf->file2_freshness;
+	f->file2_ino			= file2_stat->bs_ino;
+	f->file2_mtime			= file2_stat->bs_mtime;
+	f->file2_mtime_nsec		= file2_stat->bs_mtime_nsec;
+	f->file2_ctime			= file2_stat->bs_ctime;
+	f->file2_ctime_nsec		= file2_stat->bs_ctime_nsec;
+	f->magic			= XCR_SWAPEXT_MAGIC;
+}
+
+/* Invoke the old swapext ioctl. */
+static int
+xfrog_ioc_swapext(
+	int				file2_fd,
+	struct xfs_commit_range		*xdf)
+{
+	struct xfs_swapext		args = {
+		.sx_version		= XFS_SX_VERSION,
+		.sx_fdtarget		= file2_fd,
+		.sx_length		= xdf->length,
+		.sx_fdtmp		= xdf->file1_fd,
+	};
+	struct xfs_commit_range_fresh	*f;
+	int				ret;
+
+	BUILD_BUG_ON(sizeof(struct xfs_commit_range_fresh) !=
+		     sizeof(xdf->file2_freshness));
+
+	f = (struct xfs_commit_range_fresh *)&xdf->file2_freshness;
+	args.sx_stat.bs_ino		= f->file2_ino;
+	args.sx_stat.bs_mtime.tv_sec	= f->file2_mtime;
+	args.sx_stat.bs_mtime.tv_nsec	= f->file2_mtime_nsec;
+	args.sx_stat.bs_ctime.tv_sec	= f->file2_ctime;
+	args.sx_stat.bs_ctime.tv_nsec	= f->file2_ctime_nsec;
+
+	ret = ioctl(file2_fd, XFS_IOC_SWAPEXT, &args);
+	if (ret) {
+		/*
+		 * Old swapext returns EFAULT if file1 or file2 length doesn't
+		 * match.  The new new COMMIT_RANGE doesn't check the file
+		 * length, but the freshness checks will trip and return EBUSY.
+		 * If we see EFAULT from the old ioctl, turn that into EBUSY.
+		 */
+		if (errno == EFAULT)
+			return -EBUSY;
+		return -errno;
+	}
+
+	return 0;
+}
+
+/*
+ * Prepare for defragmenting a file by committing a file contents exchange if
+ * if nobody changes file2 in the meantime by asking the kernel to sample
+ * file2's change attributes.
+ *
+ * If the kernel supports only the old XFS_IOC_SWAPEXT ioctl, the @file2_stat
+ * information will be used to sample the change attributes.
+ *
+ * Returns 0 or a negative errno.
+ */
+int
+xfrog_defragrange_prep(
+	struct xfs_commit_range		*xdf,
+	int				file2_fd,
+	const struct xfs_bulkstat	*file2_stat,
+	int				file1_fd)
+{
+	int				ret;
+
+	memset(xdf, 0, sizeof(*xdf));
+
+	xdf->file1_fd			= file1_fd;
+	xdf->length			= file2_stat->bs_size;
+
+	ret = ioctl(file2_fd, XFS_IOC_START_COMMIT, xdf);
+	if (ret && (errno == EOPNOTSUPP || errno == ENOTTY)) {
+		xfrog_swapext_prep(xdf, file2_stat);
+		return 0;
+	}
+	if (ret)
+		return -errno;
+
+	return 0;
+}
+
+/* Execute an exchange operation.  Returns 0 for success or a negative errno. */
+int
+xfrog_defragrange(
+	int				file2_fd,
+	struct xfs_commit_range		*xdf)
+{
+	struct xfs_commit_range_fresh	*f;
+	int				ret;
+
+	f = (struct xfs_commit_range_fresh *)&xdf->file2_freshness;
+	if (f->magic == XCR_SWAPEXT_MAGIC)
+		goto legacy_fallback;
+
+	ret = ioctl(file2_fd, XFS_IOC_COMMIT_RANGE, xdf);
+	if (ret) {
+		if (errno == EOPNOTSUPP || errno != ENOTTY)
+			goto legacy_fallback;
+		return -errno;
+	}
+
+	return 0;
+
+legacy_fallback:
+	ret = xfrog_ioc_swapext(file2_fd, xdf);
+	if (ret)
+		return -errno;
+
+	return 0;
+}
diff --git a/libfrog/file_exchange.h b/libfrog/file_exchange.h
index b6f6f9f698a8c9..98d3b867c317ee 100644
--- a/libfrog/file_exchange.h
+++ b/libfrog/file_exchange.h
@@ -12,4 +12,14 @@ void xfrog_exchangerange_prep(struct xfs_exchange_range *fxr,
 int xfrog_exchangerange(int file2_fd, struct xfs_exchange_range *fxr,
 		uint64_t flags);
 
+int xfrog_commitrange_prep(struct xfs_commit_range *xcr, int file2_fd,
+		off_t file2_offset, int file1_fd, off_t file1_offset,
+		uint64_t length);
+int xfrog_commitrange(int file2_fd, struct xfs_commit_range *xcr,
+		uint64_t flags);
+
+int xfrog_defragrange_prep(struct xfs_commit_range *xdf, int file2_fd,
+		const struct xfs_bulkstat *file2_stat, int file1_fd);
+int xfrog_defragrange(int file2_fd, struct xfs_commit_range *xdf);
+
 #endif	/* __LIBFROG_FILE_EXCHANGE_H__ */


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

* [PATCH 3/7] libxfs: remove unused xfs_inode fields
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
  2024-10-25  6:32   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
  2024-10-25  6:32   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
@ 2024-10-25  6:33   ` Darrick J. Wong
  2024-10-28  8:32     ` Christoph Hellwig
  2024-10-25  6:33   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
                     ` (3 subsequent siblings)
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:33 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Remove these unused fields; on the author's system this reduces the
struct size from 560 bytes to 448.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 include/xfs_inode.h |    4 ----
 1 file changed, 4 deletions(-)


diff --git a/include/xfs_inode.h b/include/xfs_inode.h
index 170cc5288d3645..f250102ff19d65 100644
--- a/include/xfs_inode.h
+++ b/include/xfs_inode.h
@@ -215,7 +215,6 @@ typedef struct xfs_inode {
 	struct xfs_mount	*i_mount;	/* fs mount struct ptr */
 	xfs_ino_t		i_ino;		/* inode number (agno/agino) */
 	struct xfs_imap		i_imap;		/* location for xfs_imap() */
-	struct xfs_buftarg	i_dev;		/* dev for this inode */
 	struct xfs_ifork	*i_cowfp;	/* copy on write extents */
 	struct xfs_ifork	i_df;		/* data fork */
 	struct xfs_ifork	i_af;		/* attribute fork */
@@ -239,9 +238,6 @@ typedef struct xfs_inode {
 	xfs_agino_t		i_next_unlinked;
 	xfs_agino_t		i_prev_unlinked;
 
-	xfs_extnum_t		i_cnextents;	/* # of extents in cow fork */
-	unsigned int		i_cformat;	/* format of cow fork */
-
 	xfs_fsize_t		i_size;		/* in-memory size */
 	struct inode		i_vnode;
 } xfs_inode_t;


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

* [PATCH 4/7] libxfs: validate inumber in xfs_iget
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (2 preceding siblings ...)
  2024-10-25  6:33   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
@ 2024-10-25  6:33   ` Darrick J. Wong
  2024-10-28  8:32     ` Christoph Hellwig
  2024-10-25  6:33   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
                     ` (2 subsequent siblings)
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:33 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Actually use the inumber validator to check the argument passed in here,
just like we now do in the kernel.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libxfs/inode.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


diff --git a/libxfs/inode.c b/libxfs/inode.c
index 2062ecf54486cf..9230ad24a5cb6c 100644
--- a/libxfs/inode.c
+++ b/libxfs/inode.c
@@ -143,7 +143,7 @@ libxfs_iget(
 	int			error = 0;
 
 	/* reject inode numbers outside existing AGs */
-	if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount)
+	if (!xfs_verify_ino(mp, ino))
 		return -EINVAL;
 
 	ip = kmem_cache_zalloc(xfs_inode_cache, 0);


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

* [PATCH 5/7] xfs_fsr: port to new file exchange library function
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (3 preceding siblings ...)
  2024-10-25  6:33   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
@ 2024-10-25  6:33   ` Darrick J. Wong
  2024-10-28  8:33     ` Christoph Hellwig
  2024-10-25  6:34   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
  2024-10-25  6:34   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:33 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Port fsr to use the new libfrog library functions to handle exchanging
mappings between the target and donor files.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 fsr/xfs_fsr.c |   74 ++++++++++++++++++++++++++-------------------------------
 1 file changed, 34 insertions(+), 40 deletions(-)


diff --git a/fsr/xfs_fsr.c b/fsr/xfs_fsr.c
index 22e134adfd73ab..8845ff172fcb2e 100644
--- a/fsr/xfs_fsr.c
+++ b/fsr/xfs_fsr.c
@@ -13,6 +13,7 @@
 #include "libfrog/paths.h"
 #include "libfrog/fsgeom.h"
 #include "libfrog/bulkstat.h"
+#include "libfrog/file_exchange.h"
 
 #include <fcntl.h>
 #include <errno.h>
@@ -122,12 +123,6 @@ open_handle(
 	return 0;
 }
 
-static int
-xfs_swapext(int fd, xfs_swapext_t *sx)
-{
-    return ioctl(fd, XFS_IOC_SWAPEXT, sx);
-}
-
 static int
 xfs_fscounts(int fd, xfs_fsop_counts_t *counts)
 {
@@ -1189,14 +1184,13 @@ packfile(
 	struct xfs_bulkstat	*statp,
 	struct fsxattr		*fsxp)
 {
+	struct xfs_commit_range	xdf;
 	int			tfd = -1;
-	int			srval;
 	int			retval = -1;	/* Failure is the default */
 	int			nextents, extent, cur_nextents, new_nextents;
 	unsigned		blksz_dio;
 	unsigned		dio_min;
 	struct dioattr		dio;
-	static xfs_swapext_t	sx;
 	struct xfs_flock64	space;
 	off_t			cnt, pos;
 	void			*fbuf = NULL;
@@ -1239,6 +1233,16 @@ packfile(
 		goto out;
 	}
 
+	/*
+	 * Snapshot file_fd before we start copying data but after tweaking
+	 * forkoff.
+	 */
+	error = xfrog_defragrange_prep(&xdf, file_fd->fd, statp, tfd);
+	if (error) {
+		fsrprintf(_("failed to prep for defrag: %s\n"), strerror(error));
+		goto out;
+	}
+
 	/* Setup extended inode flags, project identifier, etc */
 	if (fsxp->fsx_xflags || fsxp->fsx_projid) {
 		if (ioctl(tfd, FS_IOC_FSSETXATTR, fsxp) < 0) {
@@ -1446,19 +1450,6 @@ packfile(
 		goto out;
 	}
 
-	error = -xfrog_bulkstat_v5_to_v1(file_fd, &sx.sx_stat, statp);
-	if (error) {
-		fsrprintf(_("bstat conversion error on %s: %s\n"),
-				fname, strerror(error));
-		goto out;
-	}
-
-	sx.sx_version  = XFS_SX_VERSION;
-	sx.sx_fdtarget = file_fd->fd;
-	sx.sx_fdtmp    = tfd;
-	sx.sx_offset   = 0;
-	sx.sx_length   = statp->bs_size;
-
 	/* switch to the owner's id, to keep quota in line */
         if (fchown(tfd, statp->bs_uid, statp->bs_gid) < 0) {
                 if (vflag)
@@ -1468,25 +1459,28 @@ packfile(
         }
 
 	/* Swap the extents */
-	srval = xfs_swapext(file_fd->fd, &sx);
-	if (srval < 0) {
-		if (errno == ENOTSUP) {
-			if (vflag || dflag)
-			   fsrprintf(_("%s: file type not supported\n"), fname);
-		} else if (errno == EFAULT) {
-			/* The file has changed since we started the copy */
-			if (vflag || dflag)
-			   fsrprintf(_("%s: file modified defrag aborted\n"),
-				     fname);
-		} else if (errno == EBUSY) {
-			/* Timestamp has changed or mmap'ed file */
-			if (vflag || dflag)
-			   fsrprintf(_("%s: file busy\n"), fname);
-		} else {
-			fsrprintf(_("XFS_IOC_SWAPEXT failed: %s: %s\n"),
-				  fname, strerror(errno));
-		}
-		goto out;
+	error = xfrog_defragrange(file_fd->fd, &xdf);
+	switch (error) {
+		case 0:
+			break;
+	case ENOTSUP:
+		if (vflag || dflag)
+			fsrprintf(_("%s: file type not supported\n"), fname);
+		break;
+	case EFAULT:
+		/* The file has changed since we started the copy */
+		if (vflag || dflag)
+			fsrprintf(_("%s: file modified defrag aborted\n"),
+					fname);
+		break;
+	case EBUSY:
+		/* Timestamp has changed or mmap'ed file */
+		if (vflag || dflag)
+			fsrprintf(_("%s: file busy\n"), fname);
+		break;
+	default:
+		fsrprintf(_("XFS_IOC_SWAPEXT failed: %s: %s\n"),
+			  fname, strerror(error));
 	}
 
 	/* Report progress */


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

* [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-25  6:33   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
@ 2024-10-25  6:34   ` Darrick J. Wong
  2024-10-28  8:33     ` Christoph Hellwig
  2024-10-25  6:34   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:34 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Teach the xfs_io exchangerange command to be able to use the commit
range functionality so that we can test it piece by piece.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 io/exchrange.c    |   26 ++++++++++++++++++++++----
 man/man8/xfs_io.8 |    3 +++
 2 files changed, 25 insertions(+), 4 deletions(-)


diff --git a/io/exchrange.c b/io/exchrange.c
index 016429280e2717..0a3750f1eb2607 100644
--- a/io/exchrange.c
+++ b/io/exchrange.c
@@ -19,6 +19,7 @@ exchangerange_help(void)
 "\n"
 " Exchange file data between the open file descriptor and the supplied filename.\n"
 " -C   -- Print timing information in a condensed format\n"
+" -c   -- Commit to the exchange only if file2 has not changed.\n"
 " -d N -- Start exchanging contents at this position in the open file\n"
 " -f   -- Flush changed file data and metadata to disk\n"
 " -l N -- Exchange this many bytes between the two files instead of to EOF\n"
@@ -34,9 +35,9 @@ exchangerange_f(
 	int			argc,
 	char			**argv)
 {
-	struct xfs_exchange_range	fxr;
 	struct stat		stat;
 	struct timeval		t1, t2;
+	bool			use_commit = false;
 	uint64_t		flags = XFS_EXCHANGE_RANGE_TO_EOF;
 	int64_t			src_offset = 0;
 	int64_t			dest_offset = 0;
@@ -53,6 +54,9 @@ exchangerange_f(
 		case 'C':
 			condensed = 1;
 			break;
+		case 'c':
+			use_commit = true;
+			break;
 		case 'd':
 			dest_offset = cvtnum(fsblocksize, fssectsize, optarg);
 			if (dest_offset < 0) {
@@ -117,8 +121,22 @@ exchangerange_f(
 	if (length < 0)
 		length = stat.st_size;
 
-	xfrog_exchangerange_prep(&fxr, dest_offset, fd, src_offset, length);
-	ret = xfrog_exchangerange(file->fd, &fxr, flags);
+	if (use_commit) {
+		struct xfs_commit_range	xcr;
+
+		ret = xfrog_commitrange_prep(&xcr, file->fd, dest_offset, fd,
+				src_offset, length);
+		if (!ret) {
+			gettimeofday(&t1, NULL);
+			ret = xfrog_commitrange(file->fd, &xcr, flags);
+		}
+	} else {
+		struct xfs_exchange_range	fxr;
+
+		xfrog_exchangerange_prep(&fxr, dest_offset, fd, src_offset,
+				length);
+		ret = xfrog_exchangerange(file->fd, &fxr, flags);
+	}
 	if (ret) {
 		xfrog_perror(ret, "exchangerange");
 		exitcode = 1;
@@ -149,7 +167,7 @@ static struct cmdinfo exchangerange_cmd = {
 void
 exchangerange_init(void)
 {
-	exchangerange_cmd.args = _("[-Cfntw] [-d dest_offset] [-s src_offset] [-l length] <donorfile>");
+	exchangerange_cmd.args = _("[-Ccfntw] [-d dest_offset] [-s src_offset] [-l length] <donorfile>");
 	exchangerange_cmd.oneline = _("Exchange contents between files.");
 
 	add_command(&exchangerange_cmd);
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 1e7901393ff4d4..49d4057bb069ed 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -732,6 +732,9 @@ .SH FILE I/O COMMANDS
 .B \-C
 Print timing information in a condensed format.
 .TP
+.B \-c
+Exchange contents only if file2 has not changed.
+.TP
 .BI \-d " dest_offset"
 Swap extents with open file beginning at
 .IR dest_offset .


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

* [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range
  2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (5 preceding siblings ...)
  2024-10-25  6:34   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
@ 2024-10-25  6:34   ` Darrick J. Wong
  2024-10-28  8:33     ` Christoph Hellwig
  6 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:34 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Add three commands to xfs_io so that we can exercise atomic file updates
as provided by reflink and the start-commit / commit-range functionality.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 io/exchrange.c    |  364 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 io/io.h           |    4 +
 io/open.c         |   27 +++-
 man/man8/xfs_io.8 |   32 +++++
 4 files changed, 421 insertions(+), 6 deletions(-)


diff --git a/io/exchrange.c b/io/exchrange.c
index 0a3750f1eb2607..707d78d8e624fe 100644
--- a/io/exchrange.c
+++ b/io/exchrange.c
@@ -164,6 +164,358 @@ static struct cmdinfo exchangerange_cmd = {
 	.help		= exchangerange_help,
 };
 
+/* Atomic file updates commands */
+
+struct update_info {
+	/* File that we're updating. */
+	int			fd;
+
+	/* ioctl data to commit the changes */
+	struct xfs_commit_range	xcr;
+
+	/* Name of the file we're updating. */
+	char			*old_fname;
+
+	/* fd we're using to stage the updates. */
+	int			temp_fd;
+};
+
+enum finish_how	{
+	FINISH_ABORT,
+	FINISH_COMMIT,
+	FINISH_CHECK
+};
+
+static struct update_info *updates;
+static unsigned int nr_updates;
+
+static void
+startupdate_help(void)
+{
+	printf(_(
+"\n"
+" Prepare for an atomic file update, if supported by the filesystem.\n"
+" A temporary file will be opened for writing and inserted into the file\n"
+" table.  The current file will be changed to this temporary file.  Neither\n"
+" file can be closed for the duration of the update.\n"
+"\n"
+" -e   -- Start with an empty file\n"
+"\n"));
+}
+
+static int
+startupdate_f(
+	int			argc,
+	char			*argv[])
+{
+	struct fsxattr		attr;
+	struct xfs_fsop_geom	fsgeom;
+	struct fs_path		fspath;
+	struct stat		stat;
+	struct update_info	*p;
+	char			*fname;
+	char			*path = NULL, *d;
+	size_t			fname_len;
+	int			flags = IO_TMPFILE | IO_ATOMICUPDATE;
+	int			temp_fd = -1;
+	bool			clone_file = true;
+	int			c;
+	int			ret;
+
+	while ((c = getopt(argc, argv, "e")) != -1) {
+		switch (c) {
+		case 'e':
+			clone_file = false;
+			break;
+		default:
+			startupdate_help();
+			return 0;
+		}
+	}
+	if (optind != argc) {
+		startupdate_help();
+		return 0;
+	}
+
+	/* Allocate a new slot. */
+	p = realloc(updates, (++nr_updates) * sizeof(*p));
+	if (!p) {
+		perror("startupdate realloc");
+		goto fail;
+	}
+	updates = p;
+
+	/* Fill out the update information so that we can commit later. */
+	p = &updates[nr_updates - 1];
+	memset(p, 0, sizeof(*p));
+
+	ret = fstat(file->fd, &stat);
+	if (ret) {
+		perror(file->name);
+		goto fail;
+	}
+
+	/* Is the current file realtime?  If so, the temp file must match. */
+	ret = ioctl(file->fd, FS_IOC_FSGETXATTR, &attr);
+	if (ret == 0 && attr.fsx_xflags & FS_XFLAG_REALTIME)
+		flags |= IO_REALTIME;
+
+	/* Compute path to the directory that the current file is in. */
+	path = strdup(file->name);
+	d = strrchr(path, '/');
+	if (!d) {
+		fprintf(stderr, _("%s: cannot compute dirname?"), path);
+		goto fail;
+	}
+	*d = 0;
+
+	/* Open a temporary file to stage the new contents. */
+	temp_fd = openfile(path, &fsgeom, flags, 0600, &fspath);
+	if (temp_fd < 0) {
+		perror(path);
+		goto fail;
+	}
+
+	/*
+	 * Snapshot the original file metadata in anticipation of the later
+	 * file mapping exchange request.
+	 */
+	ret = xfrog_commitrange_prep(&p->xcr, file->fd, 0, temp_fd, 0,
+			stat.st_size);
+	if (ret) {
+		perror("update prep");
+		goto fail;
+	}
+
+	/* Clone all the data from the original file into the temporary file. */
+	if (clone_file) {
+		ret = ioctl(temp_fd, XFS_IOC_CLONE, file->fd);
+		if (ret) {
+			perror(path);
+			goto fail;
+		}
+	}
+
+	/* Prepare a new path string for the duration of the update. */
+#define FILEUPDATE_STR	" (fileupdate)"
+	fname_len = strlen(file->name) + strlen(FILEUPDATE_STR);
+	fname = malloc(fname_len + 1);
+	if (!fname) {
+		perror("new path");
+		goto fail;
+	}
+	snprintf(fname, fname_len + 1, "%s%s", file->name, FILEUPDATE_STR);
+
+	/*
+	 * Install the temporary file into the same slot of the file table as
+	 * the original file.  Ensure that the original file cannot be closed.
+	 */
+	file->flags |= IO_ATOMICUPDATE;
+	p->old_fname = file->name;
+	file->name = fname;
+	p->fd = file->fd;
+	p->temp_fd = file->fd = temp_fd;
+
+	free(path);
+	return 0;
+fail:
+	if (temp_fd >= 0)
+		close(temp_fd);
+	free(path);
+	nr_updates--;
+	exitcode = 1;
+	return 1;
+}
+
+static long long
+finish_update(
+	enum finish_how		how,
+	uint64_t		flags,
+	long long		*offset)
+{
+	struct update_info	*p;
+	long long		committed_bytes = 0;
+	size_t			length;
+	unsigned int		i;
+	unsigned int		upd_offset;
+	int			temp_fd;
+	int			ret;
+
+	/* Find our update descriptor. */
+	for (i = 0, p = updates; i < nr_updates; i++, p++) {
+		if (p->temp_fd == file->fd)
+			break;
+	}
+
+	if (i == nr_updates) {
+		fprintf(stderr,
+	_("Current file is not the staging file for an atomic update.\n"));
+		exitcode = 1;
+		return -1;
+	}
+
+	/*
+	 * Commit our changes, if desired.  If the mapping exchange fails, we
+	 * stop processing immediately so that we can run more xfs_io commands.
+	 */
+	switch (how) {
+	case FINISH_CHECK:
+		flags |= XFS_EXCHANGE_RANGE_DRY_RUN;
+		fallthrough;
+	case FINISH_COMMIT:
+		ret = xfrog_commitrange(p->fd, &p->xcr, flags);
+		if (ret) {
+			xfrog_perror(ret, _("committing update"));
+			exitcode = 1;
+			return -1;
+		}
+		printf(_("Committed updates to '%s'.\n"), p->old_fname);
+		*offset = p->xcr.file2_offset;
+		committed_bytes = p->xcr.length;
+		break;
+	case FINISH_ABORT:
+		printf(_("Cancelled updates to '%s'.\n"), p->old_fname);
+		break;
+	}
+
+	/*
+	 * Reset the filetable to point to the original file, and close the
+	 * temporary file.
+	 */
+	free(file->name);
+	file->name = p->old_fname;
+	file->flags &= ~IO_ATOMICUPDATE;
+	temp_fd = file->fd;
+	file->fd = p->fd;
+	ret = close(temp_fd);
+	if (ret)
+		perror(_("closing temporary file"));
+
+	/* Remove the atomic update context, shifting things down. */
+	upd_offset = p - updates;
+	length = nr_updates * sizeof(struct update_info);
+	length -= (upd_offset + 1) * sizeof(struct update_info);
+	if (length)
+		memmove(p, p + 1, length);
+
+	nr_updates--;
+	return committed_bytes;
+}
+
+static void
+cancelupdate_help(void)
+{
+	printf(_(
+"\n"
+" Cancels an atomic file update.  The temporary file will be closed, and the\n"
+" current file set back to the original file.\n"
+"\n"));
+}
+
+static int
+cancelupdate_f(
+	int		argc,
+	char		*argv[])
+{
+	return finish_update(FINISH_ABORT, 0, NULL);
+}
+
+static void
+commitupdate_help(void)
+{
+	printf(_(
+"\n"
+" Commits an atomic file update.  File contents written to the temporary file\n"
+" will be exchanged atomically with the corresponding range in the original\n"
+" file.  The temporary file will be closed, and the current file set back to\n"
+" the original file.\n"
+"\n"
+" -C   -- Print timing information in a condensed format.\n"
+" -h   -- Only exchange written ranges in the temporary file.\n"
+" -k   -- Exchange to end of file, ignore any length previously set.\n"
+" -n   -- Check parameters but do not change anything.\n"
+" -q   -- Do not print timing information at all.\n"));
+}
+
+static int
+commitupdate_f(
+	int		argc,
+	char		*argv[])
+{
+	struct timeval	t1, t2;
+	enum finish_how	how = FINISH_COMMIT;
+	uint64_t	flags = XFS_EXCHANGE_RANGE_TO_EOF;
+	long long	offset, len;
+	int		condensed = 0, quiet_flag = 0;
+	int		c;
+
+	while ((c = getopt(argc, argv, "Chknq")) != -1) {
+		switch (c) {
+		case 'C':
+			condensed = 1;
+			break;
+		case 'h':
+			flags |= XFS_EXCHANGE_RANGE_FILE1_WRITTEN;
+			break;
+		case 'k':
+			flags &= ~XFS_EXCHANGE_RANGE_TO_EOF;
+			break;
+		case 'n':
+			how = FINISH_CHECK;
+			break;
+		case 'q':
+			quiet_flag = 1;
+			break;
+		default:
+			commitupdate_help();
+			return 0;
+		}
+	}
+	if (optind != argc) {
+		commitupdate_help();
+		return 0;
+	}
+
+	gettimeofday(&t1, NULL);
+	len = finish_update(how, flags, &offset);
+	if (len < 0)
+		return 1;
+	if (quiet_flag)
+		return 0;
+
+	gettimeofday(&t2, NULL);
+	t2 = tsub(t2, t1);
+	report_io_times("commitupdate", &t2, offset, len, len, 1, condensed);
+	return 0;
+}
+
+static struct cmdinfo startupdate_cmd = {
+	.name		= "startupdate",
+	.cfunc		= startupdate_f,
+	.argmin		= 0,
+	.argmax		= -1,
+	.flags		= CMD_FLAG_ONESHOT | CMD_NOMAP_OK,
+	.help		= startupdate_help,
+};
+
+static struct cmdinfo cancelupdate_cmd = {
+	.name		= "cancelupdate",
+	.cfunc		= cancelupdate_f,
+	.argmin		= 0,
+	.argmax		= 0,
+	.flags		= CMD_FLAG_ONESHOT | CMD_NOMAP_OK,
+	.help		= cancelupdate_help,
+};
+
+static struct cmdinfo commitupdate_cmd = {
+	.name		= "commitupdate",
+	.cfunc		= commitupdate_f,
+	.argmin		= 0,
+	.argmax		= -1,
+	.flags		= CMD_FLAG_ONESHOT | CMD_NOMAP_OK,
+	.help		= commitupdate_help,
+};
+
 void
 exchangerange_init(void)
 {
@@ -171,4 +523,16 @@ exchangerange_init(void)
 	exchangerange_cmd.oneline = _("Exchange contents between files.");
 
 	add_command(&exchangerange_cmd);
+
+	startupdate_cmd.oneline = _("start an atomic update of a file");
+	startupdate_cmd.args = _("[-e]");
+
+	cancelupdate_cmd.oneline = _("cancel an atomic update");
+
+	commitupdate_cmd.oneline = _("commit a file update atomically");
+	commitupdate_cmd.args = _("[-C] [-h] [-n] [-q]");
+
+	add_command(&startupdate_cmd);
+	add_command(&cancelupdate_cmd);
+	add_command(&commitupdate_cmd);
 }
diff --git a/io/io.h b/io/io.h
index 8c5e59100c5cbd..4daedac06419ae 100644
--- a/io/io.h
+++ b/io/io.h
@@ -31,6 +31,9 @@
 #define IO_PATH		(1<<10)
 #define IO_NOFOLLOW	(1<<11)
 
+/* undergoing atomic update, do not close */
+#define IO_ATOMICUPDATE	(1<<12)
+
 /*
  * Regular file I/O control
  */
@@ -74,6 +77,7 @@ extern int		openfile(char *, struct xfs_fsop_geom *, int, mode_t,
 				 struct fs_path *);
 extern int		addfile(char *, int , struct xfs_fsop_geom *, int,
 				struct fs_path *);
+extern int		closefile(void);
 extern void		printxattr(uint, int, int, const char *, int, int);
 
 extern unsigned int	recurse_all;
diff --git a/io/open.c b/io/open.c
index 15850b5557bc5b..a30dd89a1fd56c 100644
--- a/io/open.c
+++ b/io/open.c
@@ -338,14 +338,19 @@ open_f(
 	return 0;
 }
 
-static int
-close_f(
-	int		argc,
-	char		**argv)
+int
+closefile(void)
 {
 	size_t		length;
 	unsigned int	offset;
 
+	if (file->flags & IO_ATOMICUPDATE) {
+		fprintf(stderr,
+	_("%s: atomic update in progress, cannot close.\n"),
+			file->name);
+		exitcode = 1;
+		return 0;
+	}
 	if (close(file->fd) < 0) {
 		perror("close");
 		exitcode = 1;
@@ -371,7 +376,19 @@ close_f(
 		free(filetable);
 		file = filetable = NULL;
 	}
-	filelist_f();
+	return 0;
+}
+
+static int
+close_f(
+	int		argc,
+	char		**argv)
+{
+	int		ret;
+
+	ret = closefile();
+	if (!ret)
+		filelist_f();
 	return 0;
 }
 
diff --git a/man/man8/xfs_io.8 b/man/man8/xfs_io.8
index 49d4057bb069ed..eb2201fca74380 100644
--- a/man/man8/xfs_io.8
+++ b/man/man8/xfs_io.8
@@ -1058,7 +1058,37 @@ .SH FILE I/O COMMANDS
 nsec is the nanoseconds since the sec. This value needs to be in
 the range 0-999999999 with UTIME_NOW and UTIME_OMIT being exceptions.
 Each (sec, nsec) pair constitutes a single timestamp value.
-
+.TP
+.BI "startupdate [ " -e ]
+Create a temporary clone of a file in which to stage file updates.
+The
+.B \-e
+option creates an empty staging file.
+.TP
+.B cancelupdate
+Abandon changes from a update staging file.
+.TP
+.BI "commitupdate [" OPTIONS ]
+Commit changes from a update staging file to the real file.
+.RS 1.0i
+.PD 0
+.TP 0.4i
+.B \-C
+Print timing information in a condensed format.
+.TP 0.4i
+.B \-h
+Only swap ranges in the update staging file that were actually written.
+.TP 0.4i
+.B \-k
+Do not change file size.
+.TP 0.4i
+.B \-n
+Check parameters without changing anything.
+.TP 0.4i
+.B \-q
+Do not print timing information at all.
+.PD
+.RE
 
 .SH MEMORY MAPPED I/O COMMANDS
 .TP


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

* [PATCH 1/8] xfs_db: support passing the realtime device to the debugger
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
@ 2024-10-25  6:34   ` Darrick J. Wong
  2024-10-28  8:34     ` Christoph Hellwig
  2024-10-25  6:34   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
                     ` (6 subsequent siblings)
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:34 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Create a new -R flag so that sysadmins can pass the realtime device to
the xfs debugger.  Since we can now have superblocks on the rt device,
we need this to be able to inspect/dump/etc.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/init.c         |    7 +++++--
 db/io.c           |   28 +++++++++++++++++++++++-----
 db/io.h           |    2 ++
 db/xfs_admin.sh   |    4 +++-
 man/man8/xfs_db.8 |   13 +++++++++++++
 5 files changed, 46 insertions(+), 8 deletions(-)


diff --git a/db/init.c b/db/init.c
index cea25ae52bd1b7..17fb094296c2b8 100644
--- a/db/init.c
+++ b/db/init.c
@@ -33,7 +33,7 @@ static void
 usage(void)
 {
 	fprintf(stderr, _(
-		"Usage: %s [-ifFrxV] [-p prog] [-l logdev] [-c cmd]... device\n"
+		"Usage: %s [-ifFrxV] [-p prog] [-l logdev] [-R rtdev] [-c cmd]... device\n"
 		), progname);
 	exit(1);
 }
@@ -54,7 +54,7 @@ init(
 	textdomain(PACKAGE);
 
 	progname = basename(argv[0]);
-	while ((c = getopt(argc, argv, "c:fFip:rxVl:")) != EOF) {
+	while ((c = getopt(argc, argv, "c:fFip:rR:xVl:")) != EOF) {
 		switch (c) {
 		case 'c':
 			cmdline = xrealloc(cmdline, (ncmdline+1)*sizeof(char*));
@@ -75,6 +75,9 @@ init(
 		case 'r':
 			x.flags = LIBXFS_ISREADONLY;
 			break;
+		case 'R':
+			x.rt.name = optarg;
+			break;
 		case 'l':
 			x.log.name = optarg;
 			break;
diff --git a/db/io.c b/db/io.c
index 9b2c6b4cf7e963..26b8e78c2ebda8 100644
--- a/db/io.c
+++ b/db/io.c
@@ -458,6 +458,7 @@ ring_add(void)
 static void
 write_cur_buf(void)
 {
+	struct xfs_buftarg	*btp = iocur_top->bp->b_target;
 	int ret;
 
 	ret = -libxfs_bwrite(iocur_top->bp);
@@ -465,7 +466,7 @@ write_cur_buf(void)
 		dbprintf(_("write error: %s\n"), strerror(ret));
 
 	/* re-read buffer from disk */
-	ret = -libxfs_readbufr(mp->m_ddev_targp, iocur_top->bb, iocur_top->bp,
+	ret = -libxfs_readbufr(btp, iocur_top->bb, iocur_top->bp,
 			      iocur_top->blen, 0);
 	if (ret != 0)
 		dbprintf(_("read error: %s\n"), strerror(ret));
@@ -474,6 +475,7 @@ write_cur_buf(void)
 static void
 write_cur_bbs(void)
 {
+	struct xfs_buftarg	*btp = iocur_top->bp->b_target;
 	int ret;
 
 	ret = -libxfs_bwrite(iocur_top->bp);
@@ -482,7 +484,7 @@ write_cur_bbs(void)
 
 
 	/* re-read buffer from disk */
-	ret = -libxfs_readbufr_map(mp->m_ddev_targp, iocur_top->bp, 0);
+	ret = -libxfs_readbufr_map(btp, iocur_top->bp, 0);
 	if (ret != 0)
 		dbprintf(_("read error: %s\n"), strerror(ret));
 }
@@ -541,9 +543,9 @@ static void
 __set_cur(
 	struct xfs_buftarg	*btargp,
 	const typ_t		*type,
-	xfs_daddr_t		 blknum,
-	int			 len,
-	int			 ring_flag,
+	xfs_daddr_t		blknum,
+	int			len,
+	int			ring_flag,
 	bbmap_t			*bbmap)
 {
 	struct xfs_buf		*bp;
@@ -647,6 +649,22 @@ set_log_cur(
 	__set_cur(mp->m_logdev_targp, type, blknum, len, ring_flag, bbmap);
 }
 
+int
+set_rt_cur(
+	const typ_t	*type,
+	xfs_daddr_t	blknum,
+	int		len,
+	int		ring_flag,
+	bbmap_t		*bbmap)
+{
+	if (!mp->m_rtdev_targp->bt_bdev) {
+		printf(_("realtime device not loaded, use -R.\n"));
+		return ENODEV;
+	}
+
+	__set_cur(mp->m_rtdev_targp, type, blknum, len, ring_flag, bbmap);
+	return 0;
+}
 
 void
 set_iocur_type(
diff --git a/db/io.h b/db/io.h
index f48b67b47a2b55..bb5065f06c0d8e 100644
--- a/db/io.h
+++ b/db/io.h
@@ -51,6 +51,8 @@ extern void	set_cur(const struct typ *type, xfs_daddr_t blknum,
 			int len, int ring_add, bbmap_t *bbmap);
 extern void	set_log_cur(const struct typ *type, xfs_daddr_t blknum,
 			int len, int ring_add, bbmap_t *bbmap);
+extern int	set_rt_cur(const struct typ *type, xfs_daddr_t blknum,
+			int len, int ring_add, bbmap_t *bbmap);
 extern void     ring_add(void);
 extern void	set_iocur_type(const struct typ *type);
 extern void	xfs_dummy_verify(struct xfs_buf *bp);
diff --git a/db/xfs_admin.sh b/db/xfs_admin.sh
index cc650c4255036b..52a658ba4a540f 100755
--- a/db/xfs_admin.sh
+++ b/db/xfs_admin.sh
@@ -8,6 +8,7 @@ status=0
 require_offline=""
 require_online=""
 DB_OPTS=""
+DB_DEV_OPTS=""
 REPAIR_OPTS=""
 IO_OPTS=""
 REPAIR_DEV_OPTS=""
@@ -42,6 +43,7 @@ do
 		require_offline=1
 		;;
 	r)	REPAIR_DEV_OPTS=" -r '$OPTARG'"
+		DB_DEV_OPTS=" -R '$OPTARG'"
 		require_offline=1
 		;;
 	u)	DB_OPTS=$DB_OPTS" -r -c uuid"
@@ -89,7 +91,7 @@ case $# in
 
 		if [ -n "$DB_OPTS" ]
 		then
-			eval xfs_db -x -p xfs_admin $LOG_OPTS $DB_OPTS "$1"
+			eval xfs_db -x -p xfs_admin $LOG_OPTS $DB_DEV_OPTS $DB_OPTS "$1"
 			status=$?
 		fi
 		if [ -n "$REPAIR_OPTS" ]
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 291ec1c5827bfd..5faf8dbb1d679f 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -14,6 +14,9 @@ .SH SYNOPSIS
 .B \-l
 .I logdev
 ] [
+.B \-R
+.I rtdev
+] [
 .B \-p
 .I progname
 ]
@@ -80,6 +83,16 @@ .SH OPTIONS
 for prompts and some error messages, the default value is
 .BR xfs_db .
 .TP
+.B -R
+.I rtdev
+Specifies the device where the realtime data resides.
+This is only relevant for filesystems that have a realtime section.
+See the
+.BR mkfs.xfs "(8) " \-r
+option, and refer to
+.BR xfs (5)
+for a detailed description of the XFS realtime section.
+.TP
 .B -r
 Open
 .I device


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

* [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
  2024-10-25  6:34   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
@ 2024-10-25  6:34   ` Darrick J. Wong
  2024-10-28  8:34     ` Christoph Hellwig
  2024-10-25  6:35   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
                     ` (5 subsequent siblings)
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:34 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

When db is reporting on an io cursor and the cursor points to the
realtime device, print that fact.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/block.c |    2 ++
 db/io.c    |   11 +++++++++++
 db/io.h    |    1 +
 3 files changed, 14 insertions(+)


diff --git a/db/block.c b/db/block.c
index 22930e5a287e8f..bd25cdbe193f4f 100644
--- a/db/block.c
+++ b/db/block.c
@@ -133,6 +133,8 @@ daddr_f(
 			dbprintf(_("datadev daddr is %lld\n"), daddr);
 		else if (iocur_is_extlogdev(iocur_top))
 			dbprintf(_("logdev daddr is %lld\n"), daddr);
+		else if (iocur_is_rtdev(iocur_top))
+			dbprintf(_("rtdev daddr is %lld\n"), daddr);
 		else
 			dbprintf(_("current daddr is %lld\n"), daddr);
 
diff --git a/db/io.c b/db/io.c
index 26b8e78c2ebda8..3841c0dcb86ead 100644
--- a/db/io.c
+++ b/db/io.c
@@ -159,6 +159,15 @@ iocur_is_extlogdev(const struct iocur *ioc)
 	return bp->b_target == bp->b_mount->m_logdev_targp;
 }
 
+bool
+iocur_is_rtdev(const struct iocur *ioc)
+{
+	if (!ioc->bp)
+		return false;
+
+	return ioc->bp->b_target == ioc->bp->b_mount->m_rtdev_targp;
+}
+
 void
 print_iocur(
 	char	*tag,
@@ -171,6 +180,8 @@ print_iocur(
 		block_unit = "fsbno";
 	else if (iocur_is_extlogdev(ioc))
 		block_unit = "logbno";
+	else if (iocur_is_rtdev(ioc))
+		block_unit = "rtbno";
 
 	dbprintf("%s\n", tag);
 	dbprintf(_("\tbyte offset %lld, length %d\n"), ioc->off, ioc->len);
diff --git a/db/io.h b/db/io.h
index bb5065f06c0d8e..8eab4cd9c9a464 100644
--- a/db/io.h
+++ b/db/io.h
@@ -60,6 +60,7 @@ extern void	xfs_verify_recalc_crc(struct xfs_buf *bp);
 
 bool iocur_is_ddev(const struct iocur *ioc);
 bool iocur_is_extlogdev(const struct iocur *ioc);
+bool iocur_is_rtdev(const struct iocur *ioc);
 
 /*
  * returns -1 for unchecked, 0 for bad and 1 for good


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

* [PATCH 3/8] xfs_db: make the daddr command target the realtime device
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
  2024-10-25  6:34   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
  2024-10-25  6:34   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
@ 2024-10-25  6:35   ` Darrick J. Wong
  2024-10-28  8:35     ` Christoph Hellwig
  2024-10-25  6:35   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
                     ` (4 subsequent siblings)
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:35 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Make it so that users can issue the command "daddr -r XXX" to select
disk block XXX on the realtime device.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/block.c        |   43 ++++++++++++++++++++++++++++++++++++++-----
 man/man8/xfs_db.8 |    6 +++++-
 2 files changed, 43 insertions(+), 6 deletions(-)


diff --git a/db/block.c b/db/block.c
index bd25cdbe193f4f..6ad9f038c6da67 100644
--- a/db/block.c
+++ b/db/block.c
@@ -31,7 +31,7 @@ static const cmdinfo_t	ablock_cmd =
 	{ "ablock", NULL, ablock_f, 1, 1, 1, N_("filoff"),
 	  N_("set address to file offset (attr fork)"), ablock_help };
 static const cmdinfo_t	daddr_cmd =
-	{ "daddr", NULL, daddr_f, 0, 1, 1, N_("[d]"),
+	{ "daddr", NULL, daddr_f, 0, -1, 1, N_("[d]"),
 	  N_("set address to daddr value"), daddr_help };
 static const cmdinfo_t	dblock_cmd =
 	{ "dblock", NULL, dblock_f, 1, 1, 1, N_("filoff"),
@@ -117,16 +117,36 @@ daddr_help(void)
 ));
 }
 
+enum daddr_target {
+	DT_DATA,
+	DT_RT,
+};
+
 static int
 daddr_f(
 	int		argc,
 	char		**argv)
 {
+	xfs_rfsblock_t	max_daddrs = mp->m_sb.sb_dblocks;
 	int64_t		d;
 	char		*p;
 	int		bb_count = BTOBB(mp->m_sb.sb_sectsize);
+	int		c;
+	enum daddr_target tgt = DT_DATA;
 
-	if (argc == 1) {
+	while ((c = getopt(argc, argv, "r")) != -1) {
+		switch (c) {
+		case 'r':
+			tgt = DT_RT;
+			max_daddrs = mp->m_sb.sb_rblocks;
+			break;
+		default:
+			daddr_help();
+			return 0;
+		}
+	}
+
+	if (optind == argc) {
 		xfs_daddr_t	daddr = iocur_top->off >> BBSHIFT;
 
 		if (iocur_is_ddev(iocur_top))
@@ -140,14 +160,27 @@ daddr_f(
 
 		return 0;
 	}
-	d = (int64_t)strtoull(argv[1], &p, 0);
+
+	if (optind != argc - 1) {
+		daddr_help();
+		return 0;
+	}
+
+	d = (int64_t)strtoull(argv[optind], &p, 0);
 	if (*p != '\0' ||
-	    d >= mp->m_sb.sb_dblocks << (mp->m_sb.sb_blocklog - BBSHIFT)) {
+	    d >= max_daddrs << (mp->m_sb.sb_blocklog - BBSHIFT)) {
 		dbprintf(_("bad daddr %s\n"), argv[1]);
 		return 0;
 	}
 	ASSERT(typtab[TYP_DATA].typnm == TYP_DATA);
-	set_cur(&typtab[TYP_DATA], d, bb_count, DB_RING_ADD, NULL);
+	switch (tgt) {
+	case DT_DATA:
+		set_cur(&typtab[TYP_DATA], d, bb_count, DB_RING_ADD, NULL);
+		break;
+	case DT_RT:
+		set_rt_cur(&typtab[TYP_DATA], d, bb_count, DB_RING_ADD, NULL);
+		break;
+	}
 	return 0;
 }
 
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 5faf8dbb1d679f..f50ac949be0189 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -671,7 +671,7 @@ .SH COMMANDS
 Validate and display the current value and state of the structure's CRC.
 .RE
 .TP
-.BI "daddr [" d ]
+.BI "daddr [" -r "] [" d ]
 Set current address to the daddr (512 byte block) given by
 .IR d .
 If no value for
@@ -680,6 +680,10 @@ .SH COMMANDS
 The type is set to
 .B data
 (uninterpreted).
+
+If an address and the
+.B \-r
+option are specified, the current address is set to the realtime device.
 .TP
 .BI dblock " filoff"
 Set current address to the offset


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

* [PATCH 4/8] xfs_db: access realtime file blocks
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (2 preceding siblings ...)
  2024-10-25  6:35   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
@ 2024-10-25  6:35   ` Darrick J. Wong
  2024-10-28  8:37     ` Christoph Hellwig
  2024-10-25  6:35   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
                     ` (3 subsequent siblings)
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:35 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Now that we have the ability to point the io cursor at the realtime
device, let's make it so that the "dblock" command can walk the contents
of realtime files.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/block.c |   17 +++++++++++++++--
 db/faddr.c |    4 +++-
 2 files changed, 18 insertions(+), 3 deletions(-)


diff --git a/db/block.c b/db/block.c
index 6ad9f038c6da67..ff34557a612a2f 100644
--- a/db/block.c
+++ b/db/block.c
@@ -196,6 +196,13 @@ dblock_help(void)
 ));
 }
 
+static inline bool
+is_rtfile(
+	struct xfs_dinode	*dip)
+{
+	return dip->di_flags & cpu_to_be16(XFS_DIFLAG_REALTIME);
+}
+
 static int
 dblock_f(
 	int		argc,
@@ -235,8 +242,14 @@ dblock_f(
 	ASSERT(typtab[type].typnm == type);
 	if (nex > 1)
 		make_bbmap(&bbmap, nex, bmp);
-	set_cur(&typtab[type], (int64_t)XFS_FSB_TO_DADDR(mp, dfsbno),
-		nb * blkbb, DB_RING_ADD, nex > 1 ? &bbmap : NULL);
+	if (is_rtfile(iocur_top->data))
+		set_rt_cur(&typtab[type], (int64_t)dfsbno << mp->m_blkbb_log,
+				nb * blkbb, DB_RING_ADD,
+				nex > 1 ? &bbmap : NULL);
+	else
+		set_cur(&typtab[type], (int64_t)XFS_FSB_TO_DADDR(mp, dfsbno),
+				nb * blkbb, DB_RING_ADD,
+				nex > 1 ? &bbmap : NULL);
 	free(bmp);
 	return 0;
 }
diff --git a/db/faddr.c b/db/faddr.c
index ec4aae68bb5a81..fd65b86b5e915d 100644
--- a/db/faddr.c
+++ b/db/faddr.c
@@ -323,7 +323,9 @@ fa_drtbno(
 		dbprintf(_("null block number, cannot set new addr\n"));
 		return;
 	}
-	/* need set_cur to understand rt subvolume */
+
+	set_rt_cur(&typtab[next], (int64_t)XFS_FSB_TO_BB(mp, bno), blkbb,
+			DB_RING_ADD, NULL);
 }
 
 /*ARGSUSED*/


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

* [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (3 preceding siblings ...)
  2024-10-25  6:35   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
@ 2024-10-25  6:35   ` Darrick J. Wong
  2024-10-28  8:38     ` Christoph Hellwig
  2024-10-25  6:35   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
                     ` (2 subsequent siblings)
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:35 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Add two commands to xfs_db so that we can point ourselves at any
arbitrary realtime block or extent.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/block.c        |  105 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   20 ++++++++++
 2 files changed, 125 insertions(+)


diff --git a/db/block.c b/db/block.c
index ff34557a612a2f..000f9c1ed10fcd 100644
--- a/db/block.c
+++ b/db/block.c
@@ -25,6 +25,10 @@ static int	dblock_f(int argc, char **argv);
 static void     dblock_help(void);
 static int	fsblock_f(int argc, char **argv);
 static void     fsblock_help(void);
+static int	rtblock_f(int argc, char **argv);
+static void	rtblock_help(void);
+static int	rtextent_f(int argc, char **argv);
+static void	rtextent_help(void);
 static void	print_rawdata(void *data, int len);
 
 static const cmdinfo_t	ablock_cmd =
@@ -39,6 +43,12 @@ static const cmdinfo_t	dblock_cmd =
 static const cmdinfo_t	fsblock_cmd =
 	{ "fsblock", "fsb", fsblock_f, 0, 1, 1, N_("[fsb]"),
 	  N_("set address to fsblock value"), fsblock_help };
+static const cmdinfo_t	rtblock_cmd =
+	{ "rtblock", "rtbno", rtblock_f, 0, 1, 1, N_("[rtbno]"),
+	  N_("set address to rtblock value"), rtblock_help };
+static const cmdinfo_t	rtextent_cmd =
+	{ "rtextent", "rtx", rtextent_f, 0, 1, 1, N_("[rtxno]"),
+	  N_("set address to rtextent value"), rtextent_help };
 
 static void
 ablock_help(void)
@@ -104,6 +114,8 @@ block_init(void)
 	add_command(&daddr_cmd);
 	add_command(&dblock_cmd);
 	add_command(&fsblock_cmd);
+	add_command(&rtblock_cmd);
+	add_command(&rtextent_cmd);
 }
 
 static void
@@ -302,6 +314,99 @@ fsblock_f(
 	return 0;
 }
 
+static void
+rtblock_help(void)
+{
+	dbprintf(_(
+"\n Example:\n"
+"\n"
+" 'rtblock 1023' - sets the file position to the 1023rd block on the realtime\n"
+" volume. The filesystem block size is specified in the superblock and set\n"
+" during mkfs time.\n\n"
+));
+}
+
+static int
+rtblock_f(
+	int		argc,
+	char		**argv)
+{
+	xfs_rtblock_t	rtbno;
+	char		*p;
+
+	if (argc == 1) {
+		if (!iocur_is_rtdev(iocur_top)) {
+			dbprintf(_("cursor does not point to rt device\n"));
+			return 0;
+		}
+		dbprintf(_("current rtblock is %lld\n"),
+			XFS_BB_TO_FSB(mp, iocur_top->off >> BBSHIFT));
+		return 0;
+	}
+	rtbno = strtoull(argv[1], &p, 0);
+	if (*p != '\0') {
+		dbprintf(_("bad rtblock %s\n"), argv[1]);
+		return 0;
+	}
+	if (rtbno >= mp->m_sb.sb_rblocks) {
+		dbprintf(_("bad rtblock %s\n"), argv[1]);
+		return 0;
+	}
+	ASSERT(typtab[TYP_DATA].typnm == TYP_DATA);
+	set_rt_cur(&typtab[TYP_DATA], XFS_FSB_TO_BB(mp, rtbno), blkbb,
+			DB_RING_ADD, NULL);
+	return 0;
+}
+
+static void
+rtextent_help(void)
+{
+	dbprintf(_(
+"\n Example:\n"
+"\n"
+" 'rtextent 10' - sets the file position to the 10th extent on the realtime\n"
+" volume. The realtime extent size is specified in the superblock and set\n"
+" during mkfs or growfs time.\n\n"
+));
+}
+
+static int
+rtextent_f(
+	int		argc,
+	char		**argv)
+{
+	xfs_rtblock_t	rtbno;
+	xfs_rtxnum_t	rtx;
+	char		*p;
+
+	if (argc == 1) {
+		if (!iocur_is_rtdev(iocur_top)) {
+			dbprintf(_("cursor does not point to rt device\n"));
+			return 0;
+		}
+
+		rtbno = XFS_BB_TO_FSB(mp, iocur_top->off >> BBSHIFT);
+		dbprintf(_("current rtextent is %lld\n"),
+				xfs_rtb_to_rtx(mp, rtbno));
+		return 0;
+	}
+	rtx = strtoull(argv[1], &p, 0);
+	if (*p != '\0') {
+		dbprintf(_("bad rtextent %s\n"), argv[1]);
+		return 0;
+	}
+	if (rtx >= mp->m_sb.sb_rextents) {
+		dbprintf(_("bad rtextent %s\n"), argv[1]);
+		return 0;
+	}
+
+	rtbno = xfs_rtx_to_rtb(mp, rtx);
+	ASSERT(typtab[TYP_DATA].typnm == TYP_DATA);
+	set_rt_cur(&typtab[TYP_DATA], XFS_FSB_TO_BB(mp, rtbno),
+			mp->m_sb.sb_rextsize * blkbb, DB_RING_ADD, NULL);
+	return 0;
+}
+
 void
 print_block(
 	const field_t	*fields,
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index f50ac949be0189..b5060a68d3bfc4 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1099,6 +1099,26 @@ .SH COMMANDS
 Exit
 .BR xfs_db .
 .TP
+.BI "rtblock [" rtbno ]
+Set current address to the rtblock value given by
+.IR rtbno .
+If no value for
+.I rtbno
+is given the current address is printed, expressed as an rtbno.
+The type is set to
+.B data
+(uninterpreted).
+.TP
+.BI "rtextent [" rtxno ]
+Set current address to the rtextent value given by
+.IR rtextent .
+If no value for
+.I rtextent
+is given the current address is printed, expressed as an rtextent.
+The type is set to
+.B data
+(uninterpreted).
+.TP
 .BI "ring [" index ]
 Show position ring (if no
 .I index


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

* [PATCH 6/8] xfs_db: enable conversion of rt space units
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-25  6:35   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
@ 2024-10-25  6:35   ` Darrick J. Wong
  2024-10-28  8:41     ` Christoph Hellwig
  2024-10-25  6:36   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
  2024-10-25  6:36   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:35 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Teach the xfs_db convert function about rt extents, rt block numbers,
and how to compute offsets within the rt bitmap and summary files.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/convert.c      |  232 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 man/man8/xfs_db.8 |   51 ++++++++++++
 2 files changed, 260 insertions(+), 23 deletions(-)


diff --git a/db/convert.c b/db/convert.c
index e1466057031da6..811bac00f7196f 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -26,6 +26,10 @@
 	 agino_to_bytes(XFS_INO_TO_AGINO(mp, (x))))
 #define	inoidx_to_bytes(x)	\
 	((uint64_t)(x) << mp->m_sb.sb_inodelog)
+#define rtblock_to_bytes(x)	\
+	((uint64_t)(x) << mp->m_sb.sb_blocklog)
+#define rtx_to_rtblock(x)	\
+	((uint64_t)(x) * mp->m_sb.sb_rextsize)
 
 typedef enum {
 	CT_NONE = -1,
@@ -40,11 +44,12 @@ typedef enum {
 	CT_INO,			/* xfs_ino_t */
 	CT_INOIDX,		/* index of inode in fsblock */
 	CT_INOOFF,		/* byte offset in inode */
+	CT_RTBLOCK,		/* realtime block */
+	CT_RTX,			/* realtime extent */
 	NCTS
 } ctype_t;
 
 typedef struct ctydesc {
-	ctype_t		ctype;
 	int		allowed;
 	const char	**names;
 } ctydesc_t;
@@ -61,12 +66,16 @@ typedef union {
 	xfs_ino_t	ino;
 	int		inoidx;
 	int		inooff;
+	xfs_rtblock_t	rtblock;
+	xfs_rtblock_t	rtx;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
+static int		rtconvert_f(int argc, char **argv);
 static int		convert_f(int argc, char **argv);
 static int		getvalue(char *s, ctype_t ctype, cval_t *val);
-static ctype_t		lookupcty(char *ctyname);
+static ctype_t		lookupcty(const struct ctydesc *descs,
+				  const char *ctyname);
 
 static const char	*agblock_names[] = { "agblock", "agbno", NULL };
 static const char	*agino_names[] = { "agino", "aginode", NULL };
@@ -74,6 +83,8 @@ static const char	*agnumber_names[] = { "agnumber", "agno", NULL };
 static const char	*bboff_names[] = { "bboff", "daddroff", NULL };
 static const char	*blkoff_names[] = { "blkoff", "fsboff", "agboff",
 					    NULL };
+static const char	*rtblkoff_names[] = { "blkoff", "rtboff",
+					    NULL };
 static const char	*byte_names[] = { "byte", "fsbyte", NULL };
 static const char	*daddr_names[] = { "daddr", "bb", NULL };
 static const char	*fsblock_names[] = { "fsblock", "fsb", "fsbno", NULL };
@@ -81,30 +92,91 @@ static const char	*ino_names[] = { "ino", "inode", NULL };
 static const char	*inoidx_names[] = { "inoidx", "offset", NULL };
 static const char	*inooff_names[] = { "inooff", "inodeoff", NULL };
 
+static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
+static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
+
 static const ctydesc_t	ctydescs[NCTS] = {
-	{ CT_AGBLOCK, M(AGNUMBER)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),
-	  agblock_names },
-	{ CT_AGINO, M(AGNUMBER)|M(INOOFF), agino_names },
-	{ CT_AGNUMBER,
-	  M(AGBLOCK)|M(AGINO)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),
-	  agnumber_names },
-	{ CT_BBOFF, M(AGBLOCK)|M(AGNUMBER)|M(DADDR)|M(FSBLOCK), bboff_names },
-	{ CT_BLKOFF, M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK), blkoff_names },
-	{ CT_BYTE, 0, byte_names },
-	{ CT_DADDR, M(BBOFF), daddr_names },
-	{ CT_FSBLOCK, M(BBOFF)|M(BLKOFF)|M(INOIDX), fsblock_names },
-	{ CT_INO, M(INOOFF), ino_names },
-	{ CT_INOIDX, M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK)|M(INOOFF),
-	  inoidx_names },
-	{ CT_INOOFF,
-	  M(AGBLOCK)|M(AGINO)|M(AGNUMBER)|M(FSBLOCK)|M(INO)|M(INOIDX),
-	  inooff_names },
+	[CT_AGBLOCK] = {
+		.allowed = M(AGNUMBER)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),
+		.names   = agblock_names,
+	},
+	[CT_AGINO] = {
+		.allowed = M(AGNUMBER)|M(INOOFF),
+		.names   = agino_names,
+	},
+	[CT_AGNUMBER] = {
+		.allowed = M(AGBLOCK)|M(AGINO)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),
+		.names   = agnumber_names,
+	},
+	[CT_BBOFF] = {
+		.allowed = M(AGBLOCK)|M(AGNUMBER)|M(DADDR)|M(FSBLOCK),
+		.names   = bboff_names,
+	},
+	[CT_BLKOFF] = {
+		.allowed = M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK),
+		.names   = blkoff_names,
+	},
+	[CT_BYTE] = {
+		.allowed = 0,
+		.names   = byte_names,
+	},
+	[CT_DADDR] = {
+		.allowed = M(BBOFF),
+		.names   = daddr_names,
+	},
+	[CT_FSBLOCK] = {
+		.allowed = M(BBOFF)|M(BLKOFF)|M(INOIDX),
+		.names   = fsblock_names,
+	},
+	[CT_INO] = {
+		.allowed = M(INOOFF),
+		.names   = ino_names,
+	},
+	[CT_INOIDX] = {
+		.allowed = M(AGBLOCK)|M(AGNUMBER)|M(FSBLOCK)|M(INOOFF),
+		.names   = inoidx_names,
+	},
+	[CT_INOOFF] = {
+		.allowed = M(AGBLOCK)|M(AGINO)|M(AGNUMBER)|M(FSBLOCK)|M(INO)|M(INOIDX),
+		.names   = inooff_names,
+	},
+};
+
+static const ctydesc_t	ctydescs_rt[NCTS] = {
+	[CT_BBOFF] = {
+		.allowed = M(DADDR)|M(RTBLOCK),
+		.names   = bboff_names,
+	},
+	[CT_BLKOFF] = {
+		.allowed = M(RTBLOCK),
+		.names   = rtblkoff_names,
+	},
+	[CT_BYTE] = {
+		.allowed = 0,
+		.names   = byte_names,
+	},
+	[CT_DADDR] = {
+		.allowed = M(BBOFF),
+		.names   = daddr_names,
+	},
+	[CT_RTBLOCK] = {
+		.allowed = M(BBOFF)|M(BLKOFF),
+		.names   = rtblock_names,
+	},
+	[CT_RTX] = {
+		.allowed = M(BBOFF)|M(BLKOFF),
+		.names   = rtx_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
 	{ "convert", NULL, convert_f, 3, 9, 0, "type num [type num]... type",
 	  "convert from one address form to another", NULL };
 
+static const cmdinfo_t	rtconvert_cmd =
+	{ "rtconvert", NULL, rtconvert_f, 3, 9, 0, "type num [type num]... type",
+	  "convert from one realtime address form to another", NULL };
+
 static uint64_t
 bytevalue(ctype_t ctype, cval_t *val)
 {
@@ -131,6 +203,10 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return inoidx_to_bytes(val->inoidx);
 	case CT_INOOFF:
 		return (uint64_t)val->inooff;
+	case CT_RTBLOCK:
+		return rtblock_to_bytes(val->rtblock);
+	case CT_RTX:
+		return rtblock_to_bytes(rtx_to_rtblock(val->rtx));
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -159,13 +235,13 @@ convert_f(int argc, char **argv)
 			 "arguments\n"), argc);
 		return 0;
 	}
-	if ((wtype = lookupcty(argv[argc - 1])) == CT_NONE) {
+	if ((wtype = lookupcty(ctydescs, argv[argc - 1])) == CT_NONE) {
 		dbprintf(_("unknown conversion type %s\n"), argv[argc - 1]);
 		return 0;
 	}
 
 	for (i = mask = conmask = 0; i < (argc - 1) / 2; i++) {
-		c = lookupcty(argv[i * 2]);
+		c = lookupcty(ctydescs, argv[i * 2]);
 		if (c == CT_NONE) {
 			dbprintf(_("unknown conversion type %s\n"), argv[i * 2]);
 			return 0;
@@ -230,6 +306,107 @@ convert_f(int argc, char **argv)
 	case CT_INOOFF:
 		v &= mp->m_sb.sb_inodesize - 1;
 		break;
+	case CT_RTBLOCK:
+	case CT_RTX:
+		/* shouldn't get here */
+		ASSERT(0);
+		break;
+	case CT_NONE:
+	case NCTS:
+		/* NOTREACHED */
+		break;
+	}
+	dbprintf("0x%llx (%llu)\n", v, v);
+	return 0;
+}
+
+static inline xfs_rtblock_t
+xfs_daddr_to_rtb(
+	struct xfs_mount	*mp,
+	xfs_daddr_t		daddr)
+{
+	return daddr >> mp->m_blkbb_log;
+}
+
+static int
+rtconvert_f(int argc, char **argv)
+{
+	ctype_t		c;
+	int		conmask;
+	cval_t		cvals[NCTS] = {};
+	int		i;
+	int		mask;
+	uint64_t	v;
+	ctype_t		wtype;
+
+	/* move past the "rtconvert" command */
+	argc--;
+	argv++;
+
+	if ((argc % 2) != 1) {
+		dbprintf(_("bad argument count %d to rtconvert, expected 3,5,7,9 "
+			 "arguments\n"), argc);
+		return 0;
+	}
+	if ((wtype = lookupcty(ctydescs_rt, argv[argc - 1])) == CT_NONE) {
+		dbprintf(_("unknown conversion type %s\n"), argv[argc - 1]);
+		return 0;
+	}
+
+	for (i = mask = conmask = 0; i < (argc - 1) / 2; i++) {
+		c = lookupcty(ctydescs_rt, argv[i * 2]);
+		if (c == CT_NONE) {
+			dbprintf(_("unknown conversion type %s\n"), argv[i * 2]);
+			return 0;
+		}
+		if (c == wtype) {
+			dbprintf(_("result type same as argument\n"));
+			return 0;
+		}
+		if (conmask & (1 << c)) {
+			dbprintf(_("conflicting conversion type %s\n"),
+				argv[i * 2]);
+			return 0;
+		}
+		if (!getvalue(argv[i * 2 + 1], c, &cvals[c]))
+			return 0;
+		mask |= 1 << c;
+		conmask |= ~ctydescs_rt[c].allowed;
+	}
+	v = 0;
+	for (c = (ctype_t)0; c < NCTS; c++) {
+		if (!(mask & (1 << c)))
+			continue;
+		v += bytevalue(c, &cvals[c]);
+	}
+	switch (wtype) {
+	case CT_BBOFF:
+		v &= BBMASK;
+		break;
+	case CT_BLKOFF:
+		v &= mp->m_blockmask;
+		break;
+	case CT_BYTE:
+		break;
+	case CT_DADDR:
+		v >>= BBSHIFT;
+		break;
+	case CT_RTBLOCK:
+		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT);
+		break;
+	case CT_RTX:
+		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT) / mp->m_sb.sb_rextsize;
+		break;
+	case CT_AGBLOCK:
+	case CT_AGINO:
+	case CT_AGNUMBER:
+	case CT_FSBLOCK:
+	case CT_INO:
+	case CT_INOIDX:
+	case CT_INOOFF:
+		/* shouldn't get here */
+		ASSERT(0);
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
@@ -243,6 +420,7 @@ void
 convert_init(void)
 {
 	add_command(&convert_cmd);
+	add_command(&rtconvert_cmd);
 }
 
 static int
@@ -290,6 +468,12 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_INOOFF:
 		val->inooff = (int)v;
 		break;
+	case CT_RTBLOCK:
+		val->rtblock = (xfs_rtblock_t)v;
+		break;
+	case CT_RTX:
+		val->rtx = (xfs_rtblock_t)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
@@ -299,13 +483,15 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 }
 
 static ctype_t
-lookupcty(char *ctyname)
+lookupcty(
+	const struct ctydesc	*descs,
+	const char		*ctyname)
 {
 	ctype_t		cty;
 	const char	**name;
 
 	for (cty = (ctype_t)0; cty < NCTS; cty++) {
-		for (name = ctydescs[cty].names; *name; name++) {
+		for (name = descs[cty].names; name && *name; name++) {
 			if (strcmp(ctyname, *name) == 0)
 				return cty;
 		}
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index b5060a68d3bfc4..fdff10cbb4fcbe 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1125,6 +1125,57 @@ .SH COMMANDS
 argument is given), or move to a specific entry in the position ring given by
 .IR index .
 .TP
+.BI "rtconvert " "type number" " [" "type number" "] ... " type
+Convert from one address form to another for realtime section addresses.
+The known
+.IR type s,
+with alternate names, are:
+.RS 1.0i
+.PD 0
+.HP
+.B bboff
+or
+.B daddroff
+(byte offset in a
+.BR daddr )
+.HP
+.B blkoff
+or
+.B fsboff or
+.B rtboff
+(byte offset in a
+.B rtblock
+or
+.BR rtextent )
+.HP
+.B byte
+or
+.B fsbyte
+(byte address in filesystem)
+.HP
+.B daddr
+or
+.B bb
+(disk address, 512-byte blocks)
+.HP
+.B rtblock
+or
+.B rtb
+or
+.B rtbno
+(realtime filesystem block, see the
+.B fsblock
+command)
+.HP
+.B rtx
+or
+.B rtextent
+(realtime extent)
+.PD
+.RE
+.IP
+Only conversions that "make sense" are allowed.
+.TP
 .BI "sb [" agno ]
 Set current address to SB header in allocation group
 .IR agno .


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

* [PATCH 7/8] xfs_db: convert rtbitmap geometry
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (5 preceding siblings ...)
  2024-10-25  6:35   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
@ 2024-10-25  6:36   ` Darrick J. Wong
  2024-10-28  8:42     ` Christoph Hellwig
  2024-10-25  6:36   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:36 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Teach the rtconvert command to be able to convert realtime blocks and
extents to locations within the rt bitmap.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/convert.c      |   40 ++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   10 ++++++++++
 2 files changed, 50 insertions(+)


diff --git a/db/convert.c b/db/convert.c
index 811bac00f7196f..35e71f8a4421d6 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -30,6 +30,10 @@
 	((uint64_t)(x) << mp->m_sb.sb_blocklog)
 #define rtx_to_rtblock(x)	\
 	((uint64_t)(x) * mp->m_sb.sb_rextsize)
+#define rbmblock_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock(xfs_rbmblock_to_rtx(mp, (uint64_t)x)))
+#define rbmword_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock((uint64_t)(x) << XFS_NBWORDLOG))
 
 typedef enum {
 	CT_NONE = -1,
@@ -46,6 +50,8 @@ typedef enum {
 	CT_INOOFF,		/* byte offset in inode */
 	CT_RTBLOCK,		/* realtime block */
 	CT_RTX,			/* realtime extent */
+	CT_RBMBLOCK,		/* block within rt bitmap */
+	CT_RBMWORD,		/* word within rt bitmap */
 	NCTS
 } ctype_t;
 
@@ -68,6 +74,8 @@ typedef union {
 	int		inooff;
 	xfs_rtblock_t	rtblock;
 	xfs_rtblock_t	rtx;
+	xfs_fileoff_t	rbmblock;
+	unsigned int	rbmword;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
@@ -94,6 +102,8 @@ static const char	*inooff_names[] = { "inooff", "inodeoff", NULL };
 
 static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
 static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
+static const char	*rbmblock_names[] = { "rbmblock", "rbmb", NULL };
+static const char	*rbmword_names[] = { "rbmword", "rbmw", NULL };
 
 static const ctydesc_t	ctydescs[NCTS] = {
 	[CT_AGBLOCK] = {
@@ -167,6 +177,14 @@ static const ctydesc_t	ctydescs_rt[NCTS] = {
 		.allowed = M(BBOFF)|M(BLKOFF),
 		.names   = rtx_names,
 	},
+	[CT_RBMBLOCK] = {
+		.allowed = M(RBMWORD),
+		.names   = rbmblock_names,
+	},
+	[CT_RBMWORD] = {
+		.allowed = M(RBMBLOCK),
+		.names   = rbmword_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
@@ -207,6 +225,10 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return rtblock_to_bytes(val->rtblock);
 	case CT_RTX:
 		return rtblock_to_bytes(rtx_to_rtblock(val->rtx));
+	case CT_RBMBLOCK:
+		return rbmblock_to_bytes(val->rbmblock);
+	case CT_RBMWORD:
+		return rbmword_to_bytes(val->rbmword);
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -308,6 +330,8 @@ convert_f(int argc, char **argv)
 		break;
 	case CT_RTBLOCK:
 	case CT_RTX:
+	case CT_RBMBLOCK:
+	case CT_RBMWORD:
 		/* shouldn't get here */
 		ASSERT(0);
 		break;
@@ -397,6 +421,16 @@ rtconvert_f(int argc, char **argv)
 	case CT_RTX:
 		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT) / mp->m_sb.sb_rextsize;
 		break;
+	case CT_RBMBLOCK:
+		v = xfs_rtx_to_rbmblock(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
+	case CT_RBMWORD:
+		v = xfs_rtx_to_rbmword(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
 	case CT_AGBLOCK:
 	case CT_AGINO:
 	case CT_AGNUMBER:
@@ -474,6 +508,12 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_RTX:
 		val->rtx = (xfs_rtblock_t)v;
 		break;
+	case CT_RBMBLOCK:
+		val->rbmblock = (xfs_fileoff_t)v;
+		break;
+	case CT_RBMWORD:
+		val->rbmword = (unsigned int)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index fdff10cbb4fcbe..7b7d2ac124107c 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1171,6 +1171,16 @@ .SH COMMANDS
 or
 .B rtextent
 (realtime extent)
+.HP
+.B rbmblock
+or
+.B rbmb
+(realtime bitmap block)
+.HP
+.B rbmword
+or
+.B rbmw
+(32-bit word within a realtime bitmap block)
 .PD
 .RE
 .IP


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

* [PATCH 8/8] xfs_db: convert rtsummary geometry
  2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (6 preceding siblings ...)
  2024-10-25  6:36   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
@ 2024-10-25  6:36   ` Darrick J. Wong
  2024-10-28  8:42     ` Christoph Hellwig
  7 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:36 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Teach the rtconvert command to be able to convert realtime blocks and
extents to locations within the rt summary.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/convert.c      |  153 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 man/man8/xfs_db.8 |   29 ++++++++++
 2 files changed, 174 insertions(+), 8 deletions(-)


diff --git a/db/convert.c b/db/convert.c
index 35e71f8a4421d6..048c1766f8152b 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -52,6 +52,9 @@ typedef enum {
 	CT_RTX,			/* realtime extent */
 	CT_RBMBLOCK,		/* block within rt bitmap */
 	CT_RBMWORD,		/* word within rt bitmap */
+	CT_RSUMBLOCK,		/* block within rt summary */
+	CT_RSUMLOG,		/* log level for rtsummary computations */
+	CT_RSUMINFO,		/* info word within rt summary */
 	NCTS
 } ctype_t;
 
@@ -76,6 +79,7 @@ typedef union {
 	xfs_rtblock_t	rtx;
 	xfs_fileoff_t	rbmblock;
 	unsigned int	rbmword;
+	xfs_fileoff_t	rsumblock;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
@@ -104,6 +108,12 @@ static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
 static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
 static const char	*rbmblock_names[] = { "rbmblock", "rbmb", NULL };
 static const char	*rbmword_names[] = { "rbmword", "rbmw", NULL };
+static const char	*rsumblock_names[] = { "rsumblock", "rsmb", NULL };
+static const char	*rsumlog_names[] = { "rsumlog", "rsml", NULL };
+static const char	*rsumword_names[] = { "rsuminfo", "rsmi", NULL };
+
+static int		rsuminfo;
+static int		rsumlog;
 
 static const ctydesc_t	ctydescs[NCTS] = {
 	[CT_AGBLOCK] = {
@@ -154,37 +164,50 @@ static const ctydesc_t	ctydescs[NCTS] = {
 
 static const ctydesc_t	ctydescs_rt[NCTS] = {
 	[CT_BBOFF] = {
-		.allowed = M(DADDR)|M(RTBLOCK),
+		.allowed = M(DADDR)|M(RTBLOCK)|M(RSUMLOG),
 		.names   = bboff_names,
 	},
 	[CT_BLKOFF] = {
-		.allowed = M(RTBLOCK),
+		.allowed = M(RTBLOCK)|M(RSUMLOG),
 		.names   = rtblkoff_names,
 	},
 	[CT_BYTE] = {
-		.allowed = 0,
+		.allowed = 0|M(RSUMLOG),
 		.names   = byte_names,
 	},
 	[CT_DADDR] = {
-		.allowed = M(BBOFF),
+		.allowed = M(BBOFF)|M(RSUMLOG),
 		.names   = daddr_names,
 	},
 	[CT_RTBLOCK] = {
-		.allowed = M(BBOFF)|M(BLKOFF),
+		.allowed = M(BBOFF)|M(BLKOFF)|M(RSUMLOG),
 		.names   = rtblock_names,
 	},
 	[CT_RTX] = {
-		.allowed = M(BBOFF)|M(BLKOFF),
+		.allowed = M(BBOFF)|M(BLKOFF)|M(RSUMLOG),
 		.names   = rtx_names,
 	},
 	[CT_RBMBLOCK] = {
-		.allowed = M(RBMWORD),
+		.allowed = M(RBMWORD)|M(RSUMLOG),
 		.names   = rbmblock_names,
 	},
 	[CT_RBMWORD] = {
-		.allowed = M(RBMBLOCK),
+		.allowed = M(RBMBLOCK)|M(RSUMLOG),
 		.names   = rbmword_names,
 	},
+	/* must be specified in order rsumlog -> rsuminfo -> rsumblock */
+	[CT_RSUMBLOCK] = {
+		.allowed = 0,
+		.names   = rsumblock_names,
+	},
+	[CT_RSUMLOG] = {
+		.allowed = M(RSUMINFO)|M(RSUMBLOCK),
+		.names   = rsumlog_names,
+	},
+	[CT_RSUMINFO] = {
+		.allowed = M(RSUMBLOCK),
+		.names   = rsumword_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
@@ -195,6 +218,39 @@ static const cmdinfo_t	rtconvert_cmd =
 	{ "rtconvert", NULL, rtconvert_f, 3, 9, 0, "type num [type num]... type",
 	  "convert from one realtime address form to another", NULL };
 
+static inline uint64_t
+rsumblock_to_bytes(
+	xfs_fileoff_t	rsumblock)
+{
+	/*
+	 * We compute the rt summary file block with this formula:
+	 *   sumoffs = (log2len * sb_rbmblocks) + rbmblock;
+	 *   sumblock = sumoffs / blockwsize;
+	 *
+	 * Hence the return value is the inverse of this:
+	 *   sumoffs = (rsumblock * blockwsize) + rsuminfo;
+	 *   rbmblock = sumoffs % (log2len * sb_rbmblocks);
+	 */
+	xfs_rtsumoff_t	sumoff;
+	xfs_fileoff_t	rbmblock;
+
+	if (rsumlog < 0) {
+		dbprintf(_("need to set rsumlog\n"));
+		return 0;
+	}
+	if (rsuminfo < 0) {
+		dbprintf(_("need to set rsuminfo\n"));
+		return 0;
+	}
+
+	sumoff = rsuminfo + (rsumblock * mp->m_blockwsize);
+	if (rsumlog)
+		rbmblock = sumoff % (rsumlog * mp->m_sb.sb_rbmblocks);
+	else
+		rbmblock = sumoff;
+	return rbmblock_to_bytes(rbmblock);
+}
+
 static uint64_t
 bytevalue(ctype_t ctype, cval_t *val)
 {
@@ -229,6 +285,16 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return rbmblock_to_bytes(val->rbmblock);
 	case CT_RBMWORD:
 		return rbmword_to_bytes(val->rbmword);
+	case CT_RSUMBLOCK:
+		return rsumblock_to_bytes(val->rbmblock);
+	case CT_RSUMLOG:
+	case CT_RSUMINFO:
+		/*
+		 * These have to specified before rsumblock, and are stored in
+		 * global variables.  Hence they do not adjust the disk address
+		 * value.
+		 */
+		return 0;
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -332,6 +398,9 @@ convert_f(int argc, char **argv)
 	case CT_RTX:
 	case CT_RBMBLOCK:
 	case CT_RBMWORD:
+	case CT_RSUMBLOCK:
+	case CT_RSUMLOG:
+	case CT_RSUMINFO:
 		/* shouldn't get here */
 		ASSERT(0);
 		break;
@@ -352,6 +421,52 @@ xfs_daddr_to_rtb(
 	return daddr >> mp->m_blkbb_log;
 }
 
+static inline uint64_t
+rt_daddr_to_rsumblock(
+	struct xfs_mount	*mp,
+	uint64_t		input)
+{
+	xfs_rtblock_t		rtbno;
+	xfs_rtxnum_t		rtx;
+	xfs_fileoff_t		rbmblock;
+	xfs_rtsumoff_t		rsumoff;
+
+	if (rsumlog < 0) {
+		dbprintf(_("need to set rsumlog\n"));
+		return 0;
+	}
+
+	rtbno = xfs_daddr_to_rtb(mp, input >> BBSHIFT);
+	rtx = xfs_rtb_to_rtx(mp, rtbno);
+	rbmblock = xfs_rtx_to_rbmblock(mp, rtx);
+	rsumoff = xfs_rtsumoffs(mp, rsumlog, rbmblock);
+
+	return xfs_rtsumoffs_to_block(mp, rsumoff);
+}
+
+static inline uint64_t
+rt_daddr_to_rsuminfo(
+	struct xfs_mount	*mp,
+	uint64_t		input)
+{
+	xfs_rtblock_t		rtbno;
+	xfs_rtxnum_t		rtx;
+	xfs_fileoff_t		rbmblock;
+	xfs_rtsumoff_t		rsumoff;
+
+	if (rsumlog < 0) {
+		dbprintf(_("need to set rsumlog\n"));
+		return 0;
+	}
+
+	rtbno = xfs_daddr_to_rtb(mp, input >> BBSHIFT);
+	rtx = xfs_rtb_to_rtx(mp, rtbno);
+	rbmblock = xfs_rtx_to_rbmblock(mp, rtx);
+	rsumoff = xfs_rtsumoffs(mp, rsumlog, rbmblock);
+
+	return xfs_rtsumoffs_to_infoword(mp, rsumoff);
+}
+
 static int
 rtconvert_f(int argc, char **argv)
 {
@@ -363,6 +478,9 @@ rtconvert_f(int argc, char **argv)
 	uint64_t	v;
 	ctype_t		wtype;
 
+	rsumlog = -1;
+	rsuminfo = -1;
+
 	/* move past the "rtconvert" command */
 	argc--;
 	argv++;
@@ -431,6 +549,16 @@ rtconvert_f(int argc, char **argv)
 				xfs_rtb_to_rtx(mp,
 					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
 		break;
+	case CT_RSUMBLOCK:
+		v = rt_daddr_to_rsumblock(mp, v);
+		break;
+	case CT_RSUMLOG:
+		dbprintf(_("cannot convert to rsumlog\n"));
+		return 0;
+		break;
+	case CT_RSUMINFO:
+		v = rt_daddr_to_rsuminfo(mp, v);
+		break;
 	case CT_AGBLOCK:
 	case CT_AGINO:
 	case CT_AGNUMBER:
@@ -514,6 +642,15 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_RBMWORD:
 		val->rbmword = (unsigned int)v;
 		break;
+	case CT_RSUMBLOCK:
+		val->rsumblock = (xfs_fileoff_t)v;
+		break;
+	case CT_RSUMLOG:
+		rsumlog = (unsigned int)v;
+		break;
+	case CT_RSUMINFO:
+		rsuminfo = (unsigned int)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 7b7d2ac124107c..01e4ab83ca23ba 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1181,10 +1181,39 @@ .SH COMMANDS
 or
 .B rbmw
 (32-bit word within a realtime bitmap block)
+.HP
+.B rsumblock
+or
+.B rsmb
+(realtime summary file block)
+.HP
+.B rsuminfo
+or
+.B rsmi
+(32-bit counter within a realtime summary block)
+.HP
+.B rsumlog
+or
+.B rsml
+(log2len parameter used for summary file offset computations)
 .PD
 .RE
 .IP
 Only conversions that "make sense" are allowed.
+
+Realtime summary file location conversions have the following rules:
+Each info word in the rt summary file counts the number of free extents of a
+given log2(length) that start in a given rt bitmap block.
+
+To compute summary file location information for a given rt bitmap block, a
+log2(extent length) must be specified as the last type/number pair before the
+conversion type, and the type must be
+.BR rsumlog .
+
+To compute the rt bitmap block from summary file location, the type/number pairs
+must be specified exactly in the order
+.BR rsumlog ", " rsuminfo ", " rsumblock .
+
 .TP
 .BI "sb [" agno ]
 Set current address to SB header in allocation group


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

* [PATCH 1/1] xfs_db: allow setting current address to log blocks
  2024-10-25  6:31 ` [PATCHSET v2.6 3/5] xfs_metadump: support external devices Darrick J. Wong
@ 2024-10-25  6:36   ` Darrick J. Wong
  2024-10-28  8:43     ` Christoph Hellwig
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:36 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Add commands so that users can target blocks on an external log device.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 db/block.c        |  103 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 man/man8/xfs_db.8 |   17 +++++++++
 2 files changed, 119 insertions(+), 1 deletion(-)


diff --git a/db/block.c b/db/block.c
index 000f9c1ed10fcd..e153d82287600f 100644
--- a/db/block.c
+++ b/db/block.c
@@ -29,6 +29,8 @@ static int	rtblock_f(int argc, char **argv);
 static void	rtblock_help(void);
 static int	rtextent_f(int argc, char **argv);
 static void	rtextent_help(void);
+static int	logblock_f(int argc, char **argv);
+static void	logblock_help(void);
 static void	print_rawdata(void *data, int len);
 
 static const cmdinfo_t	ablock_cmd =
@@ -49,6 +51,9 @@ static const cmdinfo_t	rtblock_cmd =
 static const cmdinfo_t	rtextent_cmd =
 	{ "rtextent", "rtx", rtextent_f, 0, 1, 1, N_("[rtxno]"),
 	  N_("set address to rtextent value"), rtextent_help };
+static const cmdinfo_t	logblock_cmd =
+	{ "logblock", "lsb", logblock_f, 0, 1, 1, N_("[logbno]"),
+	  N_("set address to logblock value"), logblock_help };
 
 static void
 ablock_help(void)
@@ -116,6 +121,7 @@ block_init(void)
 	add_command(&fsblock_cmd);
 	add_command(&rtblock_cmd);
 	add_command(&rtextent_cmd);
+	add_command(&logblock_cmd);
 }
 
 static void
@@ -132,6 +138,7 @@ daddr_help(void)
 enum daddr_target {
 	DT_DATA,
 	DT_RT,
+	DT_LOG,
 };
 
 static int
@@ -146,18 +153,27 @@ daddr_f(
 	int		c;
 	enum daddr_target tgt = DT_DATA;
 
-	while ((c = getopt(argc, argv, "r")) != -1) {
+	while ((c = getopt(argc, argv, "rl")) != -1) {
 		switch (c) {
 		case 'r':
 			tgt = DT_RT;
 			max_daddrs = mp->m_sb.sb_rblocks;
 			break;
+		case 'l':
+			tgt = DT_LOG;
+			max_daddrs = mp->m_sb.sb_logblocks;
+			break;
 		default:
 			daddr_help();
 			return 0;
 		}
 	}
 
+	if (tgt == DT_LOG && mp->m_sb.sb_logstart > 0) {
+		dbprintf(_("filesystem has internal log\n"));
+		return 0;
+	}
+
 	if (optind == argc) {
 		xfs_daddr_t	daddr = iocur_top->off >> BBSHIFT;
 
@@ -192,6 +208,9 @@ daddr_f(
 	case DT_RT:
 		set_rt_cur(&typtab[TYP_DATA], d, bb_count, DB_RING_ADD, NULL);
 		break;
+	case DT_LOG:
+		set_log_cur(&typtab[TYP_DATA], d, bb_count, DB_RING_ADD, NULL);
+		break;
 	}
 	return 0;
 }
@@ -407,6 +426,88 @@ rtextent_f(
 	return 0;
 }
 
+static void
+logblock_help(void)
+{
+	dbprintf(_(
+"\n Example:\n"
+"\n"
+" 'logblock 1023' - sets the file position to the 1023rd log block.\n"
+" The external log device or the block offset within the internal log will be\n"
+" chosen as appropriate.\n"
+));
+}
+
+static int
+logblock_f(
+	int		argc,
+	char		**argv)
+{
+	xfs_fsblock_t	logblock;
+	char		*p;
+
+	if (argc == 1) {
+		if (mp->m_sb.sb_logstart > 0 && iocur_is_ddev(iocur_top)) {
+			logblock = XFS_DADDR_TO_FSB(mp,
+						iocur_top->off >> BBSHIFT);
+
+			if (logblock < mp->m_sb.sb_logstart ||
+			    logblock >= mp->m_sb.sb_logstart +
+					mp->m_sb.sb_logblocks) {
+				dbprintf(
+ _("current address not within internal log\n"));
+				return 0;
+			}
+
+			dbprintf(_("current logblock is %lld\n"),
+					logblock - mp->m_sb.sb_logstart);
+			return 0;
+		}
+
+		if (mp->m_sb.sb_logstart == 0 &&
+		    iocur_is_extlogdev(iocur_top)) {
+			logblock = XFS_BB_TO_FSB(mp,
+						iocur_top->off >> BBSHIFT);
+
+			if (logblock >= mp->m_sb.sb_logblocks) {
+				dbprintf(
+ _("current address not within external log\n"));
+				return 0;
+			}
+
+			dbprintf(_("current logblock is %lld\n"), logblock);
+			return 0;
+		}
+
+		dbprintf(_("current address does not point to log\n"));
+		return 0;
+	}
+
+	logblock = strtoull(argv[1], &p, 0);
+	if (*p != '\0') {
+		dbprintf(_("bad logblock %s\n"), argv[1]);
+		return 0;
+	}
+
+	if (logblock >= mp->m_sb.sb_logblocks) {
+		dbprintf(_("bad logblock %s\n"), argv[1]);
+		return 0;
+	}
+
+	ASSERT(typtab[TYP_DATA].typnm == TYP_DATA);
+
+	if (mp->m_sb.sb_logstart) {
+		logblock += mp->m_sb.sb_logstart;
+		set_cur(&typtab[TYP_DATA], XFS_FSB_TO_DADDR(mp, logblock),
+				blkbb, DB_RING_ADD, NULL);
+	} else {
+		set_log_cur(&typtab[TYP_DATA], XFS_FSB_TO_BB(mp, logblock),
+				blkbb, DB_RING_ADD, NULL);
+	}
+
+	return 0;
+}
+
 void
 print_block(
 	const field_t	*fields,
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 01e4ab83ca23ba..c2f06191cfd29d 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -681,6 +681,9 @@ .SH COMMANDS
 .B data
 (uninterpreted).
 
+If an address and the
+.B \-l
+option are specified, the current address is set to the external log device.
 If an address and the
 .B \-r
 option are specified, the current address is set to the realtime device.
@@ -1009,6 +1012,20 @@ .SH COMMANDS
 .IR filename ,
 stop logging, or print the current logging status.
 .TP
+.BI "logblock [" logbno ]
+Set current address to the log block value given by
+.IR logbno .
+If no value for
+.I logbno
+is given the current address is printed, expressed as an fsb.
+The type is set to
+.B data
+(uninterpreted).
+If the filesystem has an external log, then the address will be within the log
+device.
+If the filesystem has an internal log, then the address will be within the
+internal log.
+.TP
 .BI "logformat [\-c " cycle "] [\-s " sunit "]"
 Reformats the log to the specified log cycle and log stripe unit.
 This has the effect of clearing the log destructively.


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

* [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
@ 2024-10-25  6:36   ` Darrick J. Wong
  2024-10-28  8:43     ` Christoph Hellwig
  2024-10-25  6:37   ` [PATCH 2/6] xfs_repair: use xfs_validate_rt_geometry Darrick J. Wong
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:36 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Back in the really old days, xfs_repair would generate the new free
space information for the realtime section during phase 5, and write the
contents to the rtbitmap and summary files during phase 6.  This was ok
because the incore information isn't used until phase 6.

Then I changed the behavior to check the generated information against
what was on disk and complain about the discrepancies.  Unfortunately,
there was a subtle flaw here -- for a non -n run, we'll have regenerated
the AG metadata before we actually check the rt free space information.
If the AG btree regeneration should clobber one of the old rtbitmap or
summary blocks, this will be reported as a corruption even though
nothing's wrong.

Move check_rtmetadata to the end of phase 4 so that this doesn't happen.

Cc: <linux-xfs@vger.kernel.org> # v5.19.0
Fixes: f2e388616d7491 ("xfs_repair: check free rt extent count")
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 repair/phase4.c     |    7 +++++++
 repair/phase5.c     |    6 ------
 repair/xfs_repair.c |    3 ---
 3 files changed, 7 insertions(+), 9 deletions(-)


diff --git a/repair/phase4.c b/repair/phase4.c
index 5e5d8c3c7d9b96..071f20ed736e4b 100644
--- a/repair/phase4.c
+++ b/repair/phase4.c
@@ -401,4 +401,11 @@ phase4(xfs_mount_t *mp)
 	 */
 	quotino_check(mp);
 	quota_sb_check(mp);
+
+	/* Check the rt metadata before we rebuild */
+	if (mp->m_sb.sb_rblocks)  {
+		do_log(
+		_("        - generate realtime summary info and bitmap...\n"));
+		check_rtmetadata(mp);
+	}
 }
diff --git a/repair/phase5.c b/repair/phase5.c
index d18ec095b0524b..9207da7172c05b 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -694,12 +694,6 @@ phase5(xfs_mount_t *mp)
 	free(sb_ifree_ag);
 	free(sb_fdblocks_ag);
 
-	if (mp->m_sb.sb_rblocks)  {
-		do_log(
-		_("        - generate realtime summary info and bitmap...\n"));
-		check_rtmetadata(mp);
-	}
-
 	do_log(_("        - reset superblock...\n"));
 
 	/*
diff --git a/repair/xfs_repair.c b/repair/xfs_repair.c
index e325d61f10367e..3ade85bbcbb7fd 100644
--- a/repair/xfs_repair.c
+++ b/repair/xfs_repair.c
@@ -1318,9 +1318,6 @@ main(int argc, char **argv)
 
 	if (no_modify) {
 		printf(_("No modify flag set, skipping phase 5\n"));
-
-		if (mp->m_sb.sb_rblocks > 0)
-			check_rtmetadata(mp);
 	} else {
 		phase5(mp);
 	}


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

* [PATCH 2/6] xfs_repair: use xfs_validate_rt_geometry
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
  2024-10-25  6:36   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
@ 2024-10-25  6:37   ` Darrick J. Wong
  2024-10-25  6:37   ` [PATCH 3/6] mkfs: remove a pointless rtfreesp_init forward declaration Darrick J. Wong
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:37 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Christoph Hellwig <hch@lst.de>

Use shared libxfs code with the kernel instead of reimplementing it.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libxfs/libxfs_api_defs.h |    1 +
 repair/sb.c              |   40 ++--------------------------------------
 2 files changed, 3 insertions(+), 38 deletions(-)


diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index a4173e5f7a595c..7c08d766623c0c 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -309,6 +309,7 @@
 
 #define xfs_update_secondary_sbs	libxfs_update_secondary_sbs
 
+#define xfs_validate_rt_geometry	libxfs_validate_rt_geometry
 #define xfs_validate_stripe_geometry	libxfs_validate_stripe_geometry
 #define xfs_verify_agbno		libxfs_verify_agbno
 #define xfs_verify_agbext		libxfs_verify_agbext
diff --git a/repair/sb.c b/repair/sb.c
index 4b49c1b33c6c83..1320929caee590 100644
--- a/repair/sb.c
+++ b/repair/sb.c
@@ -447,44 +447,8 @@ verify_sb(char *sb_buf, xfs_sb_t *sb, int is_primary_sb)
 			return(XR_BAD_SECT_SIZE_DATA);
 	}
 
-	/*
-	 * real-time extent size is always set
-	 */
-	if (sb->sb_rextsize * sb->sb_blocksize > XFS_MAX_RTEXTSIZE)
-		return(XR_BAD_RT_GEO_DATA);
-
-	if (sb->sb_rextsize * sb->sb_blocksize < XFS_MIN_RTEXTSIZE)
-			return(XR_BAD_RT_GEO_DATA);
-
-	if (sb->sb_rblocks == 0)  {
-		if (sb->sb_rextents != 0)
-			return(XR_BAD_RT_GEO_DATA);
-
-		if (sb->sb_rbmblocks != 0)
-			return(XR_BAD_RT_GEO_DATA);
-
-		if (sb->sb_rextslog != 0)
-			return(XR_BAD_RT_GEO_DATA);
-
-		if (sb->sb_frextents != 0)
-			return(XR_BAD_RT_GEO_DATA);
-	} else  {
-		/*
-		 * if we have a real-time partition, sanity-check geometry
-		 */
-		if (sb->sb_rblocks / sb->sb_rextsize != sb->sb_rextents)
-			return(XR_BAD_RT_GEO_DATA);
-
-		if (sb->sb_rextents == 0)
-			return XR_BAD_RT_GEO_DATA;
-
-		if (sb->sb_rextslog != libxfs_compute_rextslog(sb->sb_rextents))
-			return(XR_BAD_RT_GEO_DATA);
-
-		if (sb->sb_rbmblocks != (xfs_extlen_t) howmany(sb->sb_rextents,
-						NBBY * sb->sb_blocksize))
-			return(XR_BAD_RT_GEO_DATA);
-	}
+	if (!libxfs_validate_rt_geometry(sb))
+		return XR_BAD_RT_GEO_DATA;
 
 	/*
 	 * verify correctness of inode alignment if it's there


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

* [PATCH 3/6] mkfs: remove a pointless rtfreesp_init forward declaration
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
  2024-10-25  6:36   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
  2024-10-25  6:37   ` [PATCH 2/6] xfs_repair: use xfs_validate_rt_geometry Darrick J. Wong
@ 2024-10-25  6:37   ` Darrick J. Wong
  2024-10-25  6:37   ` [PATCH 4/6] mkfs: use xfs_rtfile_initialize_blocks Darrick J. Wong
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:37 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Christoph Hellwig <hch@lst.de>

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 mkfs/proto.c |    1 -
 1 file changed, 1 deletion(-)


diff --git a/mkfs/proto.c b/mkfs/proto.c
index 06010980c5b313..9d21f027c0b174 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -18,7 +18,6 @@ static struct xfs_trans * getres(struct xfs_mount *mp, uint blocks);
 static void rsvfile(xfs_mount_t *mp, xfs_inode_t *ip, long long len);
 static char *newregfile(char **pp, int *len);
 static void rtinit(xfs_mount_t *mp);
-static void rtfreesp_init(struct xfs_mount *mp);
 static long filesize(int fd);
 static int slashes_are_spaces;
 


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

* [PATCH 4/6] mkfs: use xfs_rtfile_initialize_blocks
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
                     ` (2 preceding siblings ...)
  2024-10-25  6:37   ` [PATCH 3/6] mkfs: remove a pointless rtfreesp_init forward declaration Darrick J. Wong
@ 2024-10-25  6:37   ` Darrick J. Wong
  2024-10-25  6:37   ` [PATCH 5/6] xfs_repair: use libxfs_rtfile_initialize_blocks Darrick J. Wong
  2024-10-25  6:38   ` [PATCH 6/6] xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino Darrick J. Wong
  5 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:37 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Christoph Hellwig <hch@lst.de>

Use the new libxfs helper for initializing the rtbitmap/summary files
for rtgroup-enabled file systems.  Also skip the zeroing of the blocks
for rtgroup file systems as we'll overwrite every block instantly.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libxfs/libxfs_api_defs.h |    1 
 mkfs/proto.c             |  106 +++++++---------------------------------------
 2 files changed, 17 insertions(+), 90 deletions(-)


diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index 7c08d766623c0c..c5682504e41a66 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -263,6 +263,7 @@
 #define xfs_suminfo_add			libxfs_suminfo_add
 #define xfs_suminfo_get			libxfs_suminfo_get
 #define xfs_rtsummary_wordcount		libxfs_rtsummary_wordcount
+#define xfs_rtfile_initialize_blocks	libxfs_rtfile_initialize_blocks
 
 #define xfs_rtfree_extent		libxfs_rtfree_extent
 #define xfs_rtfree_blocks		libxfs_rtfree_blocks
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 9d21f027c0b174..d8eb6ca33672bd 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -819,94 +819,6 @@ rtsummary_create(
 	ihold(VFS_I(ip));
 }
 
-/* Zero the realtime bitmap. */
-static void
-rtbitmap_init(
-	struct xfs_mount	*mp)
-{
-	struct xfs_bmbt_irec	map[XFS_BMAP_MAX_NMAP];
-	struct xfs_trans	*tp;
-	struct xfs_bmbt_irec	*ep;
-	xfs_fileoff_t		bno;
-	uint			blocks;
-	int			i;
-	int			nmap;
-	int			error;
-
-	blocks = mp->m_sb.sb_rbmblocks +
-			XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
-	error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
-	if (error)
-		res_failed(error);
-
-	libxfs_trans_ijoin(tp, mp->m_rbmip, 0);
-	bno = 0;
-	while (bno < mp->m_sb.sb_rbmblocks) {
-		nmap = XFS_BMAP_MAX_NMAP;
-		error = -libxfs_bmapi_write(tp, mp->m_rbmip, bno,
-				(xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno),
-				0, mp->m_sb.sb_rbmblocks, map, &nmap);
-		if (error)
-			fail(_("Allocation of the realtime bitmap failed"),
-				error);
-
-		for (i = 0, ep = map; i < nmap; i++, ep++) {
-			libxfs_device_zero(mp->m_ddev_targp,
-				XFS_FSB_TO_DADDR(mp, ep->br_startblock),
-				XFS_FSB_TO_BB(mp, ep->br_blockcount));
-			bno += ep->br_blockcount;
-		}
-	}
-
-	error = -libxfs_trans_commit(tp);
-	if (error)
-		fail(_("Block allocation of the realtime bitmap inode failed"),
-				error);
-}
-
-/* Zero the realtime summary file. */
-static void
-rtsummary_init(
-	struct xfs_mount	*mp)
-{
-	struct xfs_bmbt_irec	map[XFS_BMAP_MAX_NMAP];
-	struct xfs_trans	*tp;
-	struct xfs_bmbt_irec	*ep;
-	xfs_fileoff_t		bno;
-	uint			blocks;
-	int			i;
-	int			nmap;
-	int			error;
-
-	blocks = mp->m_rsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
-	error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
-	if (error)
-		res_failed(error);
-	libxfs_trans_ijoin(tp, mp->m_rsumip, 0);
-
-	bno = 0;
-	while (bno < mp->m_rsumblocks) {
-		nmap = XFS_BMAP_MAX_NMAP;
-		error = -libxfs_bmapi_write(tp, mp->m_rsumip, bno,
-				(xfs_extlen_t)(mp->m_rsumblocks - bno),
-				0, mp->m_rsumblocks, map, &nmap);
-		if (error)
-			fail(_("Allocation of the realtime summary failed"),
-				error);
-
-		for (i = 0, ep = map; i < nmap; i++, ep++) {
-			libxfs_device_zero(mp->m_ddev_targp,
-				XFS_FSB_TO_DADDR(mp, ep->br_startblock),
-				XFS_FSB_TO_BB(mp, ep->br_blockcount));
-			bno += ep->br_blockcount;
-		}
-	}
-	error = -libxfs_trans_commit(tp);
-	if (error)
-		fail(_("Block allocation of the realtime summary inode failed"),
-				error);
-}
-
 /*
  * Free the whole realtime area using transactions.
  * Do one transaction per bitmap block.
@@ -920,6 +832,22 @@ rtfreesp_init(
 	xfs_rtxnum_t		ertx;
 	int			error;
 
+	/*
+	 * First zero the realtime bitmap and summary files.
+	 */
+	error = -libxfs_rtfile_initialize_blocks(mp->m_rbmip, 0,
+			mp->m_sb.sb_rbmblocks, NULL);
+	if (error)
+		fail(_("Initialization of rtbitmap inode failed"), error);
+
+	error = -libxfs_rtfile_initialize_blocks(mp->m_rsumip, 0,
+			mp->m_rsumblocks, NULL);
+	if (error)
+		fail(_("Initialization of rtsummary inode failed"), error);
+
+	/*
+	 * Then free the blocks into the allocator, one bitmap block at a time.
+	 */
 	for (rtx = 0; rtx < mp->m_sb.sb_rextents; rtx = ertx) {
 		error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate,
 				0, 0, 0, &tp);
@@ -953,8 +881,6 @@ rtinit(
 	create_sb_metadata_file(mp, rtbitmap_create);
 	create_sb_metadata_file(mp, rtsummary_create);
 
-	rtbitmap_init(mp);
-	rtsummary_init(mp);
 	rtfreesp_init(mp);
 }
 


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

* [PATCH 5/6] xfs_repair: use libxfs_rtfile_initialize_blocks
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
                     ` (3 preceding siblings ...)
  2024-10-25  6:37   ` [PATCH 4/6] mkfs: use xfs_rtfile_initialize_blocks Darrick J. Wong
@ 2024-10-25  6:37   ` Darrick J. Wong
  2024-10-25  6:38   ` [PATCH 6/6] xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino Darrick J. Wong
  5 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:37 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Christoph Hellwig <hch@lst.de>

Use libxfs_rtfile_initialize_blocks to write the re-computed rtbitmap
and rtsummary contents.  This removes duplicate code and prepares for
even more sharing once the rtgroup features adds a metadata header to
the rtbitmap and rtsummary blocks.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 repair/phase6.c |  168 ++++++++++---------------------------------------------
 1 file changed, 32 insertions(+), 136 deletions(-)


diff --git a/repair/phase6.c b/repair/phase6.c
index c96b50cf6a69dd..310a2b9c07bff0 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -547,157 +547,60 @@ mk_rbmino(xfs_mount_t *mp)
 	libxfs_irele(ip);
 }
 
-static int
-fill_rbmino(xfs_mount_t *mp)
+static void
+fill_rbmino(
+	struct xfs_mount	*mp)
 {
-	struct xfs_buf	*bp;
-	xfs_trans_t	*tp;
-	xfs_inode_t	*ip;
-	union xfs_rtword_raw	*bmp;
-	int		nmap;
-	int		error;
-	xfs_fileoff_t	bno;
-	xfs_bmbt_irec_t	map;
-
-	bmp = btmcompute;
-	bno = 0;
+	struct xfs_trans	*tp;
+	struct xfs_inode	*ip;
+	int			error;
 
 	error = -libxfs_trans_alloc_rollable(mp, 10, &tp);
 	if (error)
 		res_failed(error);
 
 	error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip);
-	if (error) {
+	libxfs_trans_cancel(tp);
+	if (error)
 		do_error(
-		_("couldn't iget realtime bitmap inode -- error - %d\n"),
-			error);
-	}
-
-	while (bno < mp->m_sb.sb_rbmblocks)  {
-		struct xfs_rtalloc_args	args = {
-			.mp		= mp,
-			.tp		= tp,
-		};
-		union xfs_rtword_raw	*ondisk;
-
-		/*
-		 * fill the file one block at a time
-		 */
-		nmap = 1;
-		error = -libxfs_bmapi_write(tp, ip, bno, 1, 0, 1, &map, &nmap);
-		if (error || nmap != 1) {
-			do_error(
-	_("couldn't map realtime bitmap block %" PRIu64 ", error = %d\n"),
-				bno, error);
-		}
-
-		ASSERT(map.br_startblock != HOLESTARTBLOCK);
-
-		error = -libxfs_trans_read_buf(
-				mp, tp, mp->m_dev,
-				XFS_FSB_TO_DADDR(mp, map.br_startblock),
-				XFS_FSB_TO_BB(mp, 1), 1, &bp, NULL);
-
-		if (error) {
-			do_warn(
-_("can't access block %" PRIu64 " (fsbno %" PRIu64 ") of realtime bitmap inode %" PRIu64 "\n"),
-				bno, map.br_startblock, mp->m_sb.sb_rbmino);
-			return(1);
-		}
+_("couldn't iget realtime bitmap inode, error %d\n"), error);
 
-		args.rbmbp = bp;
-		ondisk = xfs_rbmblock_wordptr(&args, 0);
-		memcpy(ondisk, bmp, mp->m_blockwsize << XFS_WORDLOG);
-
-		libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
-
-		bmp += mp->m_blockwsize;
-		bno++;
-	}
-
-	libxfs_trans_ijoin(tp, ip, 0);
-	error = -libxfs_trans_commit(tp);
+	error = -libxfs_rtfile_initialize_blocks(ip, 0, mp->m_sb.sb_rbmblocks,
+			btmcompute);
 	if (error)
-		do_error(_("%s: commit failed, error %d\n"), __func__, error);
+		do_error(
+_("couldn't re-initialize realtime bitmap inode, error %d\n"), error);
+
 	libxfs_irele(ip);
-	return(0);
 }
 
-static int
-fill_rsumino(xfs_mount_t *mp)
+static void
+fill_rsumino(
+	struct xfs_mount	*mp)
 {
-	struct xfs_buf	*bp;
-	xfs_trans_t	*tp;
-	xfs_inode_t	*ip;
-	union xfs_suminfo_raw *smp;
-	int		nmap;
-	int		error;
-	xfs_fileoff_t	bno;
-	xfs_bmbt_irec_t	map;
-
-	smp = sumcompute;
-	bno = 0;
+	struct xfs_trans	*tp;
+	struct xfs_inode	*ip;
+	int			error;
 
 	error = -libxfs_trans_alloc_rollable(mp, 10, &tp);
 	if (error)
 		res_failed(error);
 
 	error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip);
-	if (error) {
+	libxfs_trans_cancel(tp);
+	if (error)
 		do_error(
-		_("couldn't iget realtime summary inode -- error - %d\n"),
-			error);
-	}
-
-	while (bno < mp->m_rsumblocks)  {
-		struct xfs_rtalloc_args	args = {
-			.mp		= mp,
-			.tp		= tp,
-		};
-		union xfs_suminfo_raw	*ondisk;
-
-		/*
-		 * fill the file one block at a time
-		 */
-		nmap = 1;
-		error = -libxfs_bmapi_write(tp, ip, bno, 1, 0, 1, &map, &nmap);
-		if (error || nmap != 1) {
-			do_error(
-	_("couldn't map realtime summary inode block %" PRIu64 ", error = %d\n"),
-				bno, error);
-		}
-
-		ASSERT(map.br_startblock != HOLESTARTBLOCK);
-
-		error = -libxfs_trans_read_buf(
-				mp, tp, mp->m_dev,
-				XFS_FSB_TO_DADDR(mp, map.br_startblock),
-				XFS_FSB_TO_BB(mp, 1), 1, &bp, NULL);
-
-		if (error) {
-			do_warn(
-_("can't access block %" PRIu64 " (fsbno %" PRIu64 ") of realtime summary inode %" PRIu64 "\n"),
-				bno, map.br_startblock, mp->m_sb.sb_rsumino);
-			libxfs_irele(ip);
-			return(1);
-		}
+_("couldn't iget realtime summary inode, error %d\n"), error);
 
-		args.sumbp = bp;
-		ondisk = xfs_rsumblock_infoptr(&args, 0);
-		memcpy(ondisk, smp, mp->m_blockwsize << XFS_WORDLOG);
-
-		libxfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
-
-		smp += mp->m_blockwsize;
-		bno++;
-	}
-
-	libxfs_trans_ijoin(tp, ip, 0);
-	error = -libxfs_trans_commit(tp);
+	mp->m_rsumip = ip;
+	error = -libxfs_rtfile_initialize_blocks(ip, 0, mp->m_rsumblocks,
+			sumcompute);
+	mp->m_rsumip = NULL;
 	if (error)
-		do_error(_("%s: commit failed, error %d\n"), __func__, error);
+		do_error(
+_("couldn't re-initialize realtime summary inode, error %d\n"), error);
+
 	libxfs_irele(ip);
-	return(0);
 }
 
 static void
@@ -3302,15 +3205,8 @@ phase6(xfs_mount_t *mp)
 	if (!no_modify)  {
 		do_log(
 _("        - resetting contents of realtime bitmap and summary inodes\n"));
-		if (fill_rbmino(mp))  {
-			do_warn(
-			_("Warning:  realtime bitmap may be inconsistent\n"));
-		}
-
-		if (fill_rsumino(mp))  {
-			do_warn(
-			_("Warning:  realtime bitmap may be inconsistent\n"));
-		}
+		fill_rbmino(mp);
+		fill_rsumino(mp);
 	}
 
 	mark_standalone_inodes(mp);


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

* [PATCH 6/6] xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino
  2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-25  6:37   ` [PATCH 5/6] xfs_repair: use libxfs_rtfile_initialize_blocks Darrick J. Wong
@ 2024-10-25  6:38   ` Darrick J. Wong
  5 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:38 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, hch

From: Christoph Hellwig <hch@lst.de>

Now that repair is using libxfs_rtfile_initialize_blocks to write to the
rtbitmap and rtsummary inodes, space allocation is already taken care of
that helper and there is no need to preallocate it.  Remove the code to
do so.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 repair/phase6.c |  116 +++++++------------------------------------------------
 1 file changed, 14 insertions(+), 102 deletions(-)


diff --git a/repair/phase6.c b/repair/phase6.c
index 310a2b9c07bff0..630617ef8ab8fe 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -475,24 +475,16 @@ reset_sbroot_ino(
 }
 
 static void
-mk_rbmino(xfs_mount_t *mp)
+mk_rbmino(
+	struct xfs_mount	*mp)
 {
-	xfs_trans_t	*tp;
-	xfs_inode_t	*ip;
-	xfs_bmbt_irec_t	*ep;
-	int		i;
-	int		nmap;
-	int		error;
-	xfs_fileoff_t	bno;
-	xfs_bmbt_irec_t	map[XFS_BMAP_MAX_NMAP];
-	uint		blocks;
+	struct xfs_trans	*tp;
+	struct xfs_inode	*ip;
+	int			error;
 
-	/*
-	 * first set up inode
-	 */
-	i = -libxfs_trans_alloc_rollable(mp, 10, &tp);
-	if (i)
-		res_failed(i);
+	error = -libxfs_trans_alloc_rollable(mp, 10, &tp);
+	if (error)
+		res_failed(error);
 
 	error = -libxfs_iget(mp, tp, mp->m_sb.sb_rbmino, 0, &ip);
 	if (error) {
@@ -508,42 +500,6 @@ mk_rbmino(xfs_mount_t *mp)
 	error = -libxfs_trans_commit(tp);
 	if (error)
 		do_error(_("%s: commit failed, error %d\n"), __func__, error);
-
-	/*
-	 * then allocate blocks for file and fill with zeroes (stolen
-	 * from mkfs)
-	 */
-	blocks = mp->m_sb.sb_rbmblocks +
-			XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
-	error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
-	if (error)
-		res_failed(error);
-
-	libxfs_trans_ijoin(tp, ip, 0);
-	bno = 0;
-	while (bno < mp->m_sb.sb_rbmblocks) {
-		nmap = XFS_BMAP_MAX_NMAP;
-		error = -libxfs_bmapi_write(tp, ip, bno,
-			  (xfs_extlen_t)(mp->m_sb.sb_rbmblocks - bno),
-			  0, mp->m_sb.sb_rbmblocks, map, &nmap);
-		if (error) {
-			do_error(
-			_("couldn't allocate realtime bitmap, error = %d\n"),
-				error);
-		}
-		for (i = 0, ep = map; i < nmap; i++, ep++) {
-			libxfs_device_zero(mp->m_ddev_targp,
-				XFS_FSB_TO_DADDR(mp, ep->br_startblock),
-				XFS_FSB_TO_BB(mp, ep->br_blockcount));
-			bno += ep->br_blockcount;
-		}
-	}
-	error = -libxfs_trans_commit(tp);
-	if (error) {
-		do_error(
-		_("allocation of the realtime bitmap failed, error = %d\n"),
-			error);
-	}
 	libxfs_irele(ip);
 }
 
@@ -606,22 +562,13 @@ _("couldn't re-initialize realtime summary inode, error %d\n"), error);
 static void
 mk_rsumino(xfs_mount_t *mp)
 {
-	xfs_trans_t	*tp;
-	xfs_inode_t	*ip;
-	xfs_bmbt_irec_t	*ep;
-	int		i;
-	int		nmap;
-	int		error;
-	xfs_fileoff_t	bno;
-	xfs_bmbt_irec_t	map[XFS_BMAP_MAX_NMAP];
-	uint		blocks;
+	struct xfs_trans	*tp;
+	struct xfs_inode	*ip;
+	int			error;
 
-	/*
-	 * first set up inode
-	 */
-	i = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp);
-	if (i)
-		res_failed(i);
+	error = -libxfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 10, 0, 0, &tp);
+	if (error)
+		res_failed(error);
 
 	error = -libxfs_iget(mp, tp, mp->m_sb.sb_rsumino, 0, &ip);
 	if (error) {
@@ -637,41 +584,6 @@ mk_rsumino(xfs_mount_t *mp)
 	error = -libxfs_trans_commit(tp);
 	if (error)
 		do_error(_("%s: commit failed, error %d\n"), __func__, error);
-
-	/*
-	 * then allocate blocks for file and fill with zeroes (stolen
-	 * from mkfs)
-	 */
-	blocks = mp->m_rsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
-	error = -libxfs_trans_alloc_rollable(mp, blocks, &tp);
-	if (error)
-		res_failed(error);
-
-	libxfs_trans_ijoin(tp, ip, 0);
-	bno = 0;
-	while (bno < mp->m_rsumblocks) {
-		nmap = XFS_BMAP_MAX_NMAP;
-		error = -libxfs_bmapi_write(tp, ip, bno,
-			  (xfs_extlen_t)(mp->m_rsumblocks - bno),
-			  0, mp->m_rsumblocks, map, &nmap);
-		if (error) {
-			do_error(
-		_("couldn't allocate realtime summary inode, error = %d\n"),
-				error);
-		}
-		for (i = 0, ep = map; i < nmap; i++, ep++) {
-			libxfs_device_zero(mp->m_ddev_targp,
-				      XFS_FSB_TO_DADDR(mp, ep->br_startblock),
-				      XFS_FSB_TO_BB(mp, ep->br_blockcount));
-			bno += ep->br_blockcount;
-		}
-	}
-	error = -libxfs_trans_commit(tp);
-	if (error) {
-		do_error(
-	_("allocation of the realtime summary ino failed, error = %d\n"),
-			error);
-	}
 	libxfs_irele(ip);
 }
 


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

* [PATCH 1/1] xfs_scrub_all: wait for services to start activating
  2024-10-25  6:32 ` [PATCHSET v31.2 5/5] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
@ 2024-10-25  6:38   ` Darrick J. Wong
  2024-10-28  8:44     ` Christoph Hellwig
  0 siblings, 1 reply; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-25  6:38 UTC (permalink / raw)
  To: cem, aalbersh, djwong; +Cc: linux-xfs, linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

It seems that the function call to start a systemd unit completes
asynchronously from any change in that unit's active state.  On a
lightly loaded system, a Start() call followed by an ActiveState()
call actually sees the change in state from inactive to activating.

Unfortunately, on a heavily loaded system, the state change may take a
few seconds.  If this is the case, the wait() call can see that the unit
state is "inactive", decide that the service already finished, and exit
early, when in reality it hasn't even gotten to 'activating'.

Fix this by adding a second method that watches either for the inactive
-> activating state transition or for the last exit from inactivation
timestamp to change before waiting for the unit to reach inactive state.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Cc: <linux-xfs@vger.kernel.org> # v6.10.0
Fixes: 6d831e770359ff ("xfs_scrub_all: convert systemctl calls to dbus")
---
 scrub/xfs_scrub_all.in |   52 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)


diff --git a/scrub/xfs_scrub_all.in b/scrub/xfs_scrub_all.in
index 5e2e0446a99f89..fe4bca4b2edb11 100644
--- a/scrub/xfs_scrub_all.in
+++ b/scrub/xfs_scrub_all.in
@@ -249,6 +249,54 @@ class scrub_service(scrub_control):
 				print(e, file = sys.stderr)
 			return 'failed'
 
+	def last_activation(self):
+		'''Retrieve the last activation time, in microseconds since
+		boot.'''
+		global debug
+
+		l = lambda: self.prop.Get('org.freedesktop.systemd1.Unit',
+				'InactiveExitTimestampMonotonic')
+		try:
+			return self.__dbusrun(l)
+		except Exception as e:
+			if debug:
+				print(e, file = sys.stderr)
+			return 0
+
+	def wait_for_startup(self, last_active, wait_for = 30, interval = 0.5):
+		'''Wait for the service to start up.  This is defined as
+		exiting the inactive state.'''
+
+		for i in range(0, int(wait_for / interval)):
+			s = self.state()
+			if debug:
+				print('waiting for activation %s %s' % (self.unitname, s))
+			if s == 'failed':
+				return 1
+			if s != 'inactive':
+				return 0
+			# If the unit is inactive but the last activation time
+			# doesn't match, then the service ran so quickly that
+			# it's already gone.
+			if last_active != self.last_activation():
+				return 0
+			time.sleep(interval)
+
+		s = self.state()
+		if debug:
+			print('waited for startup %s %s' % (self.unitname, s))
+		if s == 'failed':
+			return 1
+		if s != 'inactive':
+			return 0
+
+		# If the unit is inactive but the last activation time doesn't
+		# match, then the service ran so quickly that it's already
+		# gone.
+		if last_active != self.last_activation():
+			return 0
+		return 2
+
 	def wait(self, interval = 1):
 		'''Wait until the service finishes.'''
 		global debug
@@ -278,7 +326,11 @@ class scrub_service(scrub_control):
 			print('starting %s' % self.unitname)
 
 		try:
+			last_active = self.last_activation()
 			self.__dbusrun(lambda: self.unit.Start('replace'))
+			ret = self.wait_for_startup(last_active)
+			if ret > 0:
+				return ret
 			return self.wait()
 		except dbus.exceptions.DBusException as e:
 			# If the unit was masked, the sysadmin doesn't want us


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

* Re: [PATCH 1/7] man: document file range commit ioctls
  2024-10-25  6:32   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
@ 2024-10-28  8:31     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:31 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs, hch

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 2/7] libfrog: add support for commit range ioctl family
  2024-10-25  6:32   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
@ 2024-10-28  8:32     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs, hch

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 3/7] libxfs: remove unused xfs_inode fields
  2024-10-25  6:33   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
@ 2024-10-28  8:32     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs, hch

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 4/7] libxfs: validate inumber in xfs_iget
  2024-10-25  6:33   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
@ 2024-10-28  8:32     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 5/7] xfs_fsr: port to new file exchange library function
  2024-10-25  6:33   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
@ 2024-10-28  8:33     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:33 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command
  2024-10-25  6:34   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
@ 2024-10-28  8:33     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:33 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range
  2024-10-25  6:34   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
@ 2024-10-28  8:33     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:33 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 1/8] xfs_db: support passing the realtime device to the debugger
  2024-10-25  6:34   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
@ 2024-10-28  8:34     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:34 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

> --- a/db/io.h
> +++ b/db/io.h
> @@ -51,6 +51,8 @@ extern void	set_cur(const struct typ *type, xfs_daddr_t blknum,
>  			int len, int ring_add, bbmap_t *bbmap);
>  extern void	set_log_cur(const struct typ *type, xfs_daddr_t blknum,
>  			int len, int ring_add, bbmap_t *bbmap);
> +extern int	set_rt_cur(const struct typ *type, xfs_daddr_t blknum,
> +			int len, int ring_add, bbmap_t *bbmap);

Nit: No need for the extern here.

Otherwise looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor
  2024-10-25  6:34   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
@ 2024-10-28  8:34     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:34 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs, hch

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 3/8] xfs_db: make the daddr command target the realtime device
  2024-10-25  6:35   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
@ 2024-10-28  8:35     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:35 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 4/8] xfs_db: access realtime file blocks
  2024-10-25  6:35   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
@ 2024-10-28  8:37     ` Christoph Hellwig
  2024-10-28 17:50       ` Darrick J. Wong
  0 siblings, 1 reply; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:37 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

> +	if (is_rtfile(iocur_top->data))
> +		set_rt_cur(&typtab[type], (int64_t)dfsbno << mp->m_blkbb_log,

Shouldn't this be xfs_rtb_to_daddr?

> diff --git a/db/faddr.c b/db/faddr.c
> index ec4aae68bb5a81..fd65b86b5e915d 100644
> --- a/db/faddr.c
> +++ b/db/faddr.c
> @@ -323,7 +323,9 @@ fa_drtbno(
>  		dbprintf(_("null block number, cannot set new addr\n"));
>  		return;
>  	}
> -	/* need set_cur to understand rt subvolume */
> +
> +	set_rt_cur(&typtab[next], (int64_t)XFS_FSB_TO_BB(mp, bno), blkbb,
> +			DB_RING_ADD, NULL);

Same here?


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

* Re: [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents
  2024-10-25  6:35   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
@ 2024-10-28  8:38     ` Christoph Hellwig
  2024-10-28 17:51       ` Darrick J. Wong
  0 siblings, 1 reply; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:38 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

> +	ASSERT(typtab[TYP_DATA].typnm == TYP_DATA);
> +	set_rt_cur(&typtab[TYP_DATA], XFS_FSB_TO_BB(mp, rtbno), blkbb,
> +			DB_RING_ADD, NULL);

xfs_rtb_to_daddr?

> +		rtbno = XFS_BB_TO_FSB(mp, iocur_top->off >> BBSHIFT);

xfs_daddr_to_rtb?


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

* Re: [PATCH 6/8] xfs_db: enable conversion of rt space units
  2024-10-25  6:35   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
@ 2024-10-28  8:41     ` Christoph Hellwig
  2024-10-28 17:58       ` Darrick J. Wong
  0 siblings, 1 reply; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:41 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

> +	[CT_AGBLOCK] = {
> +		.allowed = M(AGNUMBER)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),

Can you space these out with whitespaces around the operators?

> +		.allowed = M(AGBLOCK)|M(AGINO)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),

And break up the overly long lines?  In fact I wonder if just having
each M() on it's own line might be even nicer for readability.

> +static inline xfs_rtblock_t
> +xfs_daddr_to_rtb(
> +	struct xfs_mount	*mp,
> +	xfs_daddr_t		daddr)
> +{
> +	return daddr >> mp->m_blkbb_log;
> +}

We already have this in xfs_rtgroup.h in the latest tree, but
I guess that comes later?

>  Set current address to SB header in allocation group
>  .IR agno .
> 
> 
---end quoted text---

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

* Re: [PATCH 7/8] xfs_db: convert rtbitmap geometry
  2024-10-25  6:36   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
@ 2024-10-28  8:42     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:42 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH 8/8] xfs_db: convert rtsummary geometry
  2024-10-25  6:36   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
@ 2024-10-28  8:42     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:42 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good modulo the whitespace nitpick from a few patches earlier:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 1/1] xfs_db: allow setting current address to log blocks
  2024-10-25  6:36   ` [PATCH 1/1] xfs_db: allow setting current address to log blocks Darrick J. Wong
@ 2024-10-28  8:43     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:43 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4
  2024-10-25  6:36   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
@ 2024-10-28  8:43     ` Christoph Hellwig
  0 siblings, 0 replies; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:43 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


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

* Re: [PATCH 1/1] xfs_scrub_all: wait for services to start activating
  2024-10-25  6:38   ` [PATCH 1/1] xfs_scrub_all: wait for services to start activating Darrick J. Wong
@ 2024-10-28  8:44     ` Christoph Hellwig
  2024-10-28 16:45       ` Darrick J. Wong
  0 siblings, 1 reply; 56+ messages in thread
From: Christoph Hellwig @ 2024-10-28  8:44 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: cem, aalbersh, linux-xfs

On Thu, Oct 24, 2024 at 11:38:27PM -0700, Darrick J. Wong wrote:
> From: Darrick J. Wong <djwong@kernel.org>
> 
> It seems that the function call to start a systemd unit completes
> asynchronously from any change in that unit's active state.  On a
> lightly loaded system, a Start() call followed by an ActiveState()
> call actually sees the change in state from inactive to activating.
> 
> Unfortunately, on a heavily loaded system, the state change may take a
> few seconds.  If this is the case, the wait() call can see that the unit
> state is "inactive", decide that the service already finished, and exit
> early, when in reality it hasn't even gotten to 'activating'.
> 
> Fix this by adding a second method that watches either for the inactive
> -> activating state transition or for the last exit from inactivation
> timestamp to change before waiting for the unit to reach inactive state.
> 
> Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> Cc: <linux-xfs@vger.kernel.org> # v6.10.0

What is this supposed to mean? 

The patch itself looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH 1/1] xfs_scrub_all: wait for services to start activating
  2024-10-28  8:44     ` Christoph Hellwig
@ 2024-10-28 16:45       ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-28 16:45 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: cem, aalbersh, linux-xfs

On Mon, Oct 28, 2024 at 01:44:23AM -0700, Christoph Hellwig wrote:
> On Thu, Oct 24, 2024 at 11:38:27PM -0700, Darrick J. Wong wrote:
> > From: Darrick J. Wong <djwong@kernel.org>
> > 
> > It seems that the function call to start a systemd unit completes
> > asynchronously from any change in that unit's active state.  On a
> > lightly loaded system, a Start() call followed by an ActiveState()
> > call actually sees the change in state from inactive to activating.
> > 
> > Unfortunately, on a heavily loaded system, the state change may take a
> > few seconds.  If this is the case, the wait() call can see that the unit
> > state is "inactive", decide that the service already finished, and exit
> > early, when in reality it hasn't even gotten to 'activating'.
> > 
> > Fix this by adding a second method that watches either for the inactive
> > -> activating state transition or for the last exit from inactivation
> > timestamp to change before waiting for the unit to reach inactive state.
> > 
> > Signed-off-by: Darrick J. Wong <djwong@kernel.org>
> > Cc: <linux-xfs@vger.kernel.org> # v6.10.0
> 
> What is this supposed to mean? 

It means that if anyone is supporting xfsprogs 6.10, this patch applies
to it.

> The patch itself looks good:
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>

Thanks!

--D

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

* Re: [PATCH 4/8] xfs_db: access realtime file blocks
  2024-10-28  8:37     ` Christoph Hellwig
@ 2024-10-28 17:50       ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-28 17:50 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: cem, aalbersh, linux-xfs

On Mon, Oct 28, 2024 at 01:37:12AM -0700, Christoph Hellwig wrote:
> > +	if (is_rtfile(iocur_top->data))
> > +		set_rt_cur(&typtab[type], (int64_t)dfsbno << mp->m_blkbb_log,
> 
> Shouldn't this be xfs_rtb_to_daddr?

This series is for xfsprogs 6.12; the helpers adding rtb <-> daddr
conversions won't get added until the rtgroups cleanups that are headed
towards 6.13.

I could try to fling a patch for 6.12 to add these trivial helpers, hope
that I can persuade Carlos to persuade Linus to add that for 6.12-rc6,
then wait until next week to port the new helper patch to xfsprogs and
*then* resend this series.  Then I'd rebase all the 6.13 stuff, initiate
another round of review, and maybe we can push metadir into 6.13
for-next after rc6.

Good grief that sounds incredibly bureaucratic for a left and right
shift helper.

I'm going to add rtb_to_daddr and daddr_to_rtb to db/block.h for now and
update them to the xfs_ versions in the metadir patchset.

> > diff --git a/db/faddr.c b/db/faddr.c
> > index ec4aae68bb5a81..fd65b86b5e915d 100644
> > --- a/db/faddr.c
> > +++ b/db/faddr.c
> > @@ -323,7 +323,9 @@ fa_drtbno(
> >  		dbprintf(_("null block number, cannot set new addr\n"));
> >  		return;
> >  	}
> > -	/* need set_cur to understand rt subvolume */
> > +
> > +	set_rt_cur(&typtab[next], (int64_t)XFS_FSB_TO_BB(mp, bno), blkbb,
> > +			DB_RING_ADD, NULL);
> 
> Same here?

Yep.

--D

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

* Re: [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents
  2024-10-28  8:38     ` Christoph Hellwig
@ 2024-10-28 17:51       ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-28 17:51 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: cem, aalbersh, linux-xfs

On Mon, Oct 28, 2024 at 01:38:50AM -0700, Christoph Hellwig wrote:
> > +	ASSERT(typtab[TYP_DATA].typnm == TYP_DATA);
> > +	set_rt_cur(&typtab[TYP_DATA], XFS_FSB_TO_BB(mp, rtbno), blkbb,
> > +			DB_RING_ADD, NULL);
> 
> xfs_rtb_to_daddr?
> 
> > +		rtbno = XFS_BB_TO_FSB(mp, iocur_top->off >> BBSHIFT);
> 
> xfs_daddr_to_rtb?

Yes to both.

--D

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

* Re: [PATCH 6/8] xfs_db: enable conversion of rt space units
  2024-10-28  8:41     ` Christoph Hellwig
@ 2024-10-28 17:58       ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-28 17:58 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: cem, aalbersh, linux-xfs

On Mon, Oct 28, 2024 at 01:41:38AM -0700, Christoph Hellwig wrote:
> > +	[CT_AGBLOCK] = {
> > +		.allowed = M(AGNUMBER)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),
> 
> Can you space these out with whitespaces around the operators?
> 
> > +		.allowed = M(AGBLOCK)|M(AGINO)|M(BBOFF)|M(BLKOFF)|M(INOIDX)|M(INOOFF),
> 
> And break up the overly long lines?  In fact I wonder if just having
> each M() on it's own line might be even nicer for readability.

That does look a lot better:

	[CT_AGBLOCK] = {
		.allowed = M(AGNUMBER) |
			   M(BBOFF) |
			   M(BLKOFF) |
			   M(INOIDX) |
			   M(INOOFF),
		.names   = agblock_names,
	},

> > +static inline xfs_rtblock_t
> > +xfs_daddr_to_rtb(
> > +	struct xfs_mount	*mp,
> > +	xfs_daddr_t		daddr)
> > +{
> > +	return daddr >> mp->m_blkbb_log;
> > +}
> 
> We already have this in xfs_rtgroup.h in the latest tree, but
> I guess that comes later?

Yeah, that won't show up until we start working on 6.13, or whenever
metadir goes in.

(Also I changed my mind on naming and decided to use "xfs_" on the
db/block.h helpers that I mentioned in the previous two replies to
reduce churn downwind.)

--D

> >  Set current address to SB header in allocation group
> >  .IR agno .
> > 
> > 
> ---end quoted text---
> 

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

* [PATCH 7/8] xfs_db: convert rtbitmap geometry
  2024-10-29 15:47 [PATCHSET v5.2 1/2] xfs_db: debug realtime geometry Darrick J. Wong
@ 2024-10-29 15:49 ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-29 15:49 UTC (permalink / raw)
  To: aalbersh, cem, djwong; +Cc: linux-xfs, hch

From: Darrick J. Wong <djwong@kernel.org>

Teach the rtconvert command to be able to convert realtime blocks and
extents to locations within the rt bitmap.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/convert.c      |   40 ++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   10 ++++++++++
 2 files changed, 50 insertions(+)


diff --git a/db/convert.c b/db/convert.c
index 4c2ff1c5804c47..7c10690f574f7a 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -31,6 +31,10 @@
 	((uint64_t)(x) << mp->m_sb.sb_blocklog)
 #define rtx_to_rtblock(x)	\
 	((uint64_t)(x) * mp->m_sb.sb_rextsize)
+#define rbmblock_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock(xfs_rbmblock_to_rtx(mp, (uint64_t)x)))
+#define rbmword_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock((uint64_t)(x) << XFS_NBWORDLOG))
 
 typedef enum {
 	CT_NONE = -1,
@@ -47,6 +51,8 @@ typedef enum {
 	CT_INOOFF,		/* byte offset in inode */
 	CT_RTBLOCK,		/* realtime block */
 	CT_RTX,			/* realtime extent */
+	CT_RBMBLOCK,		/* block within rt bitmap */
+	CT_RBMWORD,		/* word within rt bitmap */
 	NCTS
 } ctype_t;
 
@@ -69,6 +75,8 @@ typedef union {
 	int		inooff;
 	xfs_rtblock_t	rtblock;
 	xfs_rtblock_t	rtx;
+	xfs_fileoff_t	rbmblock;
+	unsigned int	rbmword;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
@@ -95,6 +103,8 @@ static const char	*inooff_names[] = { "inooff", "inodeoff", NULL };
 
 static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
 static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
+static const char	*rbmblock_names[] = { "rbmblock", "rbmb", NULL };
+static const char	*rbmword_names[] = { "rbmword", "rbmw", NULL };
 
 static const ctydesc_t	ctydescs[NCTS] = {
 	[CT_AGBLOCK] = {
@@ -196,6 +206,14 @@ static const ctydesc_t	ctydescs_rt[NCTS] = {
 			   M(BLKOFF),
 		.names   = rtx_names,
 	},
+	[CT_RBMBLOCK] = {
+		.allowed = M(RBMWORD),
+		.names   = rbmblock_names,
+	},
+	[CT_RBMWORD] = {
+		.allowed = M(RBMBLOCK),
+		.names   = rbmword_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
@@ -236,6 +254,10 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return rtblock_to_bytes(val->rtblock);
 	case CT_RTX:
 		return rtblock_to_bytes(rtx_to_rtblock(val->rtx));
+	case CT_RBMBLOCK:
+		return rbmblock_to_bytes(val->rbmblock);
+	case CT_RBMWORD:
+		return rbmword_to_bytes(val->rbmword);
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -337,6 +359,8 @@ convert_f(int argc, char **argv)
 		break;
 	case CT_RTBLOCK:
 	case CT_RTX:
+	case CT_RBMBLOCK:
+	case CT_RBMWORD:
 		/* shouldn't get here */
 		ASSERT(0);
 		break;
@@ -418,6 +442,16 @@ rtconvert_f(int argc, char **argv)
 	case CT_RTX:
 		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT) / mp->m_sb.sb_rextsize;
 		break;
+	case CT_RBMBLOCK:
+		v = xfs_rtx_to_rbmblock(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
+	case CT_RBMWORD:
+		v = xfs_rtx_to_rbmword(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
 	case CT_AGBLOCK:
 	case CT_AGINO:
 	case CT_AGNUMBER:
@@ -495,6 +529,12 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_RTX:
 		val->rtx = (xfs_rtblock_t)v;
 		break;
+	case CT_RBMBLOCK:
+		val->rbmblock = (xfs_fileoff_t)v;
+		break;
+	case CT_RBMWORD:
+		val->rbmword = (unsigned int)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 0bf434299a3fb4..12fc4f3b51016b 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1173,6 +1173,16 @@ .SH COMMANDS
 or
 .B rtextent
 (realtime extent)
+.HP
+.B rbmblock
+or
+.B rbmb
+(realtime bitmap block)
+.HP
+.B rbmword
+or
+.B rbmw
+(32-bit word within a realtime bitmap block)
 .PD
 .RE
 .IP


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

* [PATCH 7/8] xfs_db: convert rtbitmap geometry
  2024-10-31 23:07 [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
@ 2024-10-31 23:23 ` Darrick J. Wong
  0 siblings, 0 replies; 56+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:23 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Darrick J. Wong <djwong@kernel.org>

Teach the rtconvert command to be able to convert realtime blocks and
extents to locations within the rt bitmap.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/convert.c      |   40 ++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   10 ++++++++++
 2 files changed, 50 insertions(+)


diff --git a/db/convert.c b/db/convert.c
index 4c2ff1c5804c47..7c10690f574f7a 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -31,6 +31,10 @@
 	((uint64_t)(x) << mp->m_sb.sb_blocklog)
 #define rtx_to_rtblock(x)	\
 	((uint64_t)(x) * mp->m_sb.sb_rextsize)
+#define rbmblock_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock(xfs_rbmblock_to_rtx(mp, (uint64_t)x)))
+#define rbmword_to_bytes(x)	\
+	rtblock_to_bytes(rtx_to_rtblock((uint64_t)(x) << XFS_NBWORDLOG))
 
 typedef enum {
 	CT_NONE = -1,
@@ -47,6 +51,8 @@ typedef enum {
 	CT_INOOFF,		/* byte offset in inode */
 	CT_RTBLOCK,		/* realtime block */
 	CT_RTX,			/* realtime extent */
+	CT_RBMBLOCK,		/* block within rt bitmap */
+	CT_RBMWORD,		/* word within rt bitmap */
 	NCTS
 } ctype_t;
 
@@ -69,6 +75,8 @@ typedef union {
 	int		inooff;
 	xfs_rtblock_t	rtblock;
 	xfs_rtblock_t	rtx;
+	xfs_fileoff_t	rbmblock;
+	unsigned int	rbmword;
 } cval_t;
 
 static uint64_t		bytevalue(ctype_t ctype, cval_t *val);
@@ -95,6 +103,8 @@ static const char	*inooff_names[] = { "inooff", "inodeoff", NULL };
 
 static const char	*rtblock_names[] = { "rtblock", "rtb", "rtbno", NULL };
 static const char	*rtx_names[] = { "rtx", "rtextent", NULL };
+static const char	*rbmblock_names[] = { "rbmblock", "rbmb", NULL };
+static const char	*rbmword_names[] = { "rbmword", "rbmw", NULL };
 
 static const ctydesc_t	ctydescs[NCTS] = {
 	[CT_AGBLOCK] = {
@@ -196,6 +206,14 @@ static const ctydesc_t	ctydescs_rt[NCTS] = {
 			   M(BLKOFF),
 		.names   = rtx_names,
 	},
+	[CT_RBMBLOCK] = {
+		.allowed = M(RBMWORD),
+		.names   = rbmblock_names,
+	},
+	[CT_RBMWORD] = {
+		.allowed = M(RBMBLOCK),
+		.names   = rbmword_names,
+	},
 };
 
 static const cmdinfo_t	convert_cmd =
@@ -236,6 +254,10 @@ bytevalue(ctype_t ctype, cval_t *val)
 		return rtblock_to_bytes(val->rtblock);
 	case CT_RTX:
 		return rtblock_to_bytes(rtx_to_rtblock(val->rtx));
+	case CT_RBMBLOCK:
+		return rbmblock_to_bytes(val->rbmblock);
+	case CT_RBMWORD:
+		return rbmword_to_bytes(val->rbmword);
 	case CT_NONE:
 	case NCTS:
 		break;
@@ -337,6 +359,8 @@ convert_f(int argc, char **argv)
 		break;
 	case CT_RTBLOCK:
 	case CT_RTX:
+	case CT_RBMBLOCK:
+	case CT_RBMWORD:
 		/* shouldn't get here */
 		ASSERT(0);
 		break;
@@ -418,6 +442,16 @@ rtconvert_f(int argc, char **argv)
 	case CT_RTX:
 		v = xfs_daddr_to_rtb(mp, v >> BBSHIFT) / mp->m_sb.sb_rextsize;
 		break;
+	case CT_RBMBLOCK:
+		v = xfs_rtx_to_rbmblock(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
+	case CT_RBMWORD:
+		v = xfs_rtx_to_rbmword(mp,
+				xfs_rtb_to_rtx(mp,
+					xfs_daddr_to_rtb(mp, v >> BBSHIFT)));
+		break;
 	case CT_AGBLOCK:
 	case CT_AGINO:
 	case CT_AGNUMBER:
@@ -495,6 +529,12 @@ getvalue(char *s, ctype_t ctype, cval_t *val)
 	case CT_RTX:
 		val->rtx = (xfs_rtblock_t)v;
 		break;
+	case CT_RBMBLOCK:
+		val->rbmblock = (xfs_fileoff_t)v;
+		break;
+	case CT_RBMWORD:
+		val->rbmword = (unsigned int)v;
+		break;
 	case CT_NONE:
 	case NCTS:
 		/* NOTREACHED */
diff --git a/man/man8/xfs_db.8 b/man/man8/xfs_db.8
index 0bf434299a3fb4..12fc4f3b51016b 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1173,6 +1173,16 @@ .SH COMMANDS
 or
 .B rtextent
 (realtime extent)
+.HP
+.B rbmblock
+or
+.B rbmb
+(realtime bitmap block)
+.HP
+.B rbmword
+or
+.B rbmw
+(32-bit word within a realtime bitmap block)
 .PD
 .RE
 .IP


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

end of thread, other threads:[~2024-10-31 23:23 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-25  6:26 [PATCHBOMB] xfsprogs: utility changes for 6.12 Darrick J. Wong
2024-10-25  6:31 ` Darrick J. Wong
2024-10-25  6:31 ` [PATCHSET v31.2 1/5] xfsprogs: atomic file content commits Darrick J. Wong
2024-10-25  6:32   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
2024-10-28  8:31     ` Christoph Hellwig
2024-10-25  6:32   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
2024-10-28  8:32     ` Christoph Hellwig
2024-10-25  6:33   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
2024-10-28  8:32     ` Christoph Hellwig
2024-10-25  6:33   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
2024-10-28  8:32     ` Christoph Hellwig
2024-10-25  6:33   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
2024-10-28  8:33     ` Christoph Hellwig
2024-10-25  6:34   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
2024-10-28  8:33     ` Christoph Hellwig
2024-10-25  6:34   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
2024-10-28  8:33     ` Christoph Hellwig
2024-10-25  6:31 ` [PATCHSET v2.6 2/5] xfs_db: debug realtime geometry Darrick J. Wong
2024-10-25  6:34   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
2024-10-28  8:34     ` Christoph Hellwig
2024-10-25  6:34   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
2024-10-28  8:34     ` Christoph Hellwig
2024-10-25  6:35   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
2024-10-28  8:35     ` Christoph Hellwig
2024-10-25  6:35   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
2024-10-28  8:37     ` Christoph Hellwig
2024-10-28 17:50       ` Darrick J. Wong
2024-10-25  6:35   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
2024-10-28  8:38     ` Christoph Hellwig
2024-10-28 17:51       ` Darrick J. Wong
2024-10-25  6:35   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
2024-10-28  8:41     ` Christoph Hellwig
2024-10-28 17:58       ` Darrick J. Wong
2024-10-25  6:36   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
2024-10-28  8:42     ` Christoph Hellwig
2024-10-25  6:36   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
2024-10-28  8:42     ` Christoph Hellwig
2024-10-25  6:31 ` [PATCHSET v2.6 3/5] xfs_metadump: support external devices Darrick J. Wong
2024-10-25  6:36   ` [PATCH 1/1] xfs_db: allow setting current address to log blocks Darrick J. Wong
2024-10-28  8:43     ` Christoph Hellwig
2024-10-25  6:32 ` [PATCHSET v2.6 4/5] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
2024-10-25  6:36   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
2024-10-28  8:43     ` Christoph Hellwig
2024-10-25  6:37   ` [PATCH 2/6] xfs_repair: use xfs_validate_rt_geometry Darrick J. Wong
2024-10-25  6:37   ` [PATCH 3/6] mkfs: remove a pointless rtfreesp_init forward declaration Darrick J. Wong
2024-10-25  6:37   ` [PATCH 4/6] mkfs: use xfs_rtfile_initialize_blocks Darrick J. Wong
2024-10-25  6:37   ` [PATCH 5/6] xfs_repair: use libxfs_rtfile_initialize_blocks Darrick J. Wong
2024-10-25  6:38   ` [PATCH 6/6] xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino Darrick J. Wong
2024-10-25  6:32 ` [PATCHSET v31.2 5/5] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
2024-10-25  6:38   ` [PATCH 1/1] xfs_scrub_all: wait for services to start activating Darrick J. Wong
2024-10-28  8:44     ` Christoph Hellwig
2024-10-28 16:45       ` Darrick J. Wong
  -- strict thread matches above, loose matches on Subject: below --
2024-10-31 23:07 [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
2024-10-31 23:23 ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
2024-10-29 15:47 [PATCHSET v5.2 1/2] xfs_db: debug realtime geometry Darrick J. Wong
2024-10-29 15:49 ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
2023-12-31 19:52 [PATCHSET v2.0 03/17] xfs_db: debug realtime geometry Darrick J. Wong
2023-12-31 23:46 ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
2022-12-30 22:19 [PATCHSET v1.0 0/8] xfs_db: debug realtime geometry Darrick J. Wong
2022-12-30 22:19 ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox