public inbox for linux-xfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCHBOMB v3] xfsprogs: everything I have for 6.12
@ 2024-10-31 22:57 Darrick J. Wong
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                   ` (6 more replies)
  0 siblings, 7 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 22:57 UTC (permalink / raw)
  To: Andrey Albershteyn; +Cc: xfs, Christoph Hellwig

Hi Andrey,

All of the patches that I've submitted for xfsprogs 6.12 have completed
review, and I'm about to send you pull requests for all of those
branches.  However, I'm first resending all those patches to the list so
that they are archived in their final form.

With these patches pulled, you will be in a position to say that
xfsprogs is (at last!) in sync with the kernel.  This should make it
/much/ easier for authors of large patchsets to run QA on matching
kernel and userspace.

--D

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

* [PATCHSET 1/7] libxfs: new code for 6.12
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
@ 2024-10-31 23:07 ` Darrick J. Wong
  2024-10-31 23:08   ` [PATCH 01/41] libxfs: require -std=gnu11 for compilation by default Darrick J. Wong
                     ` (40 more replies)
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
                   ` (5 subsequent siblings)
  6 siblings, 41 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:07 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

Hi all,

New code for 6.12.

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=libxfs-sync-6.12
---
Commits in this patchset:
 * libxfs: require -std=gnu11 for compilation by default
 * libxfs: test compiling public headers with a C++ compiler
 * libxfs: port IS_ENABLED from the kernel
 * libfrog: add xarray emulation
 * xfs: introduce new file range commit ioctls
 * xfs: pass the icreate args object to xfs_dialloc
 * xfs: remove xfs_validate_rtextents
 * xfs: factor out a xfs_validate_rt_geometry helper
 * xfs: remove the limit argument to xfs_rtfind_back
 * xfs: assert a valid limit in xfs_rtfind_forw
 * xfs: add bounds checking to xfs_rt{bitmap,summary}_read_buf
 * xfs: factor out rtbitmap/summary initialization helpers
 * xfs: push transaction join out of xfs_rtbitmap_lock and xfs_rtgroup_lock
 * xfs: ensure rtx mask/shift are correct after growfs
 * xfs: remove xfs_rtb_to_rtxrem
 * xfs: simplify xfs_rtalloc_query_range
 * xfs: clean up the ISVALID macro in xfs_bmap_adjacent
 * xfs: remove xfs_{rtbitmap,rtsummary}_wordcount
 * xfs: replace m_rsumsize with m_rsumblocks
 * xfs: fix a sloppy memory handling bug in xfs_iroot_realloc
 * xfs: replace shouty XFS_BM{BT,DR} macros
 * xfs: standardize the btree maxrecs function parameters
 * xfs: use kvmalloc for xattr buffers
 * xfs: remove unnecessary check
 * xfs: use kfree_rcu_mightsleep to free the perag structures
 * xfs: move the tagged perag lookup helpers to xfs_icache.c
 * xfs: convert perag lookup to xarray
 * xfs: ensure st_blocks never goes to zero during COW writes
 * xfs: enable block size larger than page size support
 * xfs: merge xfs_attr_leaf_try_add into xfs_attr_leaf_addname
 * xfs: return bool from xfs_attr3_leaf_add
 * xfs: distinguish extra split from real ENOSPC from xfs_attr3_leaf_split
 * xfs: distinguish extra split from real ENOSPC from xfs_attr_node_try_addname
 * xfs: fold xfs_bmap_alloc_userdata into xfs_bmapi_allocate
 * xfs: don't ifdef around the exact minlen allocations
 * xfs: call xfs_bmap_exact_minlen_extent_alloc from xfs_bmap_btalloc
 * xfs: support lowmode allocations in xfs_bmap_exact_minlen_extent_alloc
 * xfs: pass the exact range to initialize to xfs_initialize_perag
 * xfs: merge the perag freeing helpers
 * xfs: don't use __GFP_RETRY_MAYFAIL in xfs_initialize_perag
 * xfs: update the pag for the last AG at recovery time
---
 configure.ac                |   13 ++
 db/bmap.c                   |   10 +-
 db/bmap_inflate.c           |    2 
 db/bmroot.c                 |    8 +
 db/btheight.c               |   18 +--
 db/check.c                  |   11 +-
 db/frag.c                   |    8 +
 db/iunlink.c                |    2 
 db/metadump.c               |   16 +--
 include/builddefs.in        |    8 +
 include/kmem.h              |   11 ++
 include/libxfs.h            |    6 +
 include/platform_defs.h     |   63 ++++++++++
 include/xfs_mount.h         |    4 -
 libfrog/radix-tree.h        |   35 +++++
 libxfs/Makefile             |   31 +++++
 libxfs/defer_item.c         |   14 ++
 libxfs/init.c               |   17 ++-
 libxfs/ioctl_c_dummy.c      |   11 ++
 libxfs/ioctl_cxx_dummy.cpp  |   13 ++
 libxfs/libxfs_api_defs.h    |    2 
 libxfs/libxfs_priv.h        |    6 +
 libxfs/xfs_ag.c             |  165 +++++---------------------
 libxfs/xfs_ag.h             |   25 +---
 libxfs/xfs_alloc.c          |    7 -
 libxfs/xfs_alloc.h          |    4 -
 libxfs/xfs_alloc_btree.c    |    6 -
 libxfs/xfs_alloc_btree.h    |    3 
 libxfs/xfs_attr.c           |  190 +++++++++++++-----------------
 libxfs/xfs_attr_leaf.c      |   63 +++++-----
 libxfs/xfs_attr_leaf.h      |    2 
 libxfs/xfs_bmap.c           |  243 ++++++++++++++++----------------------
 libxfs/xfs_bmap_btree.c     |   24 ++--
 libxfs/xfs_bmap_btree.h     |  207 ++++++++++++++++++++++----------
 libxfs/xfs_da_btree.c       |    5 -
 libxfs/xfs_fs.h             |   26 ++++
 libxfs/xfs_ialloc.c         |   14 ++
 libxfs/xfs_ialloc.h         |    4 -
 libxfs/xfs_ialloc_btree.c   |    6 -
 libxfs/xfs_ialloc_btree.h   |    3 
 libxfs/xfs_inode_fork.c     |   40 +++---
 libxfs/xfs_inode_util.c     |    2 
 libxfs/xfs_refcount_btree.c |    5 -
 libxfs/xfs_refcount_btree.h |    3 
 libxfs/xfs_rmap_btree.c     |    7 +
 libxfs/xfs_rmap_btree.h     |    3 
 libxfs/xfs_rtbitmap.c       |  274 +++++++++++++++++++++++++++++++------------
 libxfs/xfs_rtbitmap.h       |   61 ++--------
 libxfs/xfs_sb.c             |   92 ++++++++------
 libxfs/xfs_sb.h             |    3 
 libxfs/xfs_shared.h         |    3 
 libxfs/xfs_trans_resv.c     |    4 -
 libxfs/xfs_types.h          |   12 --
 m4/package_utilies.m4       |    5 +
 mkfs/proto.c                |   17 +--
 repair/bmap_repair.c        |    2 
 repair/dinode.c             |   17 +--
 repair/phase5.c             |   16 +--
 repair/phase6.c             |   18 +--
 repair/prefetch.c           |    8 +
 repair/rt.c                 |    7 -
 repair/scan.c               |    6 -
 62 files changed, 1062 insertions(+), 849 deletions(-)
 create mode 100644 libxfs/ioctl_c_dummy.c
 create mode 100644 libxfs/ioctl_cxx_dummy.cpp


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

* [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
@ 2024-10-31 23:07 ` Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
                     ` (6 more replies)
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
                   ` (4 subsequent siblings)
  6 siblings, 7 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:07 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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] 73+ messages in thread

* [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
@ 2024-10-31 23:07 ` Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
                     ` (7 more replies)
  2024-10-31 23:07 ` [PATCHSET v5.3 4/7] xfs_metadump: support external devices Darrick J. Wong
                   ` (3 subsequent siblings)
  6 siblings, 8 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:07 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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        |  171 ++++++++++++++++++++-
 db/block.h        |   20 ++
 db/convert.c      |  438 ++++++++++++++++++++++++++++++++++++++++++++++++++---
 db/faddr.c        |    5 -
 db/init.c         |    7 +
 db/io.c           |   39 ++++-
 db/io.h           |    3 
 db/xfs_admin.sh   |    4 
 man/man8/xfs_db.8 |  131 ++++++++++++++++
 9 files changed, 778 insertions(+), 40 deletions(-)


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

* [PATCHSET v5.3 4/7] xfs_metadump: support external devices
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
                   ` (2 preceding siblings ...)
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
@ 2024-10-31 23:07 ` Darrick J. Wong
  2024-10-31 23:23   ` [PATCH 1/1] xfs_db: allow setting current address to log blocks Darrick J. Wong
  2024-10-31 23:08 ` [PATCHSET v5.3 5/7] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:07 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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] 73+ messages in thread

* [PATCHSET v5.3 5/7] mkfs/repair: use new rtbitmap helpers
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
                   ` (3 preceding siblings ...)
  2024-10-31 23:07 ` [PATCHSET v5.3 4/7] xfs_metadump: support external devices Darrick J. Wong
@ 2024-10-31 23:08 ` Darrick J. Wong
  2024-10-31 23:23   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
                     ` (5 more replies)
  2024-10-31 23:08 ` [PATCHSET v31.3 6/7] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
  2024-10-31 23:08 ` [PATCHSET 7/7] mkfs: new config file for 6.12 LTS Darrick J. Wong
  6 siblings, 6 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:08 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs, linux-xfs

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] 73+ messages in thread

* [PATCHSET v31.3 6/7] xfs_scrub_all: bug fix for 6.12
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
                   ` (4 preceding siblings ...)
  2024-10-31 23:08 ` [PATCHSET v5.3 5/7] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
@ 2024-10-31 23:08 ` Darrick J. Wong
  2024-10-31 23:25   ` [PATCH 1/1] xfs_scrub_all: wait for services to start activating Darrick J. Wong
  2024-10-31 23:08 ` [PATCHSET 7/7] mkfs: new config file for 6.12 LTS Darrick J. Wong
  6 siblings, 1 reply; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:08 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs, linux-xfs

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] 73+ messages in thread

* [PATCHSET 7/7] mkfs: new config file for 6.12 LTS
  2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
                   ` (5 preceding siblings ...)
  2024-10-31 23:08 ` [PATCHSET v31.3 6/7] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
@ 2024-10-31 23:08 ` Darrick J. Wong
  2024-10-31 23:25   ` [PATCH 1/1] mkfs: add a config file for 6.12 LTS kernels Darrick J. Wong
  6 siblings, 1 reply; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:08 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

Hi all,

New mkfs config file for 6.12 LTS.

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=mkfs-configs-6.12
---
Commits in this patchset:
 * mkfs: add a config file for 6.12 LTS kernels
---
 mkfs/Makefile      |    3 ++-
 mkfs/lts_6.12.conf |   19 +++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
 create mode 100644 mkfs/lts_6.12.conf


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

* [PATCH 01/41] libxfs: require -std=gnu11 for compilation by default
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
@ 2024-10-31 23:08   ` Darrick J. Wong
  2024-10-31 23:09   ` [PATCH 02/41] libxfs: test compiling public headers with a C++ compiler Darrick J. Wong
                     ` (39 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:08 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

The kernel now builds with -std=gnu11, so let's make xfsprogs do that by
default too.  Distributions can still override the parameters by passing
CFLAGS= and BUILD_CFLAGS= to configure, just as they always have.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 configure.ac |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)


diff --git a/configure.ac b/configure.ac
index 901208a8d273eb..b75f7d9e7563b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,6 +5,11 @@ AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_SRCDIR([include/libxfs.h])
 AC_PREFIX_DEFAULT(/usr)
 
+# Default CFLAGS if nobody specifies anything else
+if test "${CFLAGS+set}" != "set"; then
+	CFLAGS="-g -O2 -std=gnu11"
+fi
+
 AC_PROG_INSTALL
 LT_INIT
 
@@ -22,7 +27,7 @@ if test "${BUILD_CFLAGS+set}" != "set"; then
   if test $cross_compiling = no; then
     BUILD_CFLAGS="$CFLAGS"
   else
-    BUILD_CFLAGS="-g -O2"
+    BUILD_CFLAGS="-g -O2 -std=gnu11"
   fi
 fi
 


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

* [PATCH 02/41] libxfs: test compiling public headers with a C++ compiler
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
  2024-10-31 23:08   ` [PATCH 01/41] libxfs: require -std=gnu11 for compilation by default Darrick J. Wong
@ 2024-10-31 23:09   ` Darrick J. Wong
  2024-10-31 23:09   ` [PATCH 03/41] libxfs: port IS_ENABLED from the kernel Darrick J. Wong
                     ` (38 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:09 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Apparently C++ compilers don't like the implicit void* casts that go on
in the system headers.  Compile a dummy program with the C++ compiler to
make sure this works.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Tested-by: Sam James <sam@gentoo.org>
Reviewed-by: Sam James <sam@gentoo.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 configure.ac               |    6 ++++++
 include/builddefs.in       |    8 ++++++++
 libxfs/Makefile            |   31 ++++++++++++++++++++++++++++++-
 libxfs/ioctl_c_dummy.c     |   11 +++++++++++
 libxfs/ioctl_cxx_dummy.cpp |   13 +++++++++++++
 m4/package_utilies.m4      |    5 +++++
 6 files changed, 73 insertions(+), 1 deletion(-)
 create mode 100644 libxfs/ioctl_c_dummy.c
 create mode 100644 libxfs/ioctl_cxx_dummy.cpp


diff --git a/configure.ac b/configure.ac
index b75f7d9e7563b2..dc587f39b80533 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,6 +9,9 @@ AC_PREFIX_DEFAULT(/usr)
 if test "${CFLAGS+set}" != "set"; then
 	CFLAGS="-g -O2 -std=gnu11"
 fi
+if test "${CXXFLAGS+set}" != "set"; then
+	CXXFLAGS="-g -O2 -std=gnu++11"
+fi
 
 AC_PROG_INSTALL
 LT_INIT
@@ -31,6 +34,9 @@ if test "${BUILD_CFLAGS+set}" != "set"; then
   fi
 fi
 
+AC_PROG_CXX
+# no C++ build tools yet
+
 AC_ARG_ENABLE(shared,
 [  --enable-shared=[yes/no]  Enable use of shared libraries [default=yes]],,
 	enable_shared=yes)
diff --git a/include/builddefs.in b/include/builddefs.in
index c8c7de7fd2fd38..1cbace071108dd 100644
--- a/include/builddefs.in
+++ b/include/builddefs.in
@@ -14,6 +14,7 @@ MALLOCLIB = @malloc_lib@
 LOADERFLAGS = @LDFLAGS@
 LTLDFLAGS = @LDFLAGS@
 CFLAGS = @CFLAGS@ -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -Wno-address-of-packed-member
+CXXFLAGS = @CXXFLAGS@ -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64 -Wno-address-of-packed-member
 BUILD_CFLAGS = @BUILD_CFLAGS@ -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
 
 # make sure we don't pick up whacky LDFLAGS from the make environment and
@@ -63,6 +64,7 @@ XFS_SCRUB_ALL_AUTO_MEDIA_SCAN_STAMP=$(PKG_STATE_DIR)/xfs_scrub_all_media.stamp
 
 CC		= @cc@
 BUILD_CC	= @BUILD_CC@
+CXX		= @cxx@
 AWK		= @awk@
 SED		= @sed@
 TAR		= @tar@
@@ -161,9 +163,15 @@ ifeq ($(ENABLE_GETTEXT),yes)
 GCFLAGS += -DENABLE_GETTEXT
 endif
 
+# Override these if C++ needs other options
+SANITIZER_CXXFLAGS = $(SANITIZER_CFLAGS)
+GCXXFLAGS = $(GCFLAGS)
+PCXXFLAGS = $(PCFLAGS)
+
 BUILD_CFLAGS += $(GCFLAGS) $(PCFLAGS)
 # First, Sanitizer, Global, Platform, Local CFLAGS
 CFLAGS += $(FCFLAGS) $(SANITIZER_CFLAGS) $(OPTIMIZER) $(GCFLAGS) $(PCFLAGS) $(LCFLAGS)
+CXXFLAGS += $(FCXXFLAGS) $(SANITIZER_CXXFLAGS) $(OPTIMIZER) $(GCXXFLAGS) $(PCXXFLAGS) $(LCXXFLAGS)
 
 include $(TOPDIR)/include/buildmacros
 
diff --git a/libxfs/Makefile b/libxfs/Makefile
index 72e287b8b7957a..aca28440adac08 100644
--- a/libxfs/Makefile
+++ b/libxfs/Makefile
@@ -125,6 +125,18 @@ CFILES = buf_mem.c \
 	xfs_trans_space.c \
 	xfs_types.c
 
+EXTRA_CFILES=\
+	ioctl_c_dummy.c
+
+EXTRA_CXXFILES=\
+	ioctl_cxx_dummy.cpp
+
+EXTRA_OBJECTS=\
+	$(patsubst %.c,%.o,$(EXTRA_CFILES)) \
+	$(patsubst %.cpp,%.o,$(EXTRA_CXXFILES))
+
+LDIRT += $(EXTRA_OBJECTS)
+
 #
 # Tracing flags:
 # -DMEM_DEBUG		all zone memory use
@@ -148,7 +160,23 @@ LTLIBS = $(LIBPTHREAD) $(LIBRT)
 # don't try linking xfs_repair with a debug libxfs.
 DEBUG = -DNDEBUG
 
-default: ltdepend $(LTLIBRARY)
+default: ltdepend $(LTLIBRARY) $(EXTRA_OBJECTS)
+
+%dummy.o: %dummy.cpp
+	@echo "    [CXXD]   $@"
+	$(Q)$(CXX) $(CXXFLAGS) -c $<
+
+%dummy.o: %dummy.c
+	@echo "    [CCD]    $@"
+	$(Q)$(CC) $(CFLAGS) -c $<
+
+MAKECXXDEP := $(MAKEDEPEND) $(CXXFLAGS)
+
+.PHONY: .extradep
+
+.extradep: $(EXTRA_CFILES) $(EXTRA_CXXFILES) $(HFILES)
+	$(Q)$(MAKEDEP) $(EXTRA_CFILES) > .extradep
+	$(Q)$(MAKECXXDEP) $(EXTRA_CXXFILES) >> .extradep
 
 # set up include/xfs header directory
 include $(BUILDRULES)
@@ -172,4 +200,5 @@ install-dev: install
 # running the install-headers target.
 ifndef NODEP
 -include .ltdep
+-include .extradep
 endif
diff --git a/libxfs/ioctl_c_dummy.c b/libxfs/ioctl_c_dummy.c
new file mode 100644
index 00000000000000..e417332c3cf9f6
--- /dev/null
+++ b/libxfs/ioctl_c_dummy.c
@@ -0,0 +1,11 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+
+/* Dummy program to test C compilation of user-exported xfs headers */
+
+#include "include/xfs.h"
+#include "include/handle.h"
+#include "include/jdm.h"
diff --git a/libxfs/ioctl_cxx_dummy.cpp b/libxfs/ioctl_cxx_dummy.cpp
new file mode 100644
index 00000000000000..b95babff0b0aee
--- /dev/null
+++ b/libxfs/ioctl_cxx_dummy.cpp
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2024 Oracle.  All Rights Reserved.
+ * Author: Darrick J. Wong <djwong@kernel.org>
+ */
+
+/* Dummy program to test C++ compilation of user-exported xfs headers */
+
+extern "C" {
+#include "include/xfs.h"
+#include "include/handle.h"
+#include "include/jdm.h"
+};
diff --git a/m4/package_utilies.m4 b/m4/package_utilies.m4
index 49f4dfbbd2d168..56ee0b266130bf 100644
--- a/m4/package_utilies.m4
+++ b/m4/package_utilies.m4
@@ -42,6 +42,11 @@ AC_DEFUN([AC_PACKAGE_UTILITIES],
     AC_SUBST(cc)
     AC_PACKAGE_NEED_UTILITY($1, "$cc", cc, [C compiler])
 
+    AC_PROG_CXX
+    cxx="$CXX"
+    AC_SUBST(cxx)
+    AC_PACKAGE_NEED_UTILITY($1, "$cxx", cxx, [C++ compiler])
+
     if test -z "$MAKE"; then
         AC_PATH_PROG(MAKE, gmake,, $PATH)
     fi


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

* [PATCH 03/41] libxfs: port IS_ENABLED from the kernel
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
  2024-10-31 23:08   ` [PATCH 01/41] libxfs: require -std=gnu11 for compilation by default Darrick J. Wong
  2024-10-31 23:09   ` [PATCH 02/41] libxfs: test compiling public headers with a C++ compiler Darrick J. Wong
@ 2024-10-31 23:09   ` Darrick J. Wong
  2024-10-31 23:09   ` [PATCH 04/41] libfrog: add xarray emulation Darrick J. Wong
                     ` (37 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:09 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Port the IS_ENABLED macro from the kernel so that it can be used in
libxfs.  This requires a bit of hygiene on our part -- any CONFIG_XFS_*
define in userspace that have counterparts in the kernel must be defined
to 1 (and not simply define'd) so that the macro works, because the
kernel translates CONFIG_FOO=y in .config to #define CONFIG_FOO 1.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 include/libxfs.h        |    6 +++-
 include/platform_defs.h |   63 +++++++++++++++++++++++++++++++++++++++++++++++
 libxfs/libxfs_priv.h    |    5 ++--
 3 files changed, 70 insertions(+), 4 deletions(-)


diff --git a/include/libxfs.h b/include/libxfs.h
index 17cf619f0544aa..fe8e6584f1caca 100644
--- a/include/libxfs.h
+++ b/include/libxfs.h
@@ -7,10 +7,12 @@
 #ifndef __LIBXFS_H__
 #define __LIBXFS_H__
 
+/* CONFIG_XFS_* must be defined to 1 to work with IS_ENABLED() */
+
 /* For userspace XFS_RT is always defined */
-#define CONFIG_XFS_RT
+#define CONFIG_XFS_RT 1
 /* Ditto in-memory btrees */
-#define CONFIG_XFS_BTREE_IN_MEM
+#define CONFIG_XFS_BTREE_IN_MEM 1
 
 #include "libxfs_api_defs.h"
 #include "platform_defs.h"
diff --git a/include/platform_defs.h b/include/platform_defs.h
index c01d4c42674669..a3644dea41cdef 100644
--- a/include/platform_defs.h
+++ b/include/platform_defs.h
@@ -165,4 +165,67 @@ static inline size_t __ab_c_size(size_t a, size_t b, size_t c)
 # define barrier() __memory_barrier()
 #endif
 
+/* stuff from include/linux/kconfig.h */
+#define __ARG_PLACEHOLDER_1 0,
+#define __take_second_arg(__ignored, val, ...) val
+
+/*
+ * The use of "&&" / "||" is limited in certain expressions.
+ * The following enable to calculate "and" / "or" with macro expansion only.
+ */
+#define __and(x, y)			___and(x, y)
+#define ___and(x, y)			____and(__ARG_PLACEHOLDER_##x, y)
+#define ____and(arg1_or_junk, y)	__take_second_arg(arg1_or_junk y, 0)
+
+#define __or(x, y)			___or(x, y)
+#define ___or(x, y)			____or(__ARG_PLACEHOLDER_##x, y)
+#define ____or(arg1_or_junk, y)		__take_second_arg(arg1_or_junk 1, y)
+
+/*
+ * Helper macros to use CONFIG_ options in C/CPP expressions. Note that
+ * these only work with boolean and tristate options.
+ */
+
+/*
+ * Getting something that works in C and CPP for an arg that may or may
+ * not be defined is tricky.  Here, if we have "#define CONFIG_BOOGER 1"
+ * we match on the placeholder define, insert the "0," for arg1 and generate
+ * the triplet (0, 1, 0).  Then the last step cherry picks the 2nd arg (a one).
+ * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when
+ * the last step cherry picks the 2nd arg, we get a zero.
+ */
+#define __is_defined(x)			___is_defined(x)
+#define ___is_defined(val)		____is_defined(__ARG_PLACEHOLDER_##val)
+#define ____is_defined(arg1_or_junk)	__take_second_arg(arg1_or_junk 1, 0)
+
+/*
+ * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0
+ * otherwise. For boolean options, this is equivalent to
+ * IS_ENABLED(CONFIG_FOO).
+ */
+#define IS_BUILTIN(option) __is_defined(option)
+
+/*
+ * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0
+ * otherwise.  CONFIG_FOO=m results in "#define CONFIG_FOO_MODULE 1" in
+ * autoconf.h.
+ */
+#define IS_MODULE(option) __is_defined(option##_MODULE)
+
+/*
+ * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled
+ * code can call a function defined in code compiled based on CONFIG_FOO.
+ * This is similar to IS_ENABLED(), but returns false when invoked from
+ * built-in code when CONFIG_FOO is set to 'm'.
+ */
+#define IS_REACHABLE(option) __or(IS_BUILTIN(option), \
+				__and(IS_MODULE(option), __is_defined(MODULE)))
+
+/*
+ * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm',
+ * 0 otherwise.  Note that CONFIG_FOO=y results in "#define CONFIG_FOO 1" in
+ * autoconf.h, while CONFIG_FOO=m results in "#define CONFIG_FOO_MODULE 1".
+ */
+#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option))
+
 #endif	/* __XFS_PLATFORM_DEFS_H__ */
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index b720cc5fac94ff..fa025aeb09712b 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -37,8 +37,9 @@
 #ifndef __LIBXFS_INTERNAL_XFS_H__
 #define __LIBXFS_INTERNAL_XFS_H__
 
-#define CONFIG_XFS_RT
-#define CONFIG_XFS_BTREE_IN_MEM
+/* CONFIG_XFS_* must be defined to 1 to work with IS_ENABLED() */
+#define CONFIG_XFS_RT 1
+#define CONFIG_XFS_BTREE_IN_MEM 1
 
 #include "libxfs_api_defs.h"
 #include "platform_defs.h"


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

* [PATCH 04/41] libfrog: add xarray emulation
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (2 preceding siblings ...)
  2024-10-31 23:09   ` [PATCH 03/41] libxfs: port IS_ENABLED from the kernel Darrick J. Wong
@ 2024-10-31 23:09   ` Darrick J. Wong
  2024-10-31 23:10   ` [PATCH 05/41] xfs: introduce new file range commit ioctls Darrick J. Wong
                     ` (36 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:09 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Implement the simple parts of the kernel xarray API on-top of the libfrog
radix-tree.

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>
---
 libfrog/radix-tree.h |   35 +++++++++++++++++++++++++++++++++++
 1 file changed, 35 insertions(+)


diff --git a/libfrog/radix-tree.h b/libfrog/radix-tree.h
index dad5f5b72039e3..fe896134eeb283 100644
--- a/libfrog/radix-tree.h
+++ b/libfrog/radix-tree.h
@@ -63,4 +63,39 @@ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
 static inline int radix_tree_preload(int gfp_mask) { return 0; }
 static inline void radix_tree_preload_end(void) { }
 
+/*
+ * Emulation of the kernel xarray API.  Note that unlike the kernel
+ * xarray, there is no internal locking so code using this should not
+ * allow concurrent operations in userspace.
+ */
+struct xarray {
+	struct radix_tree_root	r;
+};
+
+static inline void xa_init(struct xarray *xa)
+{
+	INIT_RADIX_TREE(&xa->r, GFP_KERNEL);
+}
+
+static inline void *xa_load(struct xarray *xa, unsigned long index)
+{
+	return radix_tree_lookup(&xa->r, index);
+}
+
+static inline void *xa_erase(struct xarray *xa, unsigned long index)
+{
+	return radix_tree_delete(&xa->r, index);
+}
+
+static inline int xa_insert(struct xarray *xa, unsigned long index, void *entry,
+		unsigned int gfp)
+{
+	int error;
+
+	error = radix_tree_insert(&xa->r, index, entry);
+	if (error == -EEXIST)
+		return -EBUSY;
+	return error;
+}
+
 #endif /* __LIBFROG_RADIX_TREE_H__ */


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

* [PATCH 05/41] xfs: introduce new file range commit ioctls
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (3 preceding siblings ...)
  2024-10-31 23:09   ` [PATCH 04/41] libfrog: add xarray emulation Darrick J. Wong
@ 2024-10-31 23:10   ` Darrick J. Wong
  2024-10-31 23:10   ` [PATCH 06/41] xfs: pass the icreate args object to xfs_dialloc Darrick J. Wong
                     ` (35 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:10 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Source kernel commit: 398597c3ef7fb1d8fa31491c8f4f3996cff45701

This patch introduces two more new ioctls to manage atomic updates to
file contents -- XFS_IOC_START_COMMIT and XFS_IOC_COMMIT_RANGE.  The
does, but with the additional requirement that file2 cannot have changed
since some sampling point.  The start-commit ioctl performs the sampling
of file attributes.

Note: This patch currently samples i_ctime during START_COMMIT and
checks that it hasn't changed during COMMIT_RANGE.  This isn't entirely
safe in kernels prior to 6.12 because ctime only had coarse grained
granularity and very fast updates could collide with a COMMIT_RANGE.
With the multi-granularity ctime introduced by Jeff Layton, it's now
possible to update ctime such that this does not happen.

It is critical, then, that this patch must not be backported to any
kernel that does not support fine-grained file change timestamps.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 libxfs/xfs_fs.h |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)


diff --git a/libxfs/xfs_fs.h b/libxfs/xfs_fs.h
index 184ccbfe708218..860284064c5aa9 100644
--- a/libxfs/xfs_fs.h
+++ b/libxfs/xfs_fs.h
@@ -826,6 +826,30 @@ struct xfs_exchange_range {
 	__u64		flags;		/* see XFS_EXCHANGE_RANGE_* below */
 };
 
+/*
+ * Using the same definition of file2 as struct xfs_exchange_range, commit the
+ * contents of file1 into file2 if file2 has the same inode number, mtime, and
+ * ctime as the arguments provided to the call.  The old contents of file2 will
+ * be moved to file1.
+ *
+ * Returns -EBUSY if there isn't an exact match for the file2 fields.
+ *
+ * Filesystems must be able to restart and complete the operation even after
+ * the system goes down.
+ */
+struct xfs_commit_range {
+	__s32		file1_fd;
+	__u32		pad;		/* must be zeroes */
+	__u64		file1_offset;	/* file1 offset, bytes */
+	__u64		file2_offset;	/* file2 offset, bytes */
+	__u64		length;		/* bytes to exchange */
+
+	__u64		flags;		/* see XFS_EXCHANGE_RANGE_* below */
+
+	/* opaque file2 metadata for freshness checks */
+	__u64		file2_freshness[6];
+};
+
 /*
  * Exchange file data all the way to the ends of both files, and then exchange
  * the file sizes.  This flag can be used to replace a file's contents with a
@@ -998,6 +1022,8 @@ struct xfs_getparents_by_handle {
 #define XFS_IOC_BULKSTAT	     _IOR ('X', 127, struct xfs_bulkstat_req)
 #define XFS_IOC_INUMBERS	     _IOR ('X', 128, struct xfs_inumbers_req)
 #define XFS_IOC_EXCHANGE_RANGE	     _IOW ('X', 129, struct xfs_exchange_range)
+#define XFS_IOC_START_COMMIT	     _IOR ('X', 130, struct xfs_commit_range)
+#define XFS_IOC_COMMIT_RANGE	     _IOW ('X', 131, struct xfs_commit_range)
 /*	XFS_IOC_GETFSUUID ---------- deprecated 140	 */
 
 


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

* [PATCH 06/41] xfs: pass the icreate args object to xfs_dialloc
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-31 23:10   ` [PATCH 05/41] xfs: introduce new file range commit ioctls Darrick J. Wong
@ 2024-10-31 23:10   ` Darrick J. Wong
  2024-10-31 23:10   ` [PATCH 07/41] xfs: remove xfs_validate_rtextents Darrick J. Wong
                     ` (34 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:10 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Source kernel commit: 390b4775d6787706b1846f15623a68e576ec900c

Pass the xfs_icreate_args object to xfs_dialloc since we can extract the
relevant mode (really just the file type) and parent inumber from there.
This simplifies the calling convention in preparation for the next
patch.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/iunlink.c        |    2 +-
 libxfs/xfs_ialloc.c |    5 +++--
 libxfs/xfs_ialloc.h |    4 +++-
 mkfs/proto.c        |    5 ++---
 repair/phase6.c     |    2 +-
 5 files changed, 10 insertions(+), 8 deletions(-)


diff --git a/db/iunlink.c b/db/iunlink.c
index 0dc68b7240c1a3..55ba5af5a3c563 100644
--- a/db/iunlink.c
+++ b/db/iunlink.c
@@ -223,7 +223,7 @@ create_unlinked(
 		return error;
 	}
 
-	error = -libxfs_dialloc(&tp, 0, args.mode, &ino);
+	error = -libxfs_dialloc(&tp, &args, &ino);
 	if (error) {
 		dbprintf(_("alloc inode: %s\n"), strerror(error));
 		goto out_cancel;
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index c526f677e072b4..83e3d7d7c5a1b3 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -1850,11 +1850,12 @@ xfs_dialloc_try_ag(
 int
 xfs_dialloc(
 	struct xfs_trans	**tpp,
-	xfs_ino_t		parent,
-	umode_t			mode,
+	const struct xfs_icreate_args *args,
 	xfs_ino_t		*new_ino)
 {
 	struct xfs_mount	*mp = (*tpp)->t_mountp;
+	xfs_ino_t		parent = args->pip ? args->pip->i_ino : 0;
+	umode_t			mode = args->mode & S_IFMT;
 	xfs_agnumber_t		agno;
 	int			error = 0;
 	xfs_agnumber_t		start_agno;
diff --git a/libxfs/xfs_ialloc.h b/libxfs/xfs_ialloc.h
index b549627e3a6150..3a1323155a455a 100644
--- a/libxfs/xfs_ialloc.h
+++ b/libxfs/xfs_ialloc.h
@@ -33,11 +33,13 @@ xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o)
 	return xfs_buf_offset(b, o << (mp)->m_sb.sb_inodelog);
 }
 
+struct xfs_icreate_args;
+
 /*
  * Allocate an inode on disk.  Mode is used to tell whether the new inode will
  * need space, and whether it is a directory.
  */
-int xfs_dialloc(struct xfs_trans **tpp, xfs_ino_t parent, umode_t mode,
+int xfs_dialloc(struct xfs_trans **tpp, const struct xfs_icreate_args *args,
 		xfs_ino_t *new_ino);
 
 int xfs_difree(struct xfs_trans *tp, struct xfs_perag *pag,
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 8a51bfb264cedf..42ac3e10929b52 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -428,7 +428,6 @@ creatproto(
 	};
 	struct xfs_inode	*ip;
 	struct inode		*inode;
-	xfs_ino_t		parent_ino = dp ? dp->i_ino : 0;
 	xfs_ino_t		ino;
 	int			error;
 
@@ -440,7 +439,7 @@ creatproto(
 	 * Call the space management code to pick the on-disk inode to be
 	 * allocated.
 	 */
-	error = -libxfs_dialloc(tpp, parent_ino, mode, &ino);
+	error = -libxfs_dialloc(tpp, &args, &ino);
 	if (error)
 		return error;
 
@@ -769,7 +768,7 @@ create_sb_metadata_file(
 	if (error)
 		res_failed(error);
 
-	error = -libxfs_dialloc(&tp, 0, args.mode, &ino);
+	error = -libxfs_dialloc(&tp, &args, &ino);
 	if (error)
 		goto fail;
 
diff --git a/repair/phase6.c b/repair/phase6.c
index ba28edaa41c24c..b48f18b06a5c81 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -873,7 +873,7 @@ mk_orphanage(
 	if (i)
 		res_failed(i);
 
-	error = -libxfs_dialloc(&tp, mp->m_sb.sb_rootino, args.mode, &ino);
+	error = -libxfs_dialloc(&tp, &args, &ino);
 	if (error)
 		do_error(_("%s inode allocation failed %d\n"),
 			ORPHANAGE, error);


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

* [PATCH 07/41] xfs: remove xfs_validate_rtextents
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (5 preceding siblings ...)
  2024-10-31 23:10   ` [PATCH 06/41] xfs: pass the icreate args object to xfs_dialloc Darrick J. Wong
@ 2024-10-31 23:10   ` Darrick J. Wong
  2024-10-31 23:10   ` [PATCH 08/41] xfs: factor out a xfs_validate_rt_geometry helper Darrick J. Wong
                     ` (33 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:10 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 021d9c107e29a598e51fb66a54b22e5416125408

Replace xfs_validate_rtextents with an open coded check for 0
rtextents.  The name for the function implies it does a lot more
than a zero check, which is more obvious when open coded.

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/xfs_sb.c    |    2 +-
 libxfs/xfs_types.h |   12 ------------
 2 files changed, 1 insertion(+), 13 deletions(-)


diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index bedb36a0620dff..a50c9c06c3f19c 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -511,7 +511,7 @@ xfs_validate_sb_common(
 		rbmblocks = howmany_64(sbp->sb_rextents,
 				       NBBY * sbp->sb_blocksize);
 
-		if (!xfs_validate_rtextents(rexts) ||
+		if (sbp->sb_rextents == 0 ||
 		    sbp->sb_rextents != rexts ||
 		    sbp->sb_rextslog != xfs_compute_rextslog(rexts) ||
 		    sbp->sb_rbmblocks != rbmblocks) {
diff --git a/libxfs/xfs_types.h b/libxfs/xfs_types.h
index 76eb9e328835f8..a8cd44d03ef648 100644
--- a/libxfs/xfs_types.h
+++ b/libxfs/xfs_types.h
@@ -235,16 +235,4 @@ bool xfs_verify_fileoff(struct xfs_mount *mp, xfs_fileoff_t off);
 bool xfs_verify_fileext(struct xfs_mount *mp, xfs_fileoff_t off,
 		xfs_fileoff_t len);
 
-/* Do we support an rt volume having this number of rtextents? */
-static inline bool
-xfs_validate_rtextents(
-	xfs_rtbxlen_t		rtextents)
-{
-	/* No runt rt volumes */
-	if (rtextents == 0)
-		return false;
-
-	return true;
-}
-
 #endif	/* __XFS_TYPES_H__ */


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

* [PATCH 08/41] xfs: factor out a xfs_validate_rt_geometry helper
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (6 preceding siblings ...)
  2024-10-31 23:10   ` [PATCH 07/41] xfs: remove xfs_validate_rtextents Darrick J. Wong
@ 2024-10-31 23:10   ` Darrick J. Wong
  2024-10-31 23:11   ` [PATCH 09/41] xfs: remove the limit argument to xfs_rtfind_back Darrick J. Wong
                     ` (32 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:10 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 6529eef810e2ded0e540162273ee31a41314ec4e

Split the RT geometry validation in the early mount code into a
helper than can be reused by repair (from which this code was
apparently originally stolen anyway).

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: u64 return value for calc_rbmblocks]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libxfs/xfs_sb.c |   64 ++++++++++++++++++++++++++++++-------------------------
 libxfs/xfs_sb.h |    1 +
 2 files changed, 36 insertions(+), 29 deletions(-)


diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index a50c9c06c3f19c..c3185a4daeb4aa 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -229,6 +229,38 @@ xfs_validate_sb_read(
 	return 0;
 }
 
+static uint64_t
+xfs_sb_calc_rbmblocks(
+	struct xfs_sb		*sbp)
+{
+	return howmany_64(sbp->sb_rextents, NBBY * sbp->sb_blocksize);
+}
+
+/* Validate the realtime geometry */
+bool
+xfs_validate_rt_geometry(
+	struct xfs_sb		*sbp)
+{
+	if (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE ||
+	    sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE)
+		return false;
+
+	if (sbp->sb_rblocks == 0) {
+		if (sbp->sb_rextents != 0 || sbp->sb_rbmblocks != 0 ||
+		    sbp->sb_rextslog != 0 || sbp->sb_frextents != 0)
+			return false;
+		return true;
+	}
+
+	if (sbp->sb_rextents == 0 ||
+	    sbp->sb_rextents != div_u64(sbp->sb_rblocks, sbp->sb_rextsize) ||
+	    sbp->sb_rextslog != xfs_compute_rextslog(sbp->sb_rextents) ||
+	    sbp->sb_rbmblocks != xfs_sb_calc_rbmblocks(sbp))
+		return false;
+
+	return true;
+}
+
 /* Check all the superblock fields we care about when writing one out. */
 STATIC int
 xfs_validate_sb_write(
@@ -488,39 +520,13 @@ xfs_validate_sb_common(
 		}
 	}
 
-	/* Validate the realtime geometry; stolen from xfs_repair */
-	if (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE ||
-	    sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) {
+	if (!xfs_validate_rt_geometry(sbp)) {
 		xfs_notice(mp,
-			"realtime extent sanity check failed");
+			"realtime %sgeometry check failed",
+			sbp->sb_rblocks ? "" : "zeroed ");
 		return -EFSCORRUPTED;
 	}
 
-	if (sbp->sb_rblocks == 0) {
-		if (sbp->sb_rextents != 0 || sbp->sb_rbmblocks != 0 ||
-		    sbp->sb_rextslog != 0 || sbp->sb_frextents != 0) {
-			xfs_notice(mp,
-				"realtime zeroed geometry check failed");
-			return -EFSCORRUPTED;
-		}
-	} else {
-		uint64_t	rexts;
-		uint64_t	rbmblocks;
-
-		rexts = div_u64(sbp->sb_rblocks, sbp->sb_rextsize);
-		rbmblocks = howmany_64(sbp->sb_rextents,
-				       NBBY * sbp->sb_blocksize);
-
-		if (sbp->sb_rextents == 0 ||
-		    sbp->sb_rextents != rexts ||
-		    sbp->sb_rextslog != xfs_compute_rextslog(rexts) ||
-		    sbp->sb_rbmblocks != rbmblocks) {
-			xfs_notice(mp,
-				"realtime geometry sanity check failed");
-			return -EFSCORRUPTED;
-		}
-	}
-
 	/*
 	 * Either (sb_unit and !hasdalign) or (!sb_unit and hasdalign)
 	 * would imply the image is corrupted.
diff --git a/libxfs/xfs_sb.h b/libxfs/xfs_sb.h
index 37b1ed1bc2095e..796f02191dfd2e 100644
--- a/libxfs/xfs_sb.h
+++ b/libxfs/xfs_sb.h
@@ -38,6 +38,7 @@ extern int	xfs_sb_get_secondary(struct xfs_mount *mp,
 bool	xfs_validate_stripe_geometry(struct xfs_mount *mp,
 		__s64 sunit, __s64 swidth, int sectorsize, bool may_repair,
 		bool silent);
+bool	xfs_validate_rt_geometry(struct xfs_sb *sbp);
 
 uint8_t xfs_compute_rextslog(xfs_rtbxlen_t rtextents);
 


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

* [PATCH 09/41] xfs: remove the limit argument to xfs_rtfind_back
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (7 preceding siblings ...)
  2024-10-31 23:10   ` [PATCH 08/41] xfs: factor out a xfs_validate_rt_geometry helper Darrick J. Wong
@ 2024-10-31 23:11   ` Darrick J. Wong
  2024-10-31 23:11   ` [PATCH 10/41] xfs: assert a valid limit in xfs_rtfind_forw Darrick J. Wong
                     ` (31 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:11 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 119c65e56bc131b466a7cd958a4089e286ce3c4b

All callers pass a 0 limit to xfs_rtfind_back, so remove the argument
and hard code 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/xfs_rtbitmap.c |    9 ++++-----
 libxfs/xfs_rtbitmap.h |    2 +-
 2 files changed, 5 insertions(+), 6 deletions(-)


diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index 58a3ba992f51cc..c7613f2de7b0a0 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -137,14 +137,13 @@ xfs_rtbuf_get(
 }
 
 /*
- * Searching backward from start to limit, find the first block whose
- * allocated/free state is different from start's.
+ * Searching backward from start find the first block whose allocated/free state
+ * is different from start's.
  */
 int
 xfs_rtfind_back(
 	struct xfs_rtalloc_args	*args,
 	xfs_rtxnum_t		start,	/* starting rtext to look at */
-	xfs_rtxnum_t		limit,	/* last rtext to look at */
 	xfs_rtxnum_t		*rtx)	/* out: start rtext found */
 {
 	struct xfs_mount	*mp = args->mp;
@@ -173,7 +172,7 @@ xfs_rtfind_back(
 	 */
 	word = xfs_rtx_to_rbmword(mp, start);
 	bit = (int)(start & (XFS_NBWORD - 1));
-	len = start - limit + 1;
+	len = start + 1;
 	/*
 	 * Compute match value, based on the bit at start: if 1 (free)
 	 * then all-ones, else all-zeroes.
@@ -696,7 +695,7 @@ xfs_rtfree_range(
 	 * We need to find the beginning and end of the extent so we can
 	 * properly update the summary.
 	 */
-	error = xfs_rtfind_back(args, start, 0, &preblock);
+	error = xfs_rtfind_back(args, start, &preblock);
 	if (error) {
 		return error;
 	}
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index 6186585f2c376d..1e04f0954a0fa7 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -316,7 +316,7 @@ xfs_rtsummary_read_buf(
 int xfs_rtcheck_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
 		xfs_rtxlen_t len, int val, xfs_rtxnum_t *new, int *stat);
 int xfs_rtfind_back(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
-		xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock);
+		xfs_rtxnum_t *rtblock);
 int xfs_rtfind_forw(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
 		xfs_rtxnum_t limit, xfs_rtxnum_t *rtblock);
 int xfs_rtmodify_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,


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

* [PATCH 10/41] xfs: assert a valid limit in xfs_rtfind_forw
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (8 preceding siblings ...)
  2024-10-31 23:11   ` [PATCH 09/41] xfs: remove the limit argument to xfs_rtfind_back Darrick J. Wong
@ 2024-10-31 23:11   ` Darrick J. Wong
  2024-10-31 23:11   ` [PATCH 11/41] xfs: add bounds checking to xfs_rt{bitmap,summary}_read_buf Darrick J. Wong
                     ` (30 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:11 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 6d2db12d56a389b3e8efa236976f8dc3a8ae00f0

Protect against developers passing stupid limits when refactoring the
RT code once again.

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/xfs_rtbitmap.c |    2 ++
 1 file changed, 2 insertions(+)


diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index c7613f2de7b0a0..f578b0d34b36d3 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -313,6 +313,8 @@ xfs_rtfind_forw(
 	xfs_rtword_t		incore;
 	unsigned int		word;	/* word number in the buffer */
 
+	ASSERT(start <= limit);
+
 	/*
 	 * Compute and read in starting bitmap block for starting block.
 	 */


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

* [PATCH 11/41] xfs: add bounds checking to xfs_rt{bitmap,summary}_read_buf
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (9 preceding siblings ...)
  2024-10-31 23:11   ` [PATCH 10/41] xfs: assert a valid limit in xfs_rtfind_forw Darrick J. Wong
@ 2024-10-31 23:11   ` Darrick J. Wong
  2024-10-31 23:11   ` [PATCH 12/41] xfs: factor out rtbitmap/summary initialization helpers Darrick J. Wong
                     ` (29 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:11 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: b4781eea6872431840e53ffebb95a5614e6944b4

Add a corruption check for passing an invalid block number, which is a
lot easier to understand than the xfs_bmapi_read failure later on.

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/xfs_rtbitmap.c |   31 ++++++++++++++++++++++++++++++-
 libxfs/xfs_rtbitmap.h |   22 ++--------------------
 2 files changed, 32 insertions(+), 21 deletions(-)


diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index f578b0d34b36d3..fc904547147e93 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -67,7 +67,7 @@ xfs_rtbuf_cache_relse(
  * Get a buffer for the bitmap or summary file block specified.
  * The buffer is returned read and locked.
  */
-int
+static int
 xfs_rtbuf_get(
 	struct xfs_rtalloc_args	*args,
 	xfs_fileoff_t		block,	/* block number in bitmap or summary */
@@ -136,6 +136,35 @@ xfs_rtbuf_get(
 	return 0;
 }
 
+int
+xfs_rtbitmap_read_buf(
+	struct xfs_rtalloc_args		*args,
+	xfs_fileoff_t			block)
+{
+	struct xfs_mount		*mp = args->mp;
+
+	if (XFS_IS_CORRUPT(mp, block >= mp->m_sb.sb_rbmblocks)) {
+		xfs_rt_mark_sick(mp, XFS_SICK_RT_BITMAP);
+		return -EFSCORRUPTED;
+	}
+
+	return xfs_rtbuf_get(args, block, 0);
+}
+
+int
+xfs_rtsummary_read_buf(
+	struct xfs_rtalloc_args		*args,
+	xfs_fileoff_t			block)
+{
+	struct xfs_mount		*mp = args->mp;
+
+	if (XFS_IS_CORRUPT(mp, block >= XFS_B_TO_FSB(mp, mp->m_rsumsize))) {
+		xfs_rt_mark_sick(args->mp, XFS_SICK_RT_SUMMARY);
+		return -EFSCORRUPTED;
+	}
+	return xfs_rtbuf_get(args, block, 1);
+}
+
 /*
  * Searching backward from start find the first block whose allocated/free state
  * is different from start's.
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index 1e04f0954a0fa7..e87e2099cff5e0 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -293,26 +293,8 @@ typedef int (*xfs_rtalloc_query_range_fn)(
 
 #ifdef CONFIG_XFS_RT
 void xfs_rtbuf_cache_relse(struct xfs_rtalloc_args *args);
-
-int xfs_rtbuf_get(struct xfs_rtalloc_args *args, xfs_fileoff_t block,
-		int issum);
-
-static inline int
-xfs_rtbitmap_read_buf(
-	struct xfs_rtalloc_args		*args,
-	xfs_fileoff_t			block)
-{
-	return xfs_rtbuf_get(args, block, 0);
-}
-
-static inline int
-xfs_rtsummary_read_buf(
-	struct xfs_rtalloc_args		*args,
-	xfs_fileoff_t			block)
-{
-	return xfs_rtbuf_get(args, block, 1);
-}
-
+int xfs_rtbitmap_read_buf(struct xfs_rtalloc_args *args, xfs_fileoff_t block);
+int xfs_rtsummary_read_buf(struct xfs_rtalloc_args *args, xfs_fileoff_t block);
 int xfs_rtcheck_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
 		xfs_rtxlen_t len, int val, xfs_rtxnum_t *new, int *stat);
 int xfs_rtfind_back(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,


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

* [PATCH 12/41] xfs: factor out rtbitmap/summary initialization helpers
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (10 preceding siblings ...)
  2024-10-31 23:11   ` [PATCH 11/41] xfs: add bounds checking to xfs_rt{bitmap,summary}_read_buf Darrick J. Wong
@ 2024-10-31 23:11   ` Darrick J. Wong
  2024-10-31 23:12   ` [PATCH 13/41] xfs: push transaction join out of xfs_rtbitmap_lock and xfs_rtgroup_lock Darrick J. Wong
                     ` (28 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:11 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 2a95ffc44b610643c9d5d2665600d3fbefa5ec4f

Add helpers to libxfs that can be shared by growfs and mkfs for
initializing the rtbitmap and summary, and by passing the optional data
pointer also by repair for rebuilding them.  This will become even more
useful when the rtgroups feature adds a metadata header to each block,
which means even more shared code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
[djwong: minor documentation and data advance tweaks]
Signed-off-by: Darrick J. Wong <djwong@kernel.org>
---
 libxfs/xfs_rtbitmap.c |  126 +++++++++++++++++++++++++++++++++++++++++++++++++
 libxfs/xfs_rtbitmap.h |    3 +
 2 files changed, 129 insertions(+)


diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index fc904547147e93..9d771af677adb1 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -13,6 +13,8 @@
 #include "xfs_mount.h"
 #include "xfs_inode.h"
 #include "xfs_bmap.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_trans_space.h"
 #include "xfs_trans.h"
 #include "xfs_rtbitmap.h"
 #include "xfs_health.h"
@@ -1253,3 +1255,127 @@ xfs_rtbitmap_unlock_shared(
 	if (rbmlock_flags & XFS_RBMLOCK_BITMAP)
 		xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
 }
+
+static int
+xfs_rtfile_alloc_blocks(
+	struct xfs_inode	*ip,
+	xfs_fileoff_t		offset_fsb,
+	xfs_filblks_t		count_fsb,
+	struct xfs_bmbt_irec	*map)
+{
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_trans	*tp;
+	int			nmap = 1;
+	int			error;
+
+	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtalloc,
+			XFS_GROWFSRT_SPACE_RES(mp, count_fsb), 0, 0, &tp);
+	if (error)
+		return error;
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+	error = xfs_iext_count_extend(tp, ip, XFS_DATA_FORK,
+				XFS_IEXT_ADD_NOSPLIT_CNT);
+	if (error)
+		goto out_trans_cancel;
+
+	error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb,
+			XFS_BMAPI_METADATA, 0, map, &nmap);
+	if (error)
+		goto out_trans_cancel;
+
+	return xfs_trans_commit(tp);
+
+out_trans_cancel:
+	xfs_trans_cancel(tp);
+	return error;
+}
+
+/* Get a buffer for the block. */
+static int
+xfs_rtfile_initialize_block(
+	struct xfs_inode	*ip,
+	xfs_fsblock_t		fsbno,
+	void			*data)
+{
+	struct xfs_mount	*mp = ip->i_mount;
+	struct xfs_trans	*tp;
+	struct xfs_buf		*bp;
+	const size_t		copylen = mp->m_blockwsize << XFS_WORDLOG;
+	enum xfs_blft		buf_type;
+	int			error;
+
+	if (ip == mp->m_rsumip)
+		buf_type = XFS_BLFT_RTSUMMARY_BUF;
+	else
+		buf_type = XFS_BLFT_RTBITMAP_BUF;
+
+	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero, 0, 0, 0, &tp);
+	if (error)
+		return error;
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+
+	error = xfs_trans_get_buf(tp, mp->m_ddev_targp,
+			XFS_FSB_TO_DADDR(mp, fsbno), mp->m_bsize, 0, &bp);
+	if (error) {
+		xfs_trans_cancel(tp);
+		return error;
+	}
+
+	xfs_trans_buf_set_type(tp, bp, buf_type);
+	bp->b_ops = &xfs_rtbuf_ops;
+	if (data)
+		memcpy(bp->b_addr, data, copylen);
+	else
+		memset(bp->b_addr, 0, copylen);
+	xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
+	return xfs_trans_commit(tp);
+}
+
+/*
+ * Allocate space to the bitmap or summary file, and zero it, for growfs.
+ * @data must be a contiguous buffer large enough to fill all blocks in the
+ * file; or NULL to initialize the contents to zeroes.
+ */
+int
+xfs_rtfile_initialize_blocks(
+	struct xfs_inode	*ip,		/* inode (bitmap/summary) */
+	xfs_fileoff_t		offset_fsb,	/* offset to start from */
+	xfs_fileoff_t		end_fsb,	/* offset to allocate to */
+	void			*data)		/* data to fill the blocks */
+{
+	struct xfs_mount	*mp = ip->i_mount;
+	const size_t		copylen = mp->m_blockwsize << XFS_WORDLOG;
+
+	while (offset_fsb < end_fsb) {
+		struct xfs_bmbt_irec	map;
+		xfs_filblks_t		i;
+		int			error;
+
+		error = xfs_rtfile_alloc_blocks(ip, offset_fsb,
+				end_fsb - offset_fsb, &map);
+		if (error)
+			return error;
+
+		/*
+		 * Now we need to clear the allocated blocks.
+		 *
+		 * Do this one block per transaction, to keep it simple.
+		 */
+		for (i = 0; i < map.br_blockcount; i++) {
+			error = xfs_rtfile_initialize_block(ip,
+					map.br_startblock + i, data);
+			if (error)
+				return error;
+			if (data)
+				data += copylen;
+		}
+
+		offset_fsb = map.br_startoff + map.br_blockcount;
+	}
+
+	return 0;
+}
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index e87e2099cff5e0..0d5ab5e2cb6a32 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -343,6 +343,9 @@ xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp,
 unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
 		unsigned int rsumlevels, xfs_extlen_t rbmblocks);
 
+int xfs_rtfile_initialize_blocks(struct xfs_inode *ip,
+		xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb, void *data);
+
 void xfs_rtbitmap_lock(struct xfs_trans *tp, struct xfs_mount *mp);
 void xfs_rtbitmap_unlock(struct xfs_mount *mp);
 


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

* [PATCH 13/41] xfs: push transaction join out of xfs_rtbitmap_lock and xfs_rtgroup_lock
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (11 preceding siblings ...)
  2024-10-31 23:11   ` [PATCH 12/41] xfs: factor out rtbitmap/summary initialization helpers Darrick J. Wong
@ 2024-10-31 23:12   ` Darrick J. Wong
  2024-10-31 23:12   ` [PATCH 14/41] xfs: ensure rtx mask/shift are correct after growfs Darrick J. Wong
                     ` (27 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:12 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 0a59e4f3e1670bc49d60e1bd1a9b19ca156ae9cb

To prepare for being able to join an already locked rtbitmap inode to a
transaction split out separate helpers for joining the transaction from
the locking helpers.

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/xfs_bmap.c     |    3 ++-
 libxfs/xfs_rtbitmap.c |   24 +++++++++++++-----------
 libxfs/xfs_rtbitmap.h |    6 ++++--
 3 files changed, 19 insertions(+), 14 deletions(-)


diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 4b10f169f1eb94..1f63dc775ea393 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -5370,7 +5370,8 @@ xfs_bmap_del_extent_real(
 			 */
 			if (!(tp->t_flags & XFS_TRANS_RTBITMAP_LOCKED)) {
 				tp->t_flags |= XFS_TRANS_RTBITMAP_LOCKED;
-				xfs_rtbitmap_lock(tp, mp);
+				xfs_rtbitmap_lock(mp);
+				xfs_rtbitmap_trans_join(tp);
 			}
 			error = xfs_rtfree_blocks(tp, del->br_startblock,
 					del->br_blockcount);
diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index 9d771af677adb1..c86de2aa13cea9 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -1199,23 +1199,25 @@ xfs_rtsummary_wordcount(
 	return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
 }
 
-/*
- * Lock both realtime free space metadata inodes for a freespace update.  If a
- * transaction is given, the inodes will be joined to the transaction and the
- * ILOCKs will be released on transaction commit.
- */
+/* Lock both realtime free space metadata inodes for a freespace update. */
 void
 xfs_rtbitmap_lock(
-	struct xfs_trans	*tp,
 	struct xfs_mount	*mp)
 {
 	xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP);
-	if (tp)
-		xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
-
 	xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM);
-	if (tp)
-		xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
+}
+
+/*
+ * Join both realtime free space metadata inodes to the transaction.  The
+ * ILOCKs will be released on transaction commit.
+ */
+void
+xfs_rtbitmap_trans_join(
+	struct xfs_trans	*tp)
+{
+	xfs_trans_ijoin(tp, tp->t_mountp->m_rbmip, XFS_ILOCK_EXCL);
+	xfs_trans_ijoin(tp, tp->t_mountp->m_rsumip, XFS_ILOCK_EXCL);
 }
 
 /* Unlock both realtime free space metadata inodes after a freespace update. */
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index 0d5ab5e2cb6a32..523d3d3c12c608 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -346,8 +346,9 @@ unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
 int xfs_rtfile_initialize_blocks(struct xfs_inode *ip,
 		xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb, void *data);
 
-void xfs_rtbitmap_lock(struct xfs_trans *tp, struct xfs_mount *mp);
+void xfs_rtbitmap_lock(struct xfs_mount *mp);
 void xfs_rtbitmap_unlock(struct xfs_mount *mp);
+void xfs_rtbitmap_trans_join(struct xfs_trans *tp);
 
 /* Lock the rt bitmap inode in shared mode */
 #define XFS_RBMLOCK_BITMAP	(1U << 0)
@@ -376,7 +377,8 @@ xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
 # define xfs_rtbitmap_wordcount(mp, r)			(0)
 # define xfs_rtsummary_blockcount(mp, l, b)		(0)
 # define xfs_rtsummary_wordcount(mp, l, b)		(0)
-# define xfs_rtbitmap_lock(tp, mp)		do { } while (0)
+# define xfs_rtbitmap_lock(mp)			do { } while (0)
+# define xfs_rtbitmap_trans_join(tp)		do { } while (0)
 # define xfs_rtbitmap_unlock(mp)		do { } while (0)
 # define xfs_rtbitmap_lock_shared(mp, lf)	do { } while (0)
 # define xfs_rtbitmap_unlock_shared(mp, lf)	do { } while (0)


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

* [PATCH 14/41] xfs: ensure rtx mask/shift are correct after growfs
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (12 preceding siblings ...)
  2024-10-31 23:12   ` [PATCH 13/41] xfs: push transaction join out of xfs_rtbitmap_lock and xfs_rtgroup_lock Darrick J. Wong
@ 2024-10-31 23:12   ` Darrick J. Wong
  2024-10-31 23:12   ` [PATCH 15/41] xfs: remove xfs_rtb_to_rtxrem Darrick J. Wong
                     ` (26 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:12 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 86a0264ef26e90214a5bd74c72fb6e3455403bcf

When growfs sets an extent size, it doesn't updated the m_rtxblklog and
m_rtxblkmask values, which could lead to incorrect usage of them if they
were set before and can't be used for the new extent size.

Add a xfs_mount_sb_set_rextsize helper that updates the two fields, and
also use it when calculating the new RT geometry instead of disabling
the optimization there.

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/xfs_sb.c |   12 ++++++++++--
 libxfs/xfs_sb.h |    2 ++
 2 files changed, 12 insertions(+), 2 deletions(-)


diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index c3185a4daeb4aa..5f7ff4fa4e49b1 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -962,6 +962,15 @@ const struct xfs_buf_ops xfs_sb_quiet_buf_ops = {
 	.verify_write = xfs_sb_write_verify,
 };
 
+void
+xfs_mount_sb_set_rextsize(
+	struct xfs_mount	*mp,
+	struct xfs_sb		*sbp)
+{
+	mp->m_rtxblklog = log2_if_power2(sbp->sb_rextsize);
+	mp->m_rtxblkmask = mask64_if_power2(sbp->sb_rextsize);
+}
+
 /*
  * xfs_mount_common
  *
@@ -986,8 +995,7 @@ xfs_sb_mount_common(
 	mp->m_blockmask = sbp->sb_blocksize - 1;
 	mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
 	mp->m_blockwmask = mp->m_blockwsize - 1;
-	mp->m_rtxblklog = log2_if_power2(sbp->sb_rextsize);
-	mp->m_rtxblkmask = mask64_if_power2(sbp->sb_rextsize);
+	xfs_mount_sb_set_rextsize(mp, sbp);
 
 	mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
 	mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
diff --git a/libxfs/xfs_sb.h b/libxfs/xfs_sb.h
index 796f02191dfd2e..885c837559914d 100644
--- a/libxfs/xfs_sb.h
+++ b/libxfs/xfs_sb.h
@@ -17,6 +17,8 @@ extern void	xfs_log_sb(struct xfs_trans *tp);
 extern int	xfs_sync_sb(struct xfs_mount *mp, bool wait);
 extern int	xfs_sync_sb_buf(struct xfs_mount *mp);
 extern void	xfs_sb_mount_common(struct xfs_mount *mp, struct xfs_sb *sbp);
+void		xfs_mount_sb_set_rextsize(struct xfs_mount *mp,
+			struct xfs_sb *sbp);
 extern void	xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from);
 extern void	xfs_sb_to_disk(struct xfs_dsb *to, struct xfs_sb *from);
 extern void	xfs_sb_quota_from_disk(struct xfs_sb *sbp);


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

* [PATCH 15/41] xfs: remove xfs_rtb_to_rtxrem
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (13 preceding siblings ...)
  2024-10-31 23:12   ` [PATCH 14/41] xfs: ensure rtx mask/shift are correct after growfs Darrick J. Wong
@ 2024-10-31 23:12   ` Darrick J. Wong
  2024-10-31 23:12   ` [PATCH 16/41] xfs: simplify xfs_rtalloc_query_range Darrick J. Wong
                     ` (25 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:12 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: fa0fc38b255cc88aef31ff13b5593e27622204e1

Simplify the number of block number conversion helpers by removing
xfs_rtb_to_rtxrem.  Any recent compiler is smart enough to eliminate
the double divisions if using separate xfs_rtb_to_rtx and
xfs_rtb_to_rtxoff calls.

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/xfs_rtbitmap.c |    9 ++++-----
 libxfs/xfs_rtbitmap.h |   18 ------------------
 2 files changed, 4 insertions(+), 23 deletions(-)


diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index c86de2aa13cea9..74029d4431e1ca 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -1020,25 +1020,24 @@ xfs_rtfree_blocks(
 	xfs_filblks_t		rtlen)
 {
 	struct xfs_mount	*mp = tp->t_mountp;
-	xfs_rtxnum_t		start;
-	xfs_filblks_t		len;
 	xfs_extlen_t		mod;
 
 	ASSERT(rtlen <= XFS_MAX_BMBT_EXTLEN);
 
-	len = xfs_rtb_to_rtxrem(mp, rtlen, &mod);
+	mod = xfs_rtb_to_rtxoff(mp, rtlen);
 	if (mod) {
 		ASSERT(mod == 0);
 		return -EIO;
 	}
 
-	start = xfs_rtb_to_rtxrem(mp, rtbno, &mod);
+	mod = xfs_rtb_to_rtxoff(mp, rtbno);
 	if (mod) {
 		ASSERT(mod == 0);
 		return -EIO;
 	}
 
-	return xfs_rtfree_extent(tp, start, len);
+	return xfs_rtfree_extent(tp, xfs_rtb_to_rtx(mp, rtbno),
+			xfs_rtb_to_rtx(mp, rtlen));
 }
 
 /* Find all the free records within a given range. */
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index 523d3d3c12c608..69ddacd4b01e6f 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -86,24 +86,6 @@ xfs_rtb_to_rtxoff(
 	return do_div(rtbno, mp->m_sb.sb_rextsize);
 }
 
-/*
- * Crack an rt block number into an rt extent number and an offset within that
- * rt extent.  Returns the rt extent number directly and the offset in @off.
- */
-static inline xfs_rtxnum_t
-xfs_rtb_to_rtxrem(
-	struct xfs_mount	*mp,
-	xfs_rtblock_t		rtbno,
-	xfs_extlen_t		*off)
-{
-	if (likely(mp->m_rtxblklog >= 0)) {
-		*off = rtbno & mp->m_rtxblkmask;
-		return rtbno >> mp->m_rtxblklog;
-	}
-
-	return div_u64_rem(rtbno, mp->m_sb.sb_rextsize, off);
-}
-
 /*
  * Convert an rt block number into an rt extent number, rounding up to the next
  * rt extent if the rt block is not aligned to an rt extent boundary.


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

* [PATCH 16/41] xfs: simplify xfs_rtalloc_query_range
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (14 preceding siblings ...)
  2024-10-31 23:12   ` [PATCH 15/41] xfs: remove xfs_rtb_to_rtxrem Darrick J. Wong
@ 2024-10-31 23:12   ` Darrick J. Wong
  2024-10-31 23:13   ` [PATCH 17/41] xfs: clean up the ISVALID macro in xfs_bmap_adjacent Darrick J. Wong
                     ` (24 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:12 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: df8b181f1551581e96076a653cdca43468093c0f

There isn't much of a good reason to pass the xfs_rtalloc_rec structures
that describe extents to xfs_rtalloc_query_range as we really just want
a lower and upper bound xfs_rtxnum_t.  Pass the rtxnum directly and
simply the interface.

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/xfs_rtbitmap.c |   42 +++++++++++++++++-------------------------
 libxfs/xfs_rtbitmap.h |    3 +--
 2 files changed, 18 insertions(+), 27 deletions(-)


diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index 74029d4431e1ca..3f534a4724a26b 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -1045,8 +1045,8 @@ int
 xfs_rtalloc_query_range(
 	struct xfs_mount		*mp,
 	struct xfs_trans		*tp,
-	const struct xfs_rtalloc_rec	*low_rec,
-	const struct xfs_rtalloc_rec	*high_rec,
+	xfs_rtxnum_t			start,
+	xfs_rtxnum_t			end,
 	xfs_rtalloc_query_range_fn	fn,
 	void				*priv)
 {
@@ -1054,45 +1054,42 @@ xfs_rtalloc_query_range(
 		.mp			= mp,
 		.tp			= tp,
 	};
-	struct xfs_rtalloc_rec		rec;
-	xfs_rtxnum_t			rtstart;
-	xfs_rtxnum_t			rtend;
-	xfs_rtxnum_t			high_key;
-	int				is_free;
 	int				error = 0;
 
-	if (low_rec->ar_startext > high_rec->ar_startext)
+	if (start > end)
 		return -EINVAL;
-	if (low_rec->ar_startext >= mp->m_sb.sb_rextents ||
-	    low_rec->ar_startext == high_rec->ar_startext)
+	if (start == end || start >= mp->m_sb.sb_rextents)
 		return 0;
 
-	high_key = min(high_rec->ar_startext, mp->m_sb.sb_rextents - 1);
+	end = min(end, mp->m_sb.sb_rextents - 1);
 
 	/* Iterate the bitmap, looking for discrepancies. */
-	rtstart = low_rec->ar_startext;
-	while (rtstart <= high_key) {
+	while (start <= end) {
+		struct xfs_rtalloc_rec	rec;
+		int			is_free;
+		xfs_rtxnum_t		rtend;
+
 		/* Is the first block free? */
-		error = xfs_rtcheck_range(&args, rtstart, 1, 1, &rtend,
+		error = xfs_rtcheck_range(&args, start, 1, 1, &rtend,
 				&is_free);
 		if (error)
 			break;
 
 		/* How long does the extent go for? */
-		error = xfs_rtfind_forw(&args, rtstart, high_key, &rtend);
+		error = xfs_rtfind_forw(&args, start, end, &rtend);
 		if (error)
 			break;
 
 		if (is_free) {
-			rec.ar_startext = rtstart;
-			rec.ar_extcount = rtend - rtstart + 1;
+			rec.ar_startext = start;
+			rec.ar_extcount = rtend - start + 1;
 
 			error = fn(mp, tp, &rec, priv);
 			if (error)
 				break;
 		}
 
-		rtstart = rtend + 1;
+		start = rtend + 1;
 	}
 
 	xfs_rtbuf_cache_relse(&args);
@@ -1107,13 +1104,8 @@ xfs_rtalloc_query_all(
 	xfs_rtalloc_query_range_fn	fn,
 	void				*priv)
 {
-	struct xfs_rtalloc_rec		keys[2];
-
-	keys[0].ar_startext = 0;
-	keys[1].ar_startext = mp->m_sb.sb_rextents - 1;
-	keys[0].ar_extcount = keys[1].ar_extcount = 0;
-
-	return xfs_rtalloc_query_range(mp, tp, &keys[0], &keys[1], fn, priv);
+	return xfs_rtalloc_query_range(mp, tp, 0, mp->m_sb.sb_rextents - 1, fn,
+			priv);
 }
 
 /* Is the given extent all free? */
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index 69ddacd4b01e6f..0dbc9bb40668a2 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -292,8 +292,7 @@ int xfs_rtmodify_summary(struct xfs_rtalloc_args *args, int log,
 int xfs_rtfree_range(struct xfs_rtalloc_args *args, xfs_rtxnum_t start,
 		xfs_rtxlen_t len);
 int xfs_rtalloc_query_range(struct xfs_mount *mp, struct xfs_trans *tp,
-		const struct xfs_rtalloc_rec *low_rec,
-		const struct xfs_rtalloc_rec *high_rec,
+		xfs_rtxnum_t start, xfs_rtxnum_t end,
 		xfs_rtalloc_query_range_fn fn, void *priv);
 int xfs_rtalloc_query_all(struct xfs_mount *mp, struct xfs_trans *tp,
 			  xfs_rtalloc_query_range_fn fn,


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

* [PATCH 17/41] xfs: clean up the ISVALID macro in xfs_bmap_adjacent
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (15 preceding siblings ...)
  2024-10-31 23:12   ` [PATCH 16/41] xfs: simplify xfs_rtalloc_query_range Darrick J. Wong
@ 2024-10-31 23:13   ` Darrick J. Wong
  2024-10-31 23:13   ` [PATCH 18/41] xfs: remove xfs_{rtbitmap,rtsummary}_wordcount Darrick J. Wong
                     ` (23 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:13 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 1e21d1897f935815618d419c94e88452070ec8e5

Turn the  ISVALID macro defined and used inside in xfs_bmap_adjacent
that relies on implict context into a proper inline function.

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/xfs_bmap.c |   55 +++++++++++++++++++++++++++++++----------------------
 1 file changed, 32 insertions(+), 23 deletions(-)


diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 1f63dc775ea393..e2267aa1a11d4e 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -3106,6 +3106,23 @@ xfs_bmap_extsize_align(
 	return 0;
 }
 
+static inline bool
+xfs_bmap_adjacent_valid(
+	struct xfs_bmalloca	*ap,
+	xfs_fsblock_t		x,
+	xfs_fsblock_t		y)
+{
+	struct xfs_mount	*mp = ap->ip->i_mount;
+
+	if (XFS_IS_REALTIME_INODE(ap->ip) &&
+	    (ap->datatype & XFS_ALLOC_USERDATA))
+		return x < mp->m_sb.sb_rblocks;
+
+	return XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) &&
+		XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount &&
+		XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks;
+}
+
 #define XFS_ALLOC_GAP_UNITS	4
 
 /* returns true if ap->blkno was modified */
@@ -3113,36 +3130,25 @@ bool
 xfs_bmap_adjacent(
 	struct xfs_bmalloca	*ap)	/* bmap alloc argument struct */
 {
-	xfs_fsblock_t	adjust;		/* adjustment to block numbers */
-	xfs_mount_t	*mp;		/* mount point structure */
-	int		rt;		/* true if inode is realtime */
+	xfs_fsblock_t		adjust;		/* adjustment to block numbers */
 
-#define	ISVALID(x,y)	\
-	(rt ? \
-		(x) < mp->m_sb.sb_rblocks : \
-		XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \
-		XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \
-		XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks)
-
-	mp = ap->ip->i_mount;
-	rt = XFS_IS_REALTIME_INODE(ap->ip) &&
-		(ap->datatype & XFS_ALLOC_USERDATA);
 	/*
 	 * If allocating at eof, and there's a previous real block,
 	 * try to use its last block as our starting point.
 	 */
 	if (ap->eof && ap->prev.br_startoff != NULLFILEOFF &&
 	    !isnullstartblock(ap->prev.br_startblock) &&
-	    ISVALID(ap->prev.br_startblock + ap->prev.br_blockcount,
-		    ap->prev.br_startblock)) {
+	    xfs_bmap_adjacent_valid(ap,
+			ap->prev.br_startblock + ap->prev.br_blockcount,
+			ap->prev.br_startblock)) {
 		ap->blkno = ap->prev.br_startblock + ap->prev.br_blockcount;
 		/*
 		 * Adjust for the gap between prevp and us.
 		 */
 		adjust = ap->offset -
 			(ap->prev.br_startoff + ap->prev.br_blockcount);
-		if (adjust &&
-		    ISVALID(ap->blkno + adjust, ap->prev.br_startblock))
+		if (adjust && xfs_bmap_adjacent_valid(ap, ap->blkno + adjust,
+				ap->prev.br_startblock))
 			ap->blkno += adjust;
 		return true;
 	}
@@ -3165,7 +3171,8 @@ xfs_bmap_adjacent(
 		    !isnullstartblock(ap->prev.br_startblock) &&
 		    (prevbno = ap->prev.br_startblock +
 			       ap->prev.br_blockcount) &&
-		    ISVALID(prevbno, ap->prev.br_startblock)) {
+		    xfs_bmap_adjacent_valid(ap, prevbno,
+				ap->prev.br_startblock)) {
 			/*
 			 * Calculate gap to end of previous block.
 			 */
@@ -3181,8 +3188,8 @@ xfs_bmap_adjacent(
 			 * number, then just use the end of the previous block.
 			 */
 			if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->length &&
-			    ISVALID(prevbno + prevdiff,
-				    ap->prev.br_startblock))
+			    xfs_bmap_adjacent_valid(ap, prevbno + prevdiff,
+					ap->prev.br_startblock))
 				prevbno += adjust;
 			else
 				prevdiff += adjust;
@@ -3214,9 +3221,11 @@ xfs_bmap_adjacent(
 			 * offset by our length.
 			 */
 			if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->length &&
-			    ISVALID(gotbno - gotdiff, gotbno))
+			    xfs_bmap_adjacent_valid(ap, gotbno - gotdiff,
+					gotbno))
 				gotbno -= adjust;
-			else if (ISVALID(gotbno - ap->length, gotbno)) {
+			else if (xfs_bmap_adjacent_valid(ap, gotbno - ap->length,
+					gotbno)) {
 				gotbno -= ap->length;
 				gotdiff += adjust - ap->length;
 			} else
@@ -3244,7 +3253,7 @@ xfs_bmap_adjacent(
 			return true;
 		}
 	}
-#undef ISVALID
+
 	return false;
 }
 


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

* [PATCH 18/41] xfs: remove xfs_{rtbitmap,rtsummary}_wordcount
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (16 preceding siblings ...)
  2024-10-31 23:13   ` [PATCH 17/41] xfs: clean up the ISVALID macro in xfs_bmap_adjacent Darrick J. Wong
@ 2024-10-31 23:13   ` Darrick J. Wong
  2024-10-31 23:13   ` [PATCH 19/41] xfs: replace m_rsumsize with m_rsumblocks Darrick J. Wong
                     ` (22 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:13 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 1fc51cf11dd8b26856ae1c4111e402caec73019c

xfs_rtbitmap_wordcount and xfs_rtsummary_wordcount are currently unused,
so remove them to simplify refactoring other rtbitmap helpers.  They
can be added back or simply open coded when actually needed.

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>
---
 db/check.c            |    3 +--
 libxfs/xfs_rtbitmap.c |   31 -------------------------------
 libxfs/xfs_rtbitmap.h |    7 -------
 repair/rt.c           |    5 ++---
 4 files changed, 3 insertions(+), 43 deletions(-)


diff --git a/db/check.c b/db/check.c
index bceaf318d75ed8..00ef3c1d4b508c 100644
--- a/db/check.c
+++ b/db/check.c
@@ -1958,8 +1958,7 @@ init(
 
 		dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap));
 		inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap));
-		words = libxfs_rtsummary_wordcount(mp, mp->m_rsumlevels,
-				mp->m_sb.sb_rbmblocks);
+		words = mp->m_rsumsize >> XFS_WORDLOG;
 		sumfile = xcalloc(words, sizeof(union xfs_suminfo_raw));
 		sumcompute = xcalloc(words, sizeof(union xfs_suminfo_raw));
 	}
diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index 3f534a4724a26b..1c657da907132e 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -1146,21 +1146,6 @@ xfs_rtbitmap_blockcount(
 	return howmany_64(rtextents, NBBY * mp->m_sb.sb_blocksize);
 }
 
-/*
- * Compute the number of rtbitmap words needed to populate every block of a
- * bitmap that is large enough to track the given number of rt extents.
- */
-unsigned long long
-xfs_rtbitmap_wordcount(
-	struct xfs_mount	*mp,
-	xfs_rtbxlen_t		rtextents)
-{
-	xfs_filblks_t		blocks;
-
-	blocks = xfs_rtbitmap_blockcount(mp, rtextents);
-	return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
-}
-
 /* Compute the number of rtsummary blocks needed to track the given rt space. */
 xfs_filblks_t
 xfs_rtsummary_blockcount(
@@ -1174,22 +1159,6 @@ xfs_rtsummary_blockcount(
 	return XFS_B_TO_FSB(mp, rsumwords << XFS_WORDLOG);
 }
 
-/*
- * Compute the number of rtsummary info words needed to populate every block of
- * a summary file that is large enough to track the given rt space.
- */
-unsigned long long
-xfs_rtsummary_wordcount(
-	struct xfs_mount	*mp,
-	unsigned int		rsumlevels,
-	xfs_extlen_t		rbmblocks)
-{
-	xfs_filblks_t		blocks;
-
-	blocks = xfs_rtsummary_blockcount(mp, rsumlevels, rbmblocks);
-	return XFS_FSB_TO_B(mp, blocks) >> XFS_WORDLOG;
-}
-
 /* Lock both realtime free space metadata inodes for a freespace update. */
 void
 xfs_rtbitmap_lock(
diff --git a/libxfs/xfs_rtbitmap.h b/libxfs/xfs_rtbitmap.h
index 0dbc9bb40668a2..140513d1d6bcf1 100644
--- a/libxfs/xfs_rtbitmap.h
+++ b/libxfs/xfs_rtbitmap.h
@@ -316,13 +316,8 @@ int xfs_rtfree_blocks(struct xfs_trans *tp, xfs_fsblock_t rtbno,
 
 xfs_filblks_t xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t
 		rtextents);
-unsigned long long xfs_rtbitmap_wordcount(struct xfs_mount *mp,
-		xfs_rtbxlen_t rtextents);
-
 xfs_filblks_t xfs_rtsummary_blockcount(struct xfs_mount *mp,
 		unsigned int rsumlevels, xfs_extlen_t rbmblocks);
-unsigned long long xfs_rtsummary_wordcount(struct xfs_mount *mp,
-		unsigned int rsumlevels, xfs_extlen_t rbmblocks);
 
 int xfs_rtfile_initialize_blocks(struct xfs_inode *ip,
 		xfs_fileoff_t offset_fsb, xfs_fileoff_t end_fsb, void *data);
@@ -355,9 +350,7 @@ xfs_rtbitmap_blockcount(struct xfs_mount *mp, xfs_rtbxlen_t rtextents)
 	/* shut up gcc */
 	return 0;
 }
-# define xfs_rtbitmap_wordcount(mp, r)			(0)
 # define xfs_rtsummary_blockcount(mp, l, b)		(0)
-# define xfs_rtsummary_wordcount(mp, l, b)		(0)
 # define xfs_rtbitmap_lock(mp)			do { } while (0)
 # define xfs_rtbitmap_trans_join(tp)		do { } while (0)
 # define xfs_rtbitmap_unlock(mp)		do { } while (0)
diff --git a/repair/rt.c b/repair/rt.c
index 4c81e2114c7735..879946ab0b154e 100644
--- a/repair/rt.c
+++ b/repair/rt.c
@@ -27,14 +27,13 @@ rtinit(xfs_mount_t *mp)
 	 * information.  The rtbitmap buffer must be large enough to compare
 	 * against any unused bytes in the last block of the file.
 	 */
-	wordcnt = libxfs_rtbitmap_wordcount(mp, mp->m_sb.sb_rextents);
+	wordcnt = XFS_FSB_TO_B(mp, mp->m_sb.sb_rbmblocks) >> XFS_WORDLOG;
 	btmcompute = calloc(wordcnt, sizeof(union xfs_rtword_raw));
 	if (!btmcompute)
 		do_error(
 	_("couldn't allocate memory for incore realtime bitmap.\n"));
 
-	wordcnt = libxfs_rtsummary_wordcount(mp, mp->m_rsumlevels,
-			mp->m_sb.sb_rbmblocks);
+	wordcnt = mp->m_rsumsize >> XFS_WORDLOG;
 	sumcompute = calloc(wordcnt, sizeof(union xfs_suminfo_raw));
 	if (!sumcompute)
 		do_error(


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

* [PATCH 19/41] xfs: replace m_rsumsize with m_rsumblocks
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (17 preceding siblings ...)
  2024-10-31 23:13   ` [PATCH 18/41] xfs: remove xfs_{rtbitmap,rtsummary}_wordcount Darrick J. Wong
@ 2024-10-31 23:13   ` Darrick J. Wong
  2024-10-31 23:13   ` [PATCH 20/41] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc Darrick J. Wong
                     ` (21 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:13 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 33912286cb1956920712aba8cb6f38e434824357

Track the RT summary file size in blocks, just like the RT bitmap
file.  While we have users of both units, blocks are used slightly
more often and this matches the bitmap file for consistency.

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>
---
 db/check.c              |    2 +-
 include/xfs_mount.h     |    2 +-
 libxfs/init.c           |    4 +---
 libxfs/xfs_rtbitmap.c   |    2 +-
 libxfs/xfs_trans_resv.c |    2 +-
 mkfs/proto.c            |   12 +++++-------
 repair/dinode.c         |    7 ++++---
 repair/phase6.c         |   16 ++++++----------
 repair/rt.c             |    4 ++--
 9 files changed, 22 insertions(+), 29 deletions(-)


diff --git a/db/check.c b/db/check.c
index 00ef3c1d4b508c..0e91fded0c4236 100644
--- a/db/check.c
+++ b/db/check.c
@@ -1958,7 +1958,7 @@ init(
 
 		dbmap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**dbmap));
 		inomap[c] = xcalloc(mp->m_sb.sb_rblocks, sizeof(**inomap));
-		words = mp->m_rsumsize >> XFS_WORDLOG;
+		words = XFS_FSB_TO_B(mp, mp->m_rsumblocks) >> XFS_WORDLOG;
 		sumfile = xcalloc(words, sizeof(union xfs_suminfo_raw));
 		sumcompute = xcalloc(words, sizeof(union xfs_suminfo_raw));
 	}
diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index a60474a8db3f22..7571df12fba3f8 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -50,7 +50,7 @@ typedef struct xfs_mount {
 	xfs_agnumber_t		m_maxagi;	/* highest inode alloc group */
         struct xfs_ino_geometry	m_ino_geo;	/* inode geometry */
 	uint			m_rsumlevels;	/* rt summary levels */
-	uint			m_rsumsize;	/* size of rt summary, bytes */
+	xfs_filblks_t		m_rsumblocks;	/* size of rt summary, FSBs */
 	/*
 	 * Optional cache of rt summary level per bitmap block with the
 	 * invariant that m_rsum_cache[bbno] <= the minimum i for which
diff --git a/libxfs/init.c b/libxfs/init.c
index 90a539e04161bb..6ab5ef54bb69cb 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -293,7 +293,6 @@ rtmount_init(
 {
 	struct xfs_buf	*bp;	/* buffer for last block of subvolume */
 	xfs_daddr_t	d;	/* address of last block of subvolume */
-	unsigned int	rsumblocks;
 	int		error;
 
 	if (mp->m_sb.sb_rblocks == 0)
@@ -319,9 +318,8 @@ rtmount_init(
 		return -1;
 	}
 	mp->m_rsumlevels = mp->m_sb.sb_rextslog + 1;
-	rsumblocks = xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
+	mp->m_rsumblocks = xfs_rtsummary_blockcount(mp, mp->m_rsumlevels,
 			mp->m_sb.sb_rbmblocks);
-	mp->m_rsumsize = XFS_FSB_TO_B(mp, rsumblocks);
 	mp->m_rbmip = mp->m_rsumip = NULL;
 
 	/*
diff --git a/libxfs/xfs_rtbitmap.c b/libxfs/xfs_rtbitmap.c
index 1c657da907132e..cff3030d1662b7 100644
--- a/libxfs/xfs_rtbitmap.c
+++ b/libxfs/xfs_rtbitmap.c
@@ -160,7 +160,7 @@ xfs_rtsummary_read_buf(
 {
 	struct xfs_mount		*mp = args->mp;
 
-	if (XFS_IS_CORRUPT(mp, block >= XFS_B_TO_FSB(mp, mp->m_rsumsize))) {
+	if (XFS_IS_CORRUPT(mp, block >= mp->m_rsumblocks)) {
 		xfs_rt_mark_sick(args->mp, XFS_SICK_RT_SUMMARY);
 		return -EFSCORRUPTED;
 	}
diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
index 6b87bf4d554c6a..156f9578d281a0 100644
--- a/libxfs/xfs_trans_resv.c
+++ b/libxfs/xfs_trans_resv.c
@@ -915,7 +915,7 @@ xfs_calc_growrtfree_reservation(
 	return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
 		xfs_calc_inode_res(mp, 2) +
 		xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) +
-		xfs_calc_buf_res(1, mp->m_rsumsize);
+		xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, mp->m_rsumblocks));
 }
 
 /*
diff --git a/mkfs/proto.c b/mkfs/proto.c
index 42ac3e10929b52..06010980c5b313 100644
--- a/mkfs/proto.c
+++ b/mkfs/proto.c
@@ -813,7 +813,7 @@ rtsummary_create(
 {
 	struct xfs_mount	*mp = ip->i_mount;
 
-	ip->i_disk_size = mp->m_rsumsize;
+	ip->i_disk_size = mp->m_rsumblocks * mp->m_sb.sb_blocksize;
 
 	mp->m_sb.sb_rsumino = ip->i_ino;
 	mp->m_rsumip = ip;
@@ -874,25 +874,23 @@ rtsummary_init(
 	struct xfs_trans	*tp;
 	struct xfs_bmbt_irec	*ep;
 	xfs_fileoff_t		bno;
-	xfs_extlen_t		nsumblocks;
 	uint			blocks;
 	int			i;
 	int			nmap;
 	int			error;
 
-	nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
-	blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
+	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 < nsumblocks) {
+	while (bno < mp->m_rsumblocks) {
 		nmap = XFS_BMAP_MAX_NMAP;
 		error = -libxfs_bmapi_write(tp, mp->m_rsumip, bno,
-				(xfs_extlen_t)(nsumblocks - bno),
-				0, nsumblocks, map, &nmap);
+				(xfs_extlen_t)(mp->m_rsumblocks - bno),
+				0, mp->m_rsumblocks, map, &nmap);
 		if (error)
 			fail(_("Allocation of the realtime summary failed"),
 				error);
diff --git a/repair/dinode.c b/repair/dinode.c
index e36de9bf1a1be0..aae3cb7a40b981 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -1736,10 +1736,11 @@ _("realtime bitmap inode %" PRIu64 " has bad size %" PRId64 " (should be %" PRIu
 		break;
 
 	case XR_INO_RTSUM:
-		if (size != mp->m_rsumsize)  {
+		if (size != XFS_FSB_TO_B(mp, mp->m_rsumblocks))  {
 			do_warn(
-_("realtime summary inode %" PRIu64 " has bad size %" PRId64 " (should be %d)\n"),
-				lino, size, mp->m_rsumsize);
+_("realtime summary inode %" PRIu64 " has bad size %" PRIu64 " (should be %" PRIu64 ")\n"),
+				lino, size,
+				XFS_FSB_TO_B(mp, mp->m_rsumblocks));
 			return 1;
 		}
 		break;
diff --git a/repair/phase6.c b/repair/phase6.c
index b48f18b06a5c81..c96b50cf6a69dd 100644
--- a/repair/phase6.c
+++ b/repair/phase6.c
@@ -633,12 +633,10 @@ fill_rsumino(xfs_mount_t *mp)
 	int		nmap;
 	int		error;
 	xfs_fileoff_t	bno;
-	xfs_fileoff_t	end_bno;
 	xfs_bmbt_irec_t	map;
 
 	smp = sumcompute;
 	bno = 0;
-	end_bno = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
 
 	error = -libxfs_trans_alloc_rollable(mp, 10, &tp);
 	if (error)
@@ -651,7 +649,7 @@ fill_rsumino(xfs_mount_t *mp)
 			error);
 	}
 
-	while (bno < end_bno)  {
+	while (bno < mp->m_rsumblocks)  {
 		struct xfs_rtalloc_args	args = {
 			.mp		= mp,
 			.tp		= tp,
@@ -711,7 +709,6 @@ mk_rsumino(xfs_mount_t *mp)
 	int		i;
 	int		nmap;
 	int		error;
-	int		nsumblocks;
 	xfs_fileoff_t	bno;
 	xfs_bmbt_irec_t	map[XFS_BMAP_MAX_NMAP];
 	uint		blocks;
@@ -732,7 +729,7 @@ mk_rsumino(xfs_mount_t *mp)
 
 	/* Reset the rt summary inode. */
 	reset_sbroot_ino(tp, S_IFREG, ip);
-	ip->i_disk_size = mp->m_rsumsize;
+	ip->i_disk_size = mp->m_rsumblocks * mp->m_sb.sb_blocksize;
 	libxfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 	error = -libxfs_trans_commit(tp);
 	if (error)
@@ -742,19 +739,18 @@ mk_rsumino(xfs_mount_t *mp)
 	 * then allocate blocks for file and fill with zeroes (stolen
 	 * from mkfs)
 	 */
-	nsumblocks = mp->m_rsumsize >> mp->m_sb.sb_blocklog;
-	blocks = nsumblocks + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - 1;
+	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 < nsumblocks) {
+	while (bno < mp->m_rsumblocks) {
 		nmap = XFS_BMAP_MAX_NMAP;
 		error = -libxfs_bmapi_write(tp, ip, bno,
-			  (xfs_extlen_t)(nsumblocks - bno),
-			  0, nsumblocks, map, &nmap);
+			  (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"),
diff --git a/repair/rt.c b/repair/rt.c
index 879946ab0b154e..721c363cc1dd10 100644
--- a/repair/rt.c
+++ b/repair/rt.c
@@ -33,7 +33,7 @@ rtinit(xfs_mount_t *mp)
 		do_error(
 	_("couldn't allocate memory for incore realtime bitmap.\n"));
 
-	wordcnt = mp->m_rsumsize >> XFS_WORDLOG;
+	wordcnt = XFS_FSB_TO_B(mp, mp->m_rsumblocks) >> XFS_WORDLOG;
 	sumcompute = calloc(wordcnt, sizeof(union xfs_suminfo_raw));
 	if (!sumcompute)
 		do_error(
@@ -228,5 +228,5 @@ check_rtsummary(
 		return;
 
 	check_rtfile_contents(mp, "rtsummary", mp->m_sb.sb_rsumino, sumcompute,
-			XFS_B_TO_FSB(mp, mp->m_rsumsize));
+			mp->m_rsumblocks);
 }


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

* [PATCH 20/41] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (18 preceding siblings ...)
  2024-10-31 23:13   ` [PATCH 19/41] xfs: replace m_rsumsize with m_rsumblocks Darrick J. Wong
@ 2024-10-31 23:13   ` Darrick J. Wong
  2024-10-31 23:14   ` [PATCH 21/41] xfs: replace shouty XFS_BM{BT,DR} macros Darrick J. Wong
                     ` (20 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:13 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Source kernel commit: de55149b6639e903c4d06eb0474ab2c05060e61d

While refactoring code, I noticed that when xfs_iroot_realloc tries to
shrink a bmbt root block, it allocates a smaller new block and then
copies "records" and pointers to the new block.  However, bmbt root
blocks cannot ever be leaves, which means that it's not technically
correct to copy records.  We /should/ be copying keys.

Note that this has never resulted in actual memory corruption because
sizeof(bmbt_rec) == (sizeof(bmbt_key) + sizeof(bmbt_ptr)).  However,
this will no longer be true when we start adding realtime rmap stuff,
so fix this now.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 libxfs/xfs_inode_fork.c |   10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)


diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index cd5e2e72954292..8f06e5bc72b3ac 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -461,15 +461,15 @@ xfs_iroot_realloc(
 	}
 
 	/*
-	 * Only copy the records and pointers if there are any.
+	 * Only copy the keys and pointers if there are any.
 	 */
 	if (new_max > 0) {
 		/*
-		 * First copy the records.
+		 * First copy the keys.
 		 */
-		op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1);
-		np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1);
-		memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t));
+		op = (char *)XFS_BMBT_KEY_ADDR(mp, ifp->if_broot, 1);
+		np = (char *)XFS_BMBT_KEY_ADDR(mp, new_broot, 1);
+		memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));
 
 		/*
 		 * Then copy the pointers.


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

* [PATCH 21/41] xfs: replace shouty XFS_BM{BT,DR} macros
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (19 preceding siblings ...)
  2024-10-31 23:13   ` [PATCH 20/41] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc Darrick J. Wong
@ 2024-10-31 23:14   ` Darrick J. Wong
  2024-10-31 23:14   ` [PATCH 22/41] xfs: standardize the btree maxrecs function parameters Darrick J. Wong
                     ` (19 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:14 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Source kernel commit: 79124b3740063573312de4b225407ebdae219275

Replace all the shouty bmap btree and bmap disk root macros with actual
functions.

sed \
-e 's/XFS_BMBT_BLOCK_LEN/xfs_bmbt_block_len/g' \
-e 's/XFS_BMBT_REC_ADDR/xfs_bmbt_rec_addr/g' \
-e 's/XFS_BMBT_KEY_ADDR/xfs_bmbt_key_addr/g' \
-e 's/XFS_BMBT_PTR_ADDR/xfs_bmbt_ptr_addr/g' \
-e 's/XFS_BMDR_REC_ADDR/xfs_bmdr_rec_addr/g' \
-e 's/XFS_BMDR_KEY_ADDR/xfs_bmdr_key_addr/g' \
-e 's/XFS_BMDR_PTR_ADDR/xfs_bmdr_ptr_addr/g' \
-e 's/XFS_BMAP_BROOT_PTR_ADDR/xfs_bmap_broot_ptr_addr/g' \
-e 's/XFS_BMAP_BROOT_SPACE_CALC/xfs_bmap_broot_space_calc/g' \
-e 's/XFS_BMAP_BROOT_SPACE/xfs_bmap_broot_space/g' \
-e 's/XFS_BMDR_SPACE_CALC/xfs_bmdr_space_calc/g' \
-e 's/XFS_BMAP_BMDR_SPACE/xfs_bmap_bmdr_space/g' \
-i $(git ls-files fs/xfs/*.[ch] fs/xfs/libxfs/*.[ch] fs/xfs/scrub/*.[ch])

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/bmap.c               |   10 +-
 db/bmap_inflate.c       |    2 
 db/bmroot.c             |    8 +-
 db/check.c              |    8 +-
 db/frag.c               |    8 +-
 db/metadump.c           |   16 ++--
 libxfs/xfs_attr_leaf.c  |    8 +-
 libxfs/xfs_bmap.c       |   40 +++++----
 libxfs/xfs_bmap_btree.c |   18 ++--
 libxfs/xfs_bmap_btree.h |  204 ++++++++++++++++++++++++++++++++---------------
 libxfs/xfs_inode_fork.c |   30 +++----
 libxfs/xfs_trans_resv.c |    2 
 repair/bmap_repair.c    |    2 
 repair/dinode.c         |   10 +-
 repair/prefetch.c       |    8 +-
 repair/scan.c           |    6 +
 16 files changed, 228 insertions(+), 152 deletions(-)


diff --git a/db/bmap.c b/db/bmap.c
index 874135f001ea00..7915772aaee4e0 100644
--- a/db/bmap.c
+++ b/db/bmap.c
@@ -78,8 +78,8 @@ bmap(
 		push_cur();
 		rblock = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
 		fsize = XFS_DFORK_SIZE(dip, mp, whichfork);
-		pp = XFS_BMDR_PTR_ADDR(rblock, 1, libxfs_bmdr_maxrecs(fsize, 0));
-		kp = XFS_BMDR_KEY_ADDR(rblock, 1);
+		pp = xfs_bmdr_ptr_addr(rblock, 1, libxfs_bmdr_maxrecs(fsize, 0));
+		kp = xfs_bmdr_key_addr(rblock, 1);
 		bno = select_child(curoffset, kp, pp,
 					be16_to_cpu(rblock->bb_numrecs));
 		for (;;) {
@@ -88,9 +88,9 @@ bmap(
 			block = (struct xfs_btree_block *)iocur_top->data;
 			if (be16_to_cpu(block->bb_level) == 0)
 				break;
-			pp = XFS_BMBT_PTR_ADDR(mp, block, 1,
+			pp = xfs_bmbt_ptr_addr(mp, block, 1,
 				libxfs_bmbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0));
-			kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
+			kp = xfs_bmbt_key_addr(mp, block, 1);
 			bno = select_child(curoffset, kp, pp,
 					be16_to_cpu(block->bb_numrecs));
 		}
@@ -98,7 +98,7 @@ bmap(
 			nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib);
 			nextents = be16_to_cpu(block->bb_numrecs);
 			xp = (xfs_bmbt_rec_t *)
-				XFS_BMBT_REC_ADDR(mp, block, 1);
+				xfs_bmbt_rec_addr(mp, block, 1);
 			for (ep = xp; ep < &xp[nextents] && n < nex; ep++) {
 				if (!bmap_one_extent(ep, &curoffset, eoffset,
 						&n, bep)) {
diff --git a/db/bmap_inflate.c b/db/bmap_inflate.c
index 4de534dccf34b2..1de6d3439ab3d3 100644
--- a/db/bmap_inflate.c
+++ b/db/bmap_inflate.c
@@ -269,7 +269,7 @@ iroot_size(
 	unsigned int		nr_this_level,
 	void			*priv)
 {
-	return XFS_BMAP_BROOT_SPACE_CALC(cur->bc_mp, nr_this_level);
+	return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
 }
 
 static int
diff --git a/db/bmroot.c b/db/bmroot.c
index 246e390a8a39e7..7ef07da181e6ff 100644
--- a/db/bmroot.c
+++ b/db/bmroot.c
@@ -89,7 +89,7 @@ bmroota_key_offset(
 	block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
 	ASSERT(dip->di_forkoff != 0 && (char *)block == XFS_DFORK_APTR(dip));
 	ASSERT(be16_to_cpu(block->bb_level) > 0);
-	kp = XFS_BMDR_KEY_ADDR(block, idx);
+	kp = xfs_bmdr_key_addr(block, idx);
 	return bitize((int)((char *)kp - (char *)block));
 }
 
@@ -127,7 +127,7 @@ bmroota_ptr_offset(
 	block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
 	ASSERT(dip->di_forkoff != 0 && (char *)block == XFS_DFORK_APTR(dip));
 	ASSERT(be16_to_cpu(block->bb_level) > 0);
-	pp = XFS_BMDR_PTR_ADDR(block, idx,
+	pp = xfs_bmdr_ptr_addr(block, idx,
 		libxfs_bmdr_maxrecs(XFS_DFORK_ASIZE(dip, mp), 0));
 	return bitize((int)((char *)pp - (char *)block));
 }
@@ -185,7 +185,7 @@ bmrootd_key_offset(
 	ASSERT(obj == iocur_top->data);
 	block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
 	ASSERT(be16_to_cpu(block->bb_level) > 0);
-	kp = XFS_BMDR_KEY_ADDR(block, idx);
+	kp = xfs_bmdr_key_addr(block, idx);
 	return bitize((int)((char *)kp - (char *)block));
 }
 
@@ -222,7 +222,7 @@ bmrootd_ptr_offset(
 	dip = obj;
 	block = (xfs_bmdr_block_t *)((char *)obj + byteize(startoff));
 	ASSERT(be16_to_cpu(block->bb_level) > 0);
-	pp = XFS_BMDR_PTR_ADDR(block, idx,
+	pp = xfs_bmdr_ptr_addr(block, idx,
 		libxfs_bmdr_maxrecs(XFS_DFORK_DSIZE(dip, mp), 0));
 	return bitize((int)((char *)pp - (char *)block));
 }
diff --git a/db/check.c b/db/check.c
index 0e91fded0c4236..0a6e5c3280e1cf 100644
--- a/db/check.c
+++ b/db/check.c
@@ -2321,13 +2321,13 @@ process_btinode(
 		return;
 	}
 	if (be16_to_cpu(dib->bb_level) == 0) {
-		xfs_bmbt_rec_t	*rp = XFS_BMDR_REC_ADDR(dib, 1);
+		xfs_bmbt_rec_t	*rp = xfs_bmdr_rec_addr(dib, 1);
 		process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), type,
 							id, totd, blkmapp);
 		*nex += be16_to_cpu(dib->bb_numrecs);
 		return;
 	} else {
-		pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(
+		pp = xfs_bmdr_ptr_addr(dib, 1, libxfs_bmdr_maxrecs(
 				XFS_DFORK_SIZE(dip, mp, whichfork), 0));
 		for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
 			scan_lbtree(get_unaligned_be64(&pp[i]),
@@ -4357,7 +4357,7 @@ scanfunc_bmap(
 			error++;
 			return;
 		}
-		rp = XFS_BMBT_REC_ADDR(mp, block, 1);
+		rp = xfs_bmbt_rec_addr(mp, block, 1);
 		*nex += be16_to_cpu(block->bb_numrecs);
 		process_bmbt_reclist(rp, be16_to_cpu(block->bb_numrecs), type, id, totd,
 			blkmapp);
@@ -4373,7 +4373,7 @@ scanfunc_bmap(
 		error++;
 		return;
 	}
-	pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
+	pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[0]);
 	for (i = 0; i < be16_to_cpu(block->bb_numrecs); i++)
 		scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, type, id,
 					totd, toti, nex, blkmapp, 0, btype);
diff --git a/db/frag.c b/db/frag.c
index 4efc6ad07f8752..1165e824a375e7 100644
--- a/db/frag.c
+++ b/db/frag.c
@@ -243,11 +243,11 @@ process_btinode(
 
 	dib = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
 	if (be16_to_cpu(dib->bb_level) == 0) {
-		xfs_bmbt_rec_t		*rp = XFS_BMDR_REC_ADDR(dib, 1);
+		xfs_bmbt_rec_t		*rp = xfs_bmdr_rec_addr(dib, 1);
 		process_bmbt_reclist(rp, be16_to_cpu(dib->bb_numrecs), extmapp);
 		return;
 	}
-	pp = XFS_BMDR_PTR_ADDR(dib, 1,
+	pp = xfs_bmdr_ptr_addr(dib, 1,
 		libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0));
 	for (i = 0; i < be16_to_cpu(dib->bb_numrecs); i++)
 		scan_lbtree(get_unaligned_be64(&pp[i]),
@@ -437,7 +437,7 @@ scanfunc_bmap(
 				   nrecs, typtab[btype].name);
 			return;
 		}
-		rp = XFS_BMBT_REC_ADDR(mp, block, 1);
+		rp = xfs_bmbt_rec_addr(mp, block, 1);
 		process_bmbt_reclist(rp, nrecs, extmapp);
 		return;
 	}
@@ -447,7 +447,7 @@ scanfunc_bmap(
 			   nrecs, typtab[btype].name);
 		return;
 	}
-	pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[0]);
+	pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[0]);
 	for (i = 0; i < nrecs; i++)
 		scan_lbtree(be64_to_cpu(pp[i]), level, scanfunc_bmap, extmapp,
 									btype);
diff --git a/db/metadump.c b/db/metadump.c
index 424544f9f03224..5c57c1293a53cb 100644
--- a/db/metadump.c
+++ b/db/metadump.c
@@ -249,8 +249,8 @@ zero_btree_node(
 		if (nrecs > mp->m_bmap_dmxr[1])
 			return;
 
-		bkp = XFS_BMBT_KEY_ADDR(mp, block, 1);
-		bpp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+		bkp = xfs_bmbt_key_addr(mp, block, 1);
+		bpp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
 		zp1 = (char *)&bkp[nrecs];
 		zp2 = (char *)&bpp[nrecs];
 		key_end = (char *)bpp;
@@ -315,7 +315,7 @@ zero_btree_leaf(
 		if (nrecs > mp->m_bmap_dmxr[0])
 			return;
 
-		brp = XFS_BMBT_REC_ADDR(mp, block, 1);
+		brp = xfs_bmbt_rec_addr(mp, block, 1);
 		zp = (char *)&brp[nrecs];
 		break;
 	case TYP_INOBT:
@@ -2113,7 +2113,7 @@ scanfunc_bmap(
 					typtab[btype].name, agno, agbno);
 			return 1;
 		}
-		return process_bmbt_reclist(XFS_BMBT_REC_ADDR(mp, block, 1),
+		return process_bmbt_reclist(xfs_bmbt_rec_addr(mp, block, 1),
 					    nrecs, *(typnm_t*)arg);
 	}
 
@@ -2123,7 +2123,7 @@ scanfunc_bmap(
 					nrecs, typtab[btype].name, agno, agbno);
 		return 1;
 	}
-	pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+	pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
 	for (i = 0; i < nrecs; i++) {
 		xfs_agnumber_t	ag;
 		xfs_agblock_t	bno;
@@ -2176,7 +2176,7 @@ process_btinode(
 	}
 
 	if (level == 0) {
-		return process_bmbt_reclist(XFS_BMDR_REC_ADDR(dib, 1),
+		return process_bmbt_reclist(xfs_bmdr_rec_addr(dib, 1),
 					    nrecs, itype);
 	}
 
@@ -2189,13 +2189,13 @@ process_btinode(
 		return 1;
 	}
 
-	pp = XFS_BMDR_PTR_ADDR(dib, 1, maxrecs);
+	pp = xfs_bmdr_ptr_addr(dib, 1, maxrecs);
 
 	if (metadump.zero_stale_data) {
 		char	*top;
 
 		/* Unused btree key space */
-		top = (char*)XFS_BMDR_KEY_ADDR(dib, nrecs + 1);
+		top = (char*)xfs_bmdr_key_addr(dib, nrecs + 1);
 		memset(top, 0, (char*)pp - top);
 
 		/* Unused btree ptr space */
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index ce20d81a486988..97b71b6500bdc9 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -683,7 +683,7 @@ xfs_attr_shortform_bytesfit(
 		 */
 		if (!dp->i_forkoff && dp->i_df.if_bytes >
 		    xfs_default_attroffset(dp))
-			dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
+			dsize = xfs_bmdr_space_calc(MINDBTPTRS);
 		break;
 	case XFS_DINODE_FMT_BTREE:
 		/*
@@ -697,7 +697,7 @@ xfs_attr_shortform_bytesfit(
 				return 0;
 			return dp->i_forkoff;
 		}
-		dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
+		dsize = xfs_bmap_bmdr_space(dp->i_df.if_broot);
 		break;
 	}
 
@@ -705,11 +705,11 @@ xfs_attr_shortform_bytesfit(
 	 * A data fork btree root must have space for at least
 	 * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
 	 */
-	minforkoff = max_t(int64_t, dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
+	minforkoff = max_t(int64_t, dsize, xfs_bmdr_space_calc(MINDBTPTRS));
 	minforkoff = roundup(minforkoff, 8) >> 3;
 
 	/* attr fork btree root can have at least this many key/ptr pairs */
-	maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
+	maxforkoff = XFS_LITINO(mp) - xfs_bmdr_space_calc(MINABTPTRS);
 	maxforkoff = maxforkoff >> 3;	/* rounded down */
 
 	if (offset >= maxforkoff)
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index e2267aa1a11d4e..a85a75da954c4e 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -73,9 +73,9 @@ xfs_bmap_compute_maxlevels(
 	maxleafents = xfs_iext_max_nextents(xfs_has_large_extent_counts(mp),
 				whichfork);
 	if (whichfork == XFS_DATA_FORK)
-		sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
+		sz = xfs_bmdr_space_calc(MINDBTPTRS);
 	else
-		sz = XFS_BMDR_SPACE_CALC(MINABTPTRS);
+		sz = xfs_bmdr_space_calc(MINABTPTRS);
 
 	maxrootrecs = xfs_bmdr_maxrecs(sz, 0);
 	minleafrecs = mp->m_bmap_dmnr[0];
@@ -96,8 +96,8 @@ xfs_bmap_compute_attr_offset(
 	struct xfs_mount	*mp)
 {
 	if (mp->m_sb.sb_inodesize == 256)
-		return XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
-	return XFS_BMDR_SPACE_CALC(6 * MINABTPTRS);
+		return XFS_LITINO(mp) - xfs_bmdr_space_calc(MINABTPTRS);
+	return xfs_bmdr_space_calc(6 * MINABTPTRS);
 }
 
 STATIC int				/* error */
@@ -292,7 +292,7 @@ xfs_check_block(
 	prevp = NULL;
 	for( i = 1; i <= xfs_btree_get_numrecs(block); i++) {
 		dmxr = mp->m_bmap_dmxr[0];
-		keyp = XFS_BMBT_KEY_ADDR(mp, block, i);
+		keyp = xfs_bmbt_key_addr(mp, block, i);
 
 		if (prevp) {
 			ASSERT(be64_to_cpu(prevp->br_startoff) <
@@ -304,15 +304,15 @@ xfs_check_block(
 		 * Compare the block numbers to see if there are dups.
 		 */
 		if (root)
-			pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, i, sz);
+			pp = xfs_bmap_broot_ptr_addr(mp, block, i, sz);
 		else
-			pp = XFS_BMBT_PTR_ADDR(mp, block, i, dmxr);
+			pp = xfs_bmbt_ptr_addr(mp, block, i, dmxr);
 
 		for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) {
 			if (root)
-				thispa = XFS_BMAP_BROOT_PTR_ADDR(mp, block, j, sz);
+				thispa = xfs_bmap_broot_ptr_addr(mp, block, j, sz);
 			else
-				thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr);
+				thispa = xfs_bmbt_ptr_addr(mp, block, j, dmxr);
 			if (*thispa == *pp) {
 				xfs_warn(mp, "%s: thispa(%d) == pp(%d) %lld",
 					__func__, j, i,
@@ -367,7 +367,7 @@ xfs_bmap_check_leaf_extents(
 	level = be16_to_cpu(block->bb_level);
 	ASSERT(level > 0);
 	xfs_check_block(block, mp, 1, ifp->if_broot_bytes);
-	pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes);
+	pp = xfs_bmap_broot_ptr_addr(mp, block, 1, ifp->if_broot_bytes);
 	bno = be64_to_cpu(*pp);
 
 	ASSERT(bno != NULLFSBLOCK);
@@ -400,7 +400,7 @@ xfs_bmap_check_leaf_extents(
 		 */
 
 		xfs_check_block(block, mp, 0, 0);
-		pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+		pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
 		bno = be64_to_cpu(*pp);
 		if (XFS_IS_CORRUPT(mp, !xfs_verify_fsbno(mp, bno))) {
 			xfs_btree_mark_sick(cur);
@@ -440,14 +440,14 @@ xfs_bmap_check_leaf_extents(
 		 * conform with the first entry in this one.
 		 */
 
-		ep = XFS_BMBT_REC_ADDR(mp, block, 1);
+		ep = xfs_bmbt_rec_addr(mp, block, 1);
 		if (i) {
 			ASSERT(xfs_bmbt_disk_get_startoff(&last) +
 			       xfs_bmbt_disk_get_blockcount(&last) <=
 			       xfs_bmbt_disk_get_startoff(ep));
 		}
 		for (j = 1; j < num_recs; j++) {
-			nextp = XFS_BMBT_REC_ADDR(mp, block, j + 1);
+			nextp = xfs_bmbt_rec_addr(mp, block, j + 1);
 			ASSERT(xfs_bmbt_disk_get_startoff(ep) +
 			       xfs_bmbt_disk_get_blockcount(ep) <=
 			       xfs_bmbt_disk_get_startoff(nextp));
@@ -580,7 +580,7 @@ xfs_bmap_btree_to_extents(
 	ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
 	ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1);
 
-	pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes);
+	pp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, ifp->if_broot_bytes);
 	cbno = be64_to_cpu(*pp);
 #ifdef DEBUG
 	if (XFS_IS_CORRUPT(cur->bc_mp, !xfs_verify_fsbno(mp, cbno))) {
@@ -708,7 +708,7 @@ xfs_bmap_extents_to_btree(
 	for_each_xfs_iext(ifp, &icur, &rec) {
 		if (isnullstartblock(rec.br_startblock))
 			continue;
-		arp = XFS_BMBT_REC_ADDR(mp, ablock, 1 + cnt);
+		arp = xfs_bmbt_rec_addr(mp, ablock, 1 + cnt);
 		xfs_bmbt_disk_set_all(arp, &rec);
 		cnt++;
 	}
@@ -718,10 +718,10 @@ xfs_bmap_extents_to_btree(
 	/*
 	 * Fill in the root key and pointer.
 	 */
-	kp = XFS_BMBT_KEY_ADDR(mp, block, 1);
-	arp = XFS_BMBT_REC_ADDR(mp, ablock, 1);
+	kp = xfs_bmbt_key_addr(mp, block, 1);
+	arp = xfs_bmbt_rec_addr(mp, ablock, 1);
 	kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp));
-	pp = XFS_BMBT_PTR_ADDR(mp, block, 1, xfs_bmbt_get_maxrecs(cur,
+	pp = xfs_bmbt_ptr_addr(mp, block, 1, xfs_bmbt_get_maxrecs(cur,
 						be16_to_cpu(block->bb_level)));
 	*pp = cpu_to_be64(args.fsbno);
 
@@ -890,7 +890,7 @@ xfs_bmap_add_attrfork_btree(
 
 	mp = ip->i_mount;
 
-	if (XFS_BMAP_BMDR_SPACE(block) <= xfs_inode_data_fork_size(ip))
+	if (xfs_bmap_bmdr_space(block) <= xfs_inode_data_fork_size(ip))
 		*flags |= XFS_ILOG_DBROOT;
 	else {
 		cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK);
@@ -1154,7 +1154,7 @@ xfs_iread_bmbt_block(
 	}
 
 	/* Copy records into the incore cache. */
-	frp = XFS_BMBT_REC_ADDR(mp, block, 1);
+	frp = xfs_bmbt_rec_addr(mp, block, 1);
 	for (j = 0; j < num_recs; j++, frp++, ir->loaded++) {
 		struct xfs_bmbt_irec	new;
 		xfs_failaddr_t		fa;
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index a14ca35953d735..cac644c8ce35a5 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -64,10 +64,10 @@ xfs_bmdr_to_bmbt(
 	ASSERT(be16_to_cpu(rblock->bb_level) > 0);
 	rblock->bb_numrecs = dblock->bb_numrecs;
 	dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
-	fkp = XFS_BMDR_KEY_ADDR(dblock, 1);
-	tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
-	fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
-	tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
+	fkp = xfs_bmdr_key_addr(dblock, 1);
+	tkp = xfs_bmbt_key_addr(mp, rblock, 1);
+	fpp = xfs_bmdr_ptr_addr(dblock, 1, dmxr);
+	tpp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
 	dmxr = be16_to_cpu(dblock->bb_numrecs);
 	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
 	memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
@@ -167,10 +167,10 @@ xfs_bmbt_to_bmdr(
 	dblock->bb_level = rblock->bb_level;
 	dblock->bb_numrecs = rblock->bb_numrecs;
 	dmxr = xfs_bmdr_maxrecs(dblocklen, 0);
-	fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1);
-	tkp = XFS_BMDR_KEY_ADDR(dblock, 1);
-	fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen);
-	tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr);
+	fkp = xfs_bmbt_key_addr(mp, rblock, 1);
+	tkp = xfs_bmdr_key_addr(dblock, 1);
+	fpp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, rblocklen);
+	tpp = xfs_bmdr_ptr_addr(dblock, 1, dmxr);
 	dmxr = be16_to_cpu(dblock->bb_numrecs);
 	memcpy(tkp, fkp, sizeof(*fkp) * dmxr);
 	memcpy(tpp, fpp, sizeof(*fpp) * dmxr);
@@ -650,7 +650,7 @@ xfs_bmbt_maxrecs(
 	int			blocklen,
 	int			leaf)
 {
-	blocklen -= XFS_BMBT_BLOCK_LEN(mp);
+	blocklen -= xfs_bmbt_block_len(mp);
 	return xfs_bmbt_block_maxrecs(blocklen, leaf);
 }
 
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index de1b73f1225ca7..d006798d591bc2 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -13,70 +13,6 @@ struct xfs_inode;
 struct xfs_trans;
 struct xbtree_ifakeroot;
 
-/*
- * Btree block header size depends on a superblock flag.
- */
-#define XFS_BMBT_BLOCK_LEN(mp) \
-	(xfs_has_crc(((mp))) ? \
-		XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN)
-
-#define XFS_BMBT_REC_ADDR(mp, block, index) \
-	((xfs_bmbt_rec_t *) \
-		((char *)(block) + \
-		 XFS_BMBT_BLOCK_LEN(mp) + \
-		 ((index) - 1) * sizeof(xfs_bmbt_rec_t)))
-
-#define XFS_BMBT_KEY_ADDR(mp, block, index) \
-	((xfs_bmbt_key_t *) \
-		((char *)(block) + \
-		 XFS_BMBT_BLOCK_LEN(mp) + \
-		 ((index) - 1) * sizeof(xfs_bmbt_key_t)))
-
-#define XFS_BMBT_PTR_ADDR(mp, block, index, maxrecs) \
-	((xfs_bmbt_ptr_t *) \
-		((char *)(block) + \
-		 XFS_BMBT_BLOCK_LEN(mp) + \
-		 (maxrecs) * sizeof(xfs_bmbt_key_t) + \
-		 ((index) - 1) * sizeof(xfs_bmbt_ptr_t)))
-
-#define XFS_BMDR_REC_ADDR(block, index) \
-	((xfs_bmdr_rec_t *) \
-		((char *)(block) + \
-		 sizeof(struct xfs_bmdr_block) + \
-	         ((index) - 1) * sizeof(xfs_bmdr_rec_t)))
-
-#define XFS_BMDR_KEY_ADDR(block, index) \
-	((xfs_bmdr_key_t *) \
-		((char *)(block) + \
-		 sizeof(struct xfs_bmdr_block) + \
-		 ((index) - 1) * sizeof(xfs_bmdr_key_t)))
-
-#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \
-	((xfs_bmdr_ptr_t *) \
-		((char *)(block) + \
-		 sizeof(struct xfs_bmdr_block) + \
-		 (maxrecs) * sizeof(xfs_bmdr_key_t) + \
-		 ((index) - 1) * sizeof(xfs_bmdr_ptr_t)))
-
-/*
- * These are to be used when we know the size of the block and
- * we don't have a cursor.
- */
-#define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \
-	XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0))
-
-#define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \
-	(int)(XFS_BMBT_BLOCK_LEN(mp) + \
-	       ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
-
-#define XFS_BMAP_BROOT_SPACE(mp, bb) \
-	(XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs)))
-#define XFS_BMDR_SPACE_CALC(nrecs) \
-	(int)(sizeof(xfs_bmdr_block_t) + \
-	       ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t))))
-#define XFS_BMAP_BMDR_SPACE(bb) \
-	(XFS_BMDR_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs)))
-
 /*
  * Maximum number of bmap btree levels.
  */
@@ -121,4 +57,144 @@ void xfs_bmbt_destroy_cur_cache(void);
 void xfs_bmbt_init_block(struct xfs_inode *ip, struct xfs_btree_block *buf,
 		struct xfs_buf *bp, __u16 level, __u16 numrecs);
 
+/*
+ * Btree block header size depends on a superblock flag.
+ */
+static inline size_t
+xfs_bmbt_block_len(struct xfs_mount *mp)
+{
+	return xfs_has_crc(mp) ?
+			XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN;
+}
+
+/* Addresses of key, pointers, and records within an incore bmbt block. */
+
+static inline struct xfs_bmbt_rec *
+xfs_bmbt_rec_addr(
+	struct xfs_mount	*mp,
+	struct xfs_btree_block	*block,
+	unsigned int		index)
+{
+	return (struct xfs_bmbt_rec *)
+		((char *)block + xfs_bmbt_block_len(mp) +
+		 (index - 1) * sizeof(struct xfs_bmbt_rec));
+}
+
+static inline struct xfs_bmbt_key *
+xfs_bmbt_key_addr(
+	struct xfs_mount	*mp,
+	struct xfs_btree_block	*block,
+	unsigned int		index)
+{
+	return (struct xfs_bmbt_key *)
+		((char *)block + xfs_bmbt_block_len(mp) +
+		 (index - 1) * sizeof(struct xfs_bmbt_key *));
+}
+
+static inline xfs_bmbt_ptr_t *
+xfs_bmbt_ptr_addr(
+	struct xfs_mount	*mp,
+	struct xfs_btree_block	*block,
+	unsigned int		index,
+	unsigned int		maxrecs)
+{
+	return (xfs_bmbt_ptr_t *)
+		((char *)block + xfs_bmbt_block_len(mp) +
+		 maxrecs * sizeof(struct xfs_bmbt_key) +
+		 (index - 1) * sizeof(xfs_bmbt_ptr_t));
+}
+
+/* Addresses of key, pointers, and records within an ondisk bmbt block. */
+
+static inline struct xfs_bmbt_rec *
+xfs_bmdr_rec_addr(
+	struct xfs_bmdr_block	*block,
+	unsigned int		index)
+{
+	return (struct xfs_bmbt_rec *)
+		((char *)(block + 1) +
+		 (index - 1) * sizeof(struct xfs_bmbt_rec));
+}
+
+static inline struct xfs_bmbt_key *
+xfs_bmdr_key_addr(
+	struct xfs_bmdr_block	*block,
+	unsigned int		index)
+{
+	return (struct xfs_bmbt_key *)
+		((char *)(block + 1) +
+		 (index - 1) * sizeof(struct xfs_bmbt_key));
+}
+
+static inline xfs_bmbt_ptr_t *
+xfs_bmdr_ptr_addr(
+	struct xfs_bmdr_block	*block,
+	unsigned int		index,
+	unsigned int		maxrecs)
+{
+	return (xfs_bmbt_ptr_t *)
+		((char *)(block + 1) +
+		 maxrecs * sizeof(struct xfs_bmbt_key) +
+		 (index - 1) * sizeof(xfs_bmbt_ptr_t));
+}
+
+/*
+ * Address of pointers within the incore btree root.
+ *
+ * These are to be used when we know the size of the block and
+ * we don't have a cursor.
+ */
+static inline xfs_bmbt_ptr_t *
+xfs_bmap_broot_ptr_addr(
+	struct xfs_mount	*mp,
+	struct xfs_btree_block	*bb,
+	unsigned int		i,
+	unsigned int		sz)
+{
+	return xfs_bmbt_ptr_addr(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0));
+}
+
+/*
+ * Compute the space required for the incore btree root containing the given
+ * number of records.
+ */
+static inline size_t
+xfs_bmap_broot_space_calc(
+	struct xfs_mount	*mp,
+	unsigned int		nrecs)
+{
+	return xfs_bmbt_block_len(mp) +
+	       (nrecs * (sizeof(struct xfs_bmbt_key) + sizeof(xfs_bmbt_ptr_t)));
+}
+
+/*
+ * Compute the space required for the incore btree root given the ondisk
+ * btree root block.
+ */
+static inline size_t
+xfs_bmap_broot_space(
+	struct xfs_mount	*mp,
+	struct xfs_bmdr_block	*bb)
+{
+	return xfs_bmap_broot_space_calc(mp, be16_to_cpu(bb->bb_numrecs));
+}
+
+/* Compute the space required for the ondisk root block. */
+static inline size_t
+xfs_bmdr_space_calc(unsigned int nrecs)
+{
+	return sizeof(struct xfs_bmdr_block) +
+	       (nrecs * (sizeof(struct xfs_bmbt_key) + sizeof(xfs_bmbt_ptr_t)));
+}
+
+/*
+ * Compute the space required for the ondisk root block given an incore root
+ * block.
+ */
+static inline size_t
+xfs_bmap_bmdr_space(struct xfs_btree_block *bb)
+{
+	return xfs_bmdr_space_calc(be16_to_cpu(bb->bb_numrecs));
+}
+
 #endif	/* __XFS_BMAP_BTREE_H__ */
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index 8f06e5bc72b3ac..fd79da64e43a8d 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -183,7 +183,7 @@ xfs_iformat_btree(
 
 	ifp = xfs_ifork_ptr(ip, whichfork);
 	dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork);
-	size = XFS_BMAP_BROOT_SPACE(mp, dfp);
+	size = xfs_bmap_broot_space(mp, dfp);
 	nrecs = be16_to_cpu(dfp->bb_numrecs);
 	level = be16_to_cpu(dfp->bb_level);
 
@@ -196,7 +196,7 @@ xfs_iformat_btree(
 	 */
 	if (unlikely(ifp->if_nextents <= XFS_IFORK_MAXEXT(ip, whichfork) ||
 		     nrecs == 0 ||
-		     XFS_BMDR_SPACE_CALC(nrecs) >
+		     xfs_bmdr_space_calc(nrecs) >
 					XFS_DFORK_SIZE(dip, mp, whichfork) ||
 		     ifp->if_nextents > ip->i_nblocks) ||
 		     level == 0 || level > XFS_BM_MAXLEVELS(mp, whichfork)) {
@@ -407,7 +407,7 @@ xfs_iroot_realloc(
 		 * allocate it now and get out.
 		 */
 		if (ifp->if_broot_bytes == 0) {
-			new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff);
+			new_size = xfs_bmap_broot_space_calc(mp, rec_diff);
 			ifp->if_broot = kmalloc(new_size,
 						GFP_KERNEL | __GFP_NOFAIL);
 			ifp->if_broot_bytes = (int)new_size;
@@ -422,15 +422,15 @@ xfs_iroot_realloc(
 		 */
 		cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
 		new_max = cur_max + rec_diff;
-		new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
+		new_size = xfs_bmap_broot_space_calc(mp, new_max);
 		ifp->if_broot = krealloc(ifp->if_broot, new_size,
 					 GFP_KERNEL | __GFP_NOFAIL);
-		op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+		op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
 						     ifp->if_broot_bytes);
-		np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+		np = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
 						     (int)new_size);
 		ifp->if_broot_bytes = (int)new_size;
-		ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+		ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
 			xfs_inode_fork_size(ip, whichfork));
 		memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t));
 		return;
@@ -446,7 +446,7 @@ xfs_iroot_realloc(
 	new_max = cur_max + rec_diff;
 	ASSERT(new_max >= 0);
 	if (new_max > 0)
-		new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max);
+		new_size = xfs_bmap_broot_space_calc(mp, new_max);
 	else
 		new_size = 0;
 	if (new_size > 0) {
@@ -455,7 +455,7 @@ xfs_iroot_realloc(
 		 * First copy over the btree block header.
 		 */
 		memcpy(new_broot, ifp->if_broot,
-			XFS_BMBT_BLOCK_LEN(ip->i_mount));
+			xfs_bmbt_block_len(ip->i_mount));
 	} else {
 		new_broot = NULL;
 	}
@@ -467,16 +467,16 @@ xfs_iroot_realloc(
 		/*
 		 * First copy the keys.
 		 */
-		op = (char *)XFS_BMBT_KEY_ADDR(mp, ifp->if_broot, 1);
-		np = (char *)XFS_BMBT_KEY_ADDR(mp, new_broot, 1);
+		op = (char *)xfs_bmbt_key_addr(mp, ifp->if_broot, 1);
+		np = (char *)xfs_bmbt_key_addr(mp, new_broot, 1);
 		memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_key_t));
 
 		/*
 		 * Then copy the pointers.
 		 */
-		op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1,
+		op = (char *)xfs_bmap_broot_ptr_addr(mp, ifp->if_broot, 1,
 						     ifp->if_broot_bytes);
-		np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1,
+		np = (char *)xfs_bmap_broot_ptr_addr(mp, new_broot, 1,
 						     (int)new_size);
 		memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t));
 	}
@@ -484,7 +484,7 @@ xfs_iroot_realloc(
 	ifp->if_broot = new_broot;
 	ifp->if_broot_bytes = (int)new_size;
 	if (ifp->if_broot)
-		ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+		ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
 			xfs_inode_fork_size(ip, whichfork));
 	return;
 }
@@ -653,7 +653,7 @@ xfs_iflush_fork(
 		if ((iip->ili_fields & brootflag[whichfork]) &&
 		    (ifp->if_broot_bytes > 0)) {
 			ASSERT(ifp->if_broot != NULL);
-			ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <=
+			ASSERT(xfs_bmap_bmdr_space(ifp->if_broot) <=
 			        xfs_inode_fork_size(ip, whichfork));
 			xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes,
 				(xfs_bmdr_block_t *)cp,
diff --git a/libxfs/xfs_trans_resv.c b/libxfs/xfs_trans_resv.c
index 156f9578d281a0..3da18fb4027420 100644
--- a/libxfs/xfs_trans_resv.c
+++ b/libxfs/xfs_trans_resv.c
@@ -127,7 +127,7 @@ xfs_calc_inode_res(
 		(4 * sizeof(struct xlog_op_header) +
 		 sizeof(struct xfs_inode_log_format) +
 		 mp->m_sb.sb_inodesize +
-		 2 * XFS_BMBT_BLOCK_LEN(mp));
+		 2 * xfs_bmbt_block_len(mp));
 }
 
 /*
diff --git a/repair/bmap_repair.c b/repair/bmap_repair.c
index 317061aa564f56..b341caf627d5fd 100644
--- a/repair/bmap_repair.c
+++ b/repair/bmap_repair.c
@@ -284,7 +284,7 @@ xrep_bmap_iroot_size(
 {
 	ASSERT(level > 0);
 
-	return XFS_BMAP_BROOT_SPACE_CALC(cur->bc_mp, nr_this_level);
+	return xfs_bmap_broot_space_calc(cur->bc_mp, nr_this_level);
 }
 
 /* Update the inode counters. */
diff --git a/repair/dinode.c b/repair/dinode.c
index aae3cb7a40b981..ac81c487a20b8a 100644
--- a/repair/dinode.c
+++ b/repair/dinode.c
@@ -809,19 +809,19 @@ _("bad numrecs 0 in inode %" PRIu64 " bmap btree root block\n"),
 	/*
 	 * use bmdr/dfork_dsize since the root block is in the data fork
 	 */
-	if (XFS_BMDR_SPACE_CALC(numrecs) > XFS_DFORK_SIZE(dip, mp, whichfork)) {
+	if (xfs_bmdr_space_calc(numrecs) > XFS_DFORK_SIZE(dip, mp, whichfork)) {
 		do_warn(
-	_("indicated size of %s btree root (%d bytes) greater than space in "
+	_("indicated size of %s btree root (%zu bytes) greater than space in "
 	  "inode %" PRIu64 " %s fork\n"),
-			forkname, XFS_BMDR_SPACE_CALC(numrecs), lino, forkname);
+			forkname, xfs_bmdr_space_calc(numrecs), lino, forkname);
 		return(1);
 	}
 
 	init_bm_cursor(&cursor, level + 1);
 
-	pp = XFS_BMDR_PTR_ADDR(dib, 1,
+	pp = xfs_bmdr_ptr_addr(dib, 1,
 		libxfs_bmdr_maxrecs(XFS_DFORK_SIZE(dip, mp, whichfork), 0));
-	pkey = XFS_BMDR_KEY_ADDR(dib, 1);
+	pkey = xfs_bmdr_key_addr(dib, 1);
 	last_key = NULLFILEOFF;
 
 	for (i = 0; i < numrecs; i++)  {
diff --git a/repair/prefetch.c b/repair/prefetch.c
index 22efd54bf9ebf3..998797e3696bac 100644
--- a/repair/prefetch.c
+++ b/repair/prefetch.c
@@ -328,13 +328,13 @@ pf_scanfunc_bmap(
 		if (numrecs > mp->m_bmap_dmxr[0] || !isadir)
 			return 0;
 		return pf_read_bmbt_reclist(args,
-			XFS_BMBT_REC_ADDR(mp, block, 1), numrecs);
+			xfs_bmbt_rec_addr(mp, block, 1), numrecs);
 	}
 
 	if (numrecs > mp->m_bmap_dmxr[1])
 		return 0;
 
-	pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
+	pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
 
 	for (i = 0; i < numrecs; i++) {
 		dbno = get_unaligned_be64(&pp[i]);
@@ -372,11 +372,11 @@ pf_read_btinode(
 	/*
 	 * use bmdr/dfork_dsize since the root block is in the data fork
 	 */
-	if (XFS_BMDR_SPACE_CALC(numrecs) > XFS_DFORK_DSIZE(dino, mp))
+	if (xfs_bmdr_space_calc(numrecs) > XFS_DFORK_DSIZE(dino, mp))
 		return;
 
 	dsize = XFS_DFORK_DSIZE(dino, mp);
-	pp = XFS_BMDR_PTR_ADDR(dib, 1, libxfs_bmdr_maxrecs(dsize, 0));
+	pp = xfs_bmdr_ptr_addr(dib, 1, libxfs_bmdr_maxrecs(dsize, 0));
 
 	for (i = 0; i < numrecs; i++) {
 		dbno = get_unaligned_be64(&pp[i]);
diff --git a/repair/scan.c b/repair/scan.c
index 8352b3ccff7d7e..b115dd4948b969 100644
--- a/repair/scan.c
+++ b/repair/scan.c
@@ -416,7 +416,7 @@ _("inode %" PRIu64 " bad # of bmap records (%" PRIu64 ", min - %u, max - %u)\n")
 					mp->m_bmap_dmxr[0]);
 			return(1);
 		}
-		rp = XFS_BMBT_REC_ADDR(mp, block, 1);
+		rp = xfs_bmbt_rec_addr(mp, block, 1);
 		*nex += numrecs;
 		/*
 		 * XXX - if we were going to fix up the btree record,
@@ -466,8 +466,8 @@ _("inode %" PRIu64 " bad # of bmap records (%" PRIu64 ", min - %u, max - %u)\n")
 			ino, numrecs, mp->m_bmap_dmnr[1], mp->m_bmap_dmxr[1]);
 		return(1);
 	}
-	pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]);
-	pkey = XFS_BMBT_KEY_ADDR(mp, block, 1);
+	pp = xfs_bmbt_ptr_addr(mp, block, 1, mp->m_bmap_dmxr[1]);
+	pkey = xfs_bmbt_key_addr(mp, block, 1);
 
 	last_key = NULLFILEOFF;
 


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

* [PATCH 22/41] xfs: standardize the btree maxrecs function parameters
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (20 preceding siblings ...)
  2024-10-31 23:14   ` [PATCH 21/41] xfs: replace shouty XFS_BM{BT,DR} macros Darrick J. Wong
@ 2024-10-31 23:14   ` Darrick J. Wong
  2024-10-31 23:14   ` [PATCH 23/41] xfs: use kvmalloc for xattr buffers Darrick J. Wong
                     ` (18 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:14 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

Source kernel commit: 411a71256de6f5a0015a28929cfbe6bc36c503dc

Standardize the parameters in xfs_{alloc,bm,ino,rmap,refcount}bt_maxrecs
so that we have consistent calling conventions.  This doesn't affect the
kernel that much, but enables us to clean up userspace a bit.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/btheight.c               |   18 ++++--------------
 libxfs/xfs_alloc_btree.c    |    6 +++---
 libxfs/xfs_alloc_btree.h    |    3 ++-
 libxfs/xfs_bmap.c           |    2 +-
 libxfs/xfs_bmap_btree.c     |    6 +++---
 libxfs/xfs_bmap_btree.h     |    5 +++--
 libxfs/xfs_ialloc.c         |    4 ++--
 libxfs/xfs_ialloc_btree.c   |    6 +++---
 libxfs/xfs_ialloc_btree.h   |    3 ++-
 libxfs/xfs_inode_fork.c     |    4 ++--
 libxfs/xfs_refcount_btree.c |    5 +++--
 libxfs/xfs_refcount_btree.h |    3 ++-
 libxfs/xfs_rmap_btree.c     |    7 ++++---
 libxfs/xfs_rmap_btree.h     |    3 ++-
 libxfs/xfs_sb.c             |   16 ++++++++--------
 repair/phase5.c             |   16 ++++++++--------
 16 files changed, 52 insertions(+), 55 deletions(-)


diff --git a/db/btheight.c b/db/btheight.c
index 0b421ab50a3a76..6643489c82c4c9 100644
--- a/db/btheight.c
+++ b/db/btheight.c
@@ -12,21 +12,11 @@
 #include "input.h"
 #include "libfrog/convert.h"
 
-static int refc_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
-{
-	return libxfs_refcountbt_maxrecs(blocklen, leaf != 0);
-}
-
-static int rmap_maxrecs(struct xfs_mount *mp, int blocklen, int leaf)
-{
-	return libxfs_rmapbt_maxrecs(blocklen, leaf);
-}
-
 struct btmap {
 	const char	*tag;
 	unsigned int	(*maxlevels)(void);
-	int		(*maxrecs)(struct xfs_mount *mp, int blocklen,
-				   int leaf);
+	unsigned int	(*maxrecs)(struct xfs_mount *mp, unsigned int blocklen,
+				   bool leaf);
 } maps[] = {
 	{
 		.tag		= "bnobt",
@@ -56,12 +46,12 @@ struct btmap {
 	{
 		.tag		= "refcountbt",
 		.maxlevels	= libxfs_refcountbt_maxlevels_ondisk,
-		.maxrecs	= refc_maxrecs,
+		.maxrecs	= libxfs_refcountbt_maxrecs,
 	},
 	{
 		.tag		= "rmapbt",
 		.maxlevels	= libxfs_rmapbt_maxlevels_ondisk,
-		.maxrecs	= rmap_maxrecs,
+		.maxrecs	= libxfs_rmapbt_maxrecs,
 	},
 };
 
diff --git a/libxfs/xfs_alloc_btree.c b/libxfs/xfs_alloc_btree.c
index 9140dec00645f0..4a711f2463cd30 100644
--- a/libxfs/xfs_alloc_btree.c
+++ b/libxfs/xfs_alloc_btree.c
@@ -567,11 +567,11 @@ xfs_allocbt_block_maxrecs(
 /*
  * Calculate number of records in an alloc btree block.
  */
-int
+unsigned int
 xfs_allocbt_maxrecs(
 	struct xfs_mount	*mp,
-	int			blocklen,
-	int			leaf)
+	unsigned int		blocklen,
+	bool			leaf)
 {
 	blocklen -= XFS_ALLOC_BLOCK_LEN(mp);
 	return xfs_allocbt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_alloc_btree.h b/libxfs/xfs_alloc_btree.h
index 155b47f231ab2f..12647f9aaa6d79 100644
--- a/libxfs/xfs_alloc_btree.h
+++ b/libxfs/xfs_alloc_btree.h
@@ -53,7 +53,8 @@ struct xfs_btree_cur *xfs_bnobt_init_cursor(struct xfs_mount *mp,
 struct xfs_btree_cur *xfs_cntbt_init_cursor(struct xfs_mount *mp,
 		struct xfs_trans *tp, struct xfs_buf *bp,
 		struct xfs_perag *pag);
-extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int);
+unsigned int xfs_allocbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+		bool leaf);
 extern xfs_extlen_t xfs_allocbt_calc_size(struct xfs_mount *mp,
 		unsigned long long len);
 
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index a85a75da954c4e..4ee8d9b07a0ca7 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -578,7 +578,7 @@ xfs_bmap_btree_to_extents(
 	ASSERT(ifp->if_format == XFS_DINODE_FMT_BTREE);
 	ASSERT(be16_to_cpu(rblock->bb_level) == 1);
 	ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1);
-	ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1);
+	ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false) == 1);
 
 	pp = xfs_bmap_broot_ptr_addr(mp, rblock, 1, ifp->if_broot_bytes);
 	cbno = be64_to_cpu(*pp);
diff --git a/libxfs/xfs_bmap_btree.c b/libxfs/xfs_bmap_btree.c
index cac644c8ce35a5..62e79d8fc49784 100644
--- a/libxfs/xfs_bmap_btree.c
+++ b/libxfs/xfs_bmap_btree.c
@@ -644,11 +644,11 @@ xfs_bmbt_commit_staged_btree(
 /*
  * Calculate number of records in a bmap btree block.
  */
-int
+unsigned int
 xfs_bmbt_maxrecs(
 	struct xfs_mount	*mp,
-	int			blocklen,
-	int			leaf)
+	unsigned int		blocklen,
+	bool			leaf)
 {
 	blocklen -= xfs_bmbt_block_len(mp);
 	return xfs_bmbt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_bmap_btree.h b/libxfs/xfs_bmap_btree.h
index d006798d591bc2..49a3bae3f6ecec 100644
--- a/libxfs/xfs_bmap_btree.h
+++ b/libxfs/xfs_bmap_btree.h
@@ -35,7 +35,8 @@ extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int,
 
 extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level);
 extern int xfs_bmdr_maxrecs(int blocklen, int leaf);
-extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf);
+unsigned int xfs_bmbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+		bool leaf);
 
 extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip,
 				 int whichfork, xfs_ino_t new_owner,
@@ -151,7 +152,7 @@ xfs_bmap_broot_ptr_addr(
 	unsigned int		i,
 	unsigned int		sz)
 {
-	return xfs_bmbt_ptr_addr(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0));
+	return xfs_bmbt_ptr_addr(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, false));
 }
 
 /*
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 83e3d7d7c5a1b3..141b2d397b1fe7 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -2943,8 +2943,8 @@ xfs_ialloc_setup_geometry(
 
 	/* Compute inode btree geometry. */
 	igeo->agino_log = sbp->sb_inopblog + sbp->sb_agblklog;
-	igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1);
-	igeo->inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0);
+	igeo->inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, true);
+	igeo->inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, false);
 	igeo->inobt_mnr[0] = igeo->inobt_mxr[0] / 2;
 	igeo->inobt_mnr[1] = igeo->inobt_mxr[1] / 2;
 
diff --git a/libxfs/xfs_ialloc_btree.c b/libxfs/xfs_ialloc_btree.c
index 489c080fb22d05..ffca4a80219d6d 100644
--- a/libxfs/xfs_ialloc_btree.c
+++ b/libxfs/xfs_ialloc_btree.c
@@ -571,11 +571,11 @@ xfs_inobt_block_maxrecs(
 /*
  * Calculate number of records in an inobt btree block.
  */
-int
+unsigned int
 xfs_inobt_maxrecs(
 	struct xfs_mount	*mp,
-	int			blocklen,
-	int			leaf)
+	unsigned int		blocklen,
+	bool			leaf)
 {
 	blocklen -= XFS_INOBT_BLOCK_LEN(mp);
 	return xfs_inobt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_ialloc_btree.h b/libxfs/xfs_ialloc_btree.h
index 6472ec1ecbb458..300edf5bc00949 100644
--- a/libxfs/xfs_ialloc_btree.h
+++ b/libxfs/xfs_ialloc_btree.h
@@ -50,7 +50,8 @@ struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_perag *pag,
 		struct xfs_trans *tp, struct xfs_buf *agbp);
 struct xfs_btree_cur *xfs_finobt_init_cursor(struct xfs_perag *pag,
 		struct xfs_trans *tp, struct xfs_buf *agbp);
-extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int);
+unsigned int xfs_inobt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+		bool leaf);
 
 /* ir_holemask to inode allocation bitmap conversion */
 uint64_t xfs_inobt_irec_to_allocmask(const struct xfs_inobt_rec_incore *irec);
diff --git a/libxfs/xfs_inode_fork.c b/libxfs/xfs_inode_fork.c
index fd79da64e43a8d..a71a5e98bf408b 100644
--- a/libxfs/xfs_inode_fork.c
+++ b/libxfs/xfs_inode_fork.c
@@ -420,7 +420,7 @@ xfs_iroot_realloc(
 		 * location.  The records don't change location because
 		 * they are kept butted up against the btree block header.
 		 */
-		cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
+		cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false);
 		new_max = cur_max + rec_diff;
 		new_size = xfs_bmap_broot_space_calc(mp, new_max);
 		ifp->if_broot = krealloc(ifp->if_broot, new_size,
@@ -442,7 +442,7 @@ xfs_iroot_realloc(
 	 * records, just get rid of the root and clear the status bit.
 	 */
 	ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0));
-	cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0);
+	cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, false);
 	new_max = cur_max + rec_diff;
 	ASSERT(new_max >= 0);
 	if (new_max > 0)
diff --git a/libxfs/xfs_refcount_btree.c b/libxfs/xfs_refcount_btree.c
index 162f9e6896a590..9028dea06b0c07 100644
--- a/libxfs/xfs_refcount_btree.c
+++ b/libxfs/xfs_refcount_btree.c
@@ -416,9 +416,10 @@ xfs_refcountbt_block_maxrecs(
 /*
  * Calculate the number of records in a refcount btree block.
  */
-int
+unsigned int
 xfs_refcountbt_maxrecs(
-	int			blocklen,
+	struct xfs_mount	*mp,
+	unsigned int		blocklen,
 	bool			leaf)
 {
 	blocklen -= XFS_REFCOUNT_BLOCK_LEN;
diff --git a/libxfs/xfs_refcount_btree.h b/libxfs/xfs_refcount_btree.h
index 1e0ab25f6c6808..beb93bef6a8141 100644
--- a/libxfs/xfs_refcount_btree.h
+++ b/libxfs/xfs_refcount_btree.h
@@ -48,7 +48,8 @@ struct xbtree_afakeroot;
 extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp,
 		struct xfs_trans *tp, struct xfs_buf *agbp,
 		struct xfs_perag *pag);
-extern int xfs_refcountbt_maxrecs(int blocklen, bool leaf);
+unsigned int xfs_refcountbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+		bool leaf);
 extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp);
 
 extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp,
diff --git a/libxfs/xfs_rmap_btree.c b/libxfs/xfs_rmap_btree.c
index f1732b72d13db1..ada58e92645020 100644
--- a/libxfs/xfs_rmap_btree.c
+++ b/libxfs/xfs_rmap_btree.c
@@ -730,10 +730,11 @@ xfs_rmapbt_block_maxrecs(
 /*
  * Calculate number of records in an rmap btree block.
  */
-int
+unsigned int
 xfs_rmapbt_maxrecs(
-	int			blocklen,
-	int			leaf)
+	struct xfs_mount	*mp,
+	unsigned int		blocklen,
+	bool			leaf)
 {
 	blocklen -= XFS_RMAP_BLOCK_LEN;
 	return xfs_rmapbt_block_maxrecs(blocklen, leaf);
diff --git a/libxfs/xfs_rmap_btree.h b/libxfs/xfs_rmap_btree.h
index eb90d89e808666..119b1567cd0ee8 100644
--- a/libxfs/xfs_rmap_btree.h
+++ b/libxfs/xfs_rmap_btree.h
@@ -47,7 +47,8 @@ struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp,
 				struct xfs_perag *pag);
 void xfs_rmapbt_commit_staged_btree(struct xfs_btree_cur *cur,
 		struct xfs_trans *tp, struct xfs_buf *agbp);
-int xfs_rmapbt_maxrecs(int blocklen, int leaf);
+unsigned int xfs_rmapbt_maxrecs(struct xfs_mount *mp, unsigned int blocklen,
+		bool leaf);
 extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp);
 
 extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp,
diff --git a/libxfs/xfs_sb.c b/libxfs/xfs_sb.c
index 5f7ff4fa4e49b1..0603e5087f2e46 100644
--- a/libxfs/xfs_sb.c
+++ b/libxfs/xfs_sb.c
@@ -997,23 +997,23 @@ xfs_sb_mount_common(
 	mp->m_blockwmask = mp->m_blockwsize - 1;
 	xfs_mount_sb_set_rextsize(mp, sbp);
 
-	mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1);
-	mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0);
+	mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, true);
+	mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, false);
 	mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2;
 	mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2;
 
-	mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1);
-	mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0);
+	mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, true);
+	mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, false);
 	mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2;
 	mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2;
 
-	mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(sbp->sb_blocksize, 1);
-	mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(sbp->sb_blocksize, 0);
+	mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, true);
+	mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, false);
 	mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2;
 	mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2;
 
-	mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(sbp->sb_blocksize, true);
-	mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(sbp->sb_blocksize, false);
+	mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, true);
+	mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, false);
 	mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2;
 	mp->m_refc_mnr[1] = mp->m_refc_mxr[1] / 2;
 
diff --git a/repair/phase5.c b/repair/phase5.c
index 52666ad8823312..d18ec095b0524b 100644
--- a/repair/phase5.c
+++ b/repair/phase5.c
@@ -641,21 +641,21 @@ phase5(xfs_mount_t *mp)
 
 #ifdef XR_BLD_FREE_TRACE
 	fprintf(stderr, "inobt level 1, maxrec = %d, minrec = %d\n",
-		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0),
-		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2);
+		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, false),
+		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, false) / 2);
 	fprintf(stderr, "inobt level 0 (leaf), maxrec = %d, minrec = %d\n",
-		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1),
-		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2);
+		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, true),
+		libxfs_inobt_maxrecs(mp, mp->m_sb.sb_blocksize, true) / 2);
 	fprintf(stderr, "xr inobt level 0 (leaf), maxrec = %d\n",
 		XR_INOBT_BLOCK_MAXRECS(mp, 0));
 	fprintf(stderr, "xr inobt level 1 (int), maxrec = %d\n",
 		XR_INOBT_BLOCK_MAXRECS(mp, 1));
 	fprintf(stderr, "bnobt level 1, maxrec = %d, minrec = %d\n",
-		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0),
-		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 0) / 2);
+		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, false),
+		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, false) / 2);
 	fprintf(stderr, "bnobt level 0 (leaf), maxrec = %d, minrec = %d\n",
-		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1),
-		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, 1) / 2);
+		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, true),
+		libxfs_allocbt_maxrecs(mp, mp->m_sb.sb_blocksize, true) / 2);
 #endif
 	/*
 	 * make sure the root and realtime inodes show up allocated


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

* [PATCH 23/41] xfs: use kvmalloc for xattr buffers
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (21 preceding siblings ...)
  2024-10-31 23:14   ` [PATCH 22/41] xfs: standardize the btree maxrecs function parameters Darrick J. Wong
@ 2024-10-31 23:14   ` Darrick J. Wong
  2024-10-31 23:14   ` [PATCH 24/41] xfs: remove unnecessary check Darrick J. Wong
                     ` (17 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:14 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Dave Chinner <dchinner@redhat.com>

Source kernel commit: de631e1a8b71017b8a12b57d07db82e4052555af

Pankaj Raghav reported that when filesystem block size is larger
than page size, the xattr code can use kmalloc() for high order
allocations. This triggers a useless warning in the allocator as it
is a __GFP_NOFAIL allocation here:

static inline
struct page *rmqueue(struct zone *preferred_zone,
struct zone *zone, unsigned int order,
gfp_t gfp_flags, unsigned int alloc_flags,
int migratetype)
{
struct page *page;

/*
* We most definitely don't want callers attempting to
* allocate greater than order-1 page units with __GFP_NOFAIL.
*/
>>>>    WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1));
...

Fix this by changing all these call sites to use kvmalloc(), which
will strip the NOFAIL from the kmalloc attempt and if that fails
will do a __GFP_NOFAIL vmalloc().

This is not an issue that productions systems will see as
filesystems with block size > page size cannot be mounted by the
kernel; Pankaj is developing this functionality right now.

Reported-by: Pankaj Raghav <kernel@pankajraghav.com>
Fixes: f078d4ea8276 ("xfs: convert kmem_alloc() to kmalloc()")
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Link: https://lore.kernel.org/r/20240822135018.1931258-8-kernel@pankajraghav.com
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Pankaj Raghav <p.raghav@samsung.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Acked-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Daniel Gomez <da.gomez@samsung.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
 include/kmem.h         |    6 ++++++
 libxfs/xfs_attr_leaf.c |   15 ++++++---------
 2 files changed, 12 insertions(+), 9 deletions(-)


diff --git a/include/kmem.h b/include/kmem.h
index 8dfb2fb0b45020..8739d824008e2a 100644
--- a/include/kmem.h
+++ b/include/kmem.h
@@ -59,12 +59,18 @@ static inline void *kmalloc(size_t size, gfp_t flags)
 }
 
 #define kzalloc(size, gfp)	kvmalloc((size), (gfp) | __GFP_ZERO)
+#define kvzalloc(size, gfp)	kzalloc((size), (gfp))
 
 static inline void kfree(const void *ptr)
 {
 	free((void *)ptr);
 }
 
+static inline void kvfree(const void *ptr)
+{
+	kfree(ptr);
+}
+
 __attribute__((format(printf,2,3)))
 char *kasprintf(gfp_t gfp, const char *fmt, ...);
 
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 97b71b6500bdc9..db2e48d719d36f 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -1135,10 +1135,7 @@ xfs_attr3_leaf_to_shortform(
 
 	trace_xfs_attr_leaf_to_sf(args);
 
-	tmpbuffer = kmalloc(args->geo->blksize, GFP_KERNEL | __GFP_NOFAIL);
-	if (!tmpbuffer)
-		return -ENOMEM;
-
+	tmpbuffer = kvmalloc(args->geo->blksize, GFP_KERNEL | __GFP_NOFAIL);
 	memcpy(tmpbuffer, bp->b_addr, args->geo->blksize);
 
 	leaf = (xfs_attr_leafblock_t *)tmpbuffer;
@@ -1202,7 +1199,7 @@ xfs_attr3_leaf_to_shortform(
 	error = 0;
 
 out:
-	kfree(tmpbuffer);
+	kvfree(tmpbuffer);
 	return error;
 }
 
@@ -1610,7 +1607,7 @@ xfs_attr3_leaf_compact(
 
 	trace_xfs_attr_leaf_compact(args);
 
-	tmpbuffer = kmalloc(args->geo->blksize, GFP_KERNEL | __GFP_NOFAIL);
+	tmpbuffer = kvmalloc(args->geo->blksize, GFP_KERNEL | __GFP_NOFAIL);
 	memcpy(tmpbuffer, bp->b_addr, args->geo->blksize);
 	memset(bp->b_addr, 0, args->geo->blksize);
 	leaf_src = (xfs_attr_leafblock_t *)tmpbuffer;
@@ -1648,7 +1645,7 @@ xfs_attr3_leaf_compact(
 	 */
 	xfs_trans_log_buf(trans, bp, 0, args->geo->blksize - 1);
 
-	kfree(tmpbuffer);
+	kvfree(tmpbuffer);
 }
 
 /*
@@ -2327,7 +2324,7 @@ xfs_attr3_leaf_unbalance(
 		struct xfs_attr_leafblock *tmp_leaf;
 		struct xfs_attr3_icleaf_hdr tmphdr;
 
-		tmp_leaf = kzalloc(state->args->geo->blksize,
+		tmp_leaf = kvzalloc(state->args->geo->blksize,
 				GFP_KERNEL | __GFP_NOFAIL);
 
 		/*
@@ -2368,7 +2365,7 @@ xfs_attr3_leaf_unbalance(
 		}
 		memcpy(save_leaf, tmp_leaf, state->args->geo->blksize);
 		savehdr = tmphdr; /* struct copy */
-		kfree(tmp_leaf);
+		kvfree(tmp_leaf);
 	}
 
 	xfs_attr3_leaf_hdr_to_disk(state->args->geo, save_leaf, &savehdr);


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

* [PATCH 24/41] xfs: remove unnecessary check
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (22 preceding siblings ...)
  2024-10-31 23:14   ` [PATCH 23/41] xfs: use kvmalloc for xattr buffers Darrick J. Wong
@ 2024-10-31 23:14   ` Darrick J. Wong
  2024-10-31 23:15   ` [PATCH 25/41] xfs: use kfree_rcu_mightsleep to free the perag structures Darrick J. Wong
                     ` (16 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:14 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Dan Carpenter <dan.carpenter@linaro.org>

Source kernel commit: fb8b941c75bd70ddfb0a8a3bb9bb770ed1d648f8

We checked that "pip" is non-NULL at the start of the if else statement
so there is no need to check again here.  Delete the check.

Signed-off-by: Dan Carpenter <dan.carpenter@linaro.org>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
---
 libxfs/xfs_inode_util.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


diff --git a/libxfs/xfs_inode_util.c b/libxfs/xfs_inode_util.c
index 74d2b5960bf0f2..92bfdf0715f02e 100644
--- a/libxfs/xfs_inode_util.c
+++ b/libxfs/xfs_inode_util.c
@@ -305,7 +305,7 @@ xfs_inode_init(
 		    !vfsgid_in_group_p(i_gid_into_vfsgid(args->idmap, inode)))
 			inode->i_mode &= ~S_ISGID;
 
-		ip->i_projid = pip ? xfs_get_initial_prid(pip) : 0;
+		ip->i_projid = xfs_get_initial_prid(pip);
 	}
 
 	ip->i_disk_size = 0;


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

* [PATCH 25/41] xfs: use kfree_rcu_mightsleep to free the perag structures
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (23 preceding siblings ...)
  2024-10-31 23:14   ` [PATCH 24/41] xfs: remove unnecessary check Darrick J. Wong
@ 2024-10-31 23:15   ` Darrick J. Wong
  2024-10-31 23:15   ` [PATCH 26/41] xfs: move the tagged perag lookup helpers to xfs_icache.c Darrick J. Wong
                     ` (15 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:15 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 4ef7c6d39dc72dae983b836c8b2b5de7128c0da3

Using the kfree_rcu_mightsleep is simpler and removes the need for a
rcu_head in the perag structure.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
---
 include/kmem.h  |    5 +++++
 libxfs/xfs_ag.c |   12 +-----------
 libxfs/xfs_ag.h |    3 ---
 3 files changed, 6 insertions(+), 14 deletions(-)


diff --git a/include/kmem.h b/include/kmem.h
index 8739d824008e2a..16a7957f1acee3 100644
--- a/include/kmem.h
+++ b/include/kmem.h
@@ -71,6 +71,11 @@ static inline void kvfree(const void *ptr)
 	kfree(ptr);
 }
 
+static inline void kfree_rcu_mightsleep(const void *ptr)
+{
+	kfree(ptr);
+}
+
 __attribute__((format(printf,2,3)))
 char *kasprintf(gfp_t gfp, const char *fmt, ...);
 
diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index ed9ac7f58d1aba..1b65ba983ad542 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -233,16 +233,6 @@ xfs_initialize_perag_data(
 	return error;
 }
 
-STATIC void
-__xfs_free_perag(
-	struct rcu_head	*head)
-{
-	struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head);
-
-	ASSERT(!delayed_work_pending(&pag->pag_blockgc_work));
-	kfree(pag);
-}
-
 /*
  * Free up the per-ag resources associated with the mount structure.
  */
@@ -268,7 +258,7 @@ xfs_free_perag(
 		xfs_perag_rele(pag);
 		XFS_IS_CORRUPT(pag->pag_mount,
 				atomic_read(&pag->pag_active_ref) != 0);
-		call_rcu(&pag->rcu_head, __xfs_free_perag);
+		kfree_rcu_mightsleep(pag);
 	}
 }
 
diff --git a/libxfs/xfs_ag.h b/libxfs/xfs_ag.h
index 35de09a2516c70..d62c266c0b44d5 100644
--- a/libxfs/xfs_ag.h
+++ b/libxfs/xfs_ag.h
@@ -63,9 +63,6 @@ struct xfs_perag {
 	/* Blocks reserved for the reverse mapping btree. */
 	struct xfs_ag_resv	pag_rmapbt_resv;
 
-	/* for rcu-safe freeing */
-	struct rcu_head	rcu_head;
-
 	/* Precalculated geometry info */
 	xfs_agblock_t		block_count;
 	xfs_agblock_t		min_block;


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

* [PATCH 26/41] xfs: move the tagged perag lookup helpers to xfs_icache.c
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (24 preceding siblings ...)
  2024-10-31 23:15   ` [PATCH 25/41] xfs: use kfree_rcu_mightsleep to free the perag structures Darrick J. Wong
@ 2024-10-31 23:15   ` Darrick J. Wong
  2024-10-31 23:15   ` [PATCH 27/41] xfs: convert perag lookup to xarray Darrick J. Wong
                     ` (14 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:15 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: f48f0a8e00b67028d4492e7656b346fa0d806570

The tagged perag helpers are only used in xfs_icache.c in the kernel code
and not at all in xfsprogs.  Move them to xfs_icache.c in preparation for
switching to an xarray, for which I have no plan to implement the tagged
lookup functions for userspace.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
---
 libxfs/xfs_ag.c |   51 ---------------------------------------------------
 libxfs/xfs_ag.h |   11 -----------
 2 files changed, 62 deletions(-)


diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index 1b65ba983ad542..a63d9c0dc6fe44 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -54,31 +54,6 @@ xfs_perag_get(
 	return pag;
 }
 
-/*
- * search from @first to find the next perag with the given tag set.
- */
-struct xfs_perag *
-xfs_perag_get_tag(
-	struct xfs_mount	*mp,
-	xfs_agnumber_t		first,
-	unsigned int		tag)
-{
-	struct xfs_perag	*pag;
-	int			found;
-
-	rcu_read_lock();
-	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
-					(void **)&pag, first, 1, tag);
-	if (found <= 0) {
-		rcu_read_unlock();
-		return NULL;
-	}
-	trace_xfs_perag_get_tag(pag, _RET_IP_);
-	atomic_inc(&pag->pag_ref);
-	rcu_read_unlock();
-	return pag;
-}
-
 /* Get a passive reference to the given perag. */
 struct xfs_perag *
 xfs_perag_hold(
@@ -125,32 +100,6 @@ xfs_perag_grab(
 	return pag;
 }
 
-/*
- * search from @first to find the next perag with the given tag set.
- */
-struct xfs_perag *
-xfs_perag_grab_tag(
-	struct xfs_mount	*mp,
-	xfs_agnumber_t		first,
-	int			tag)
-{
-	struct xfs_perag	*pag;
-	int			found;
-
-	rcu_read_lock();
-	found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
-					(void **)&pag, first, 1, tag);
-	if (found <= 0) {
-		rcu_read_unlock();
-		return NULL;
-	}
-	trace_xfs_perag_grab_tag(pag, _RET_IP_);
-	if (!atomic_inc_not_zero(&pag->pag_active_ref))
-		pag = NULL;
-	rcu_read_unlock();
-	return pag;
-}
-
 void
 xfs_perag_rele(
 	struct xfs_perag	*pag)
diff --git a/libxfs/xfs_ag.h b/libxfs/xfs_ag.h
index d62c266c0b44d5..d9cccd093b60e0 100644
--- a/libxfs/xfs_ag.h
+++ b/libxfs/xfs_ag.h
@@ -153,15 +153,11 @@ void xfs_free_perag(struct xfs_mount *mp);
 
 /* Passive AG references */
 struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);
-struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *mp, xfs_agnumber_t agno,
-		unsigned int tag);
 struct xfs_perag *xfs_perag_hold(struct xfs_perag *pag);
 void xfs_perag_put(struct xfs_perag *pag);
 
 /* Active AG references */
 struct xfs_perag *xfs_perag_grab(struct xfs_mount *, xfs_agnumber_t);
-struct xfs_perag *xfs_perag_grab_tag(struct xfs_mount *, xfs_agnumber_t,
-				   int tag);
 void xfs_perag_rele(struct xfs_perag *pag);
 
 /*
@@ -263,13 +259,6 @@ xfs_perag_next(
 	(agno) = 0; \
 	for_each_perag_from((mp), (agno), (pag))
 
-#define for_each_perag_tag(mp, agno, pag, tag) \
-	for ((agno) = 0, (pag) = xfs_perag_grab_tag((mp), 0, (tag)); \
-		(pag) != NULL; \
-		(agno) = (pag)->pag_agno + 1, \
-		xfs_perag_rele(pag), \
-		(pag) = xfs_perag_grab_tag((mp), (agno), (tag)))
-
 static inline struct xfs_perag *
 xfs_perag_next_wrap(
 	struct xfs_perag	*pag,


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

* [PATCH 27/41] xfs: convert perag lookup to xarray
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (25 preceding siblings ...)
  2024-10-31 23:15   ` [PATCH 26/41] xfs: move the tagged perag lookup helpers to xfs_icache.c Darrick J. Wong
@ 2024-10-31 23:15   ` Darrick J. Wong
  2024-10-31 23:15   ` [PATCH 28/41] xfs: ensure st_blocks never goes to zero during COW writes Darrick J. Wong
                     ` (13 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:15 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 32fa4059fe6776d7db1e9058f360e06b36c9f2ce

Convert the perag lookup from the legacy radix tree to the xarray,
which allows for much nicer iteration and bulk lookup semantics.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
---
 include/xfs_mount.h |    2 +-
 libxfs/init.c       |    2 +-
 libxfs/xfs_ag.c     |   31 ++++++++-----------------------
 3 files changed, 10 insertions(+), 25 deletions(-)


diff --git a/include/xfs_mount.h b/include/xfs_mount.h
index 7571df12fba3f8..e2add8a648f887 100644
--- a/include/xfs_mount.h
+++ b/include/xfs_mount.h
@@ -91,7 +91,7 @@ typedef struct xfs_mount {
 	xfs_extlen_t		m_ag_prealloc_blocks; /* reserved ag blocks */
 	uint			m_alloc_set_aside; /* space we can't use */
 	uint			m_ag_max_usable; /* max space per AG */
-	struct radix_tree_root	m_perag_tree;
+	struct xarray		m_perags;
 	uint64_t		m_features;	/* active filesystem features */
 	uint64_t		m_low_space[XFS_LOWSP_MAX];
 	uint64_t		m_rtxblkmask;	/* rt extent block mask */
diff --git a/libxfs/init.c b/libxfs/init.c
index 6ab5ef54bb69cb..1e45f091dbb5bf 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -662,7 +662,7 @@ libxfs_mount(
 	mp->m_finobt_nores = true;
 	xfs_set_inode32(mp);
 	mp->m_sb = *sb;
-	INIT_RADIX_TREE(&mp->m_perag_tree, GFP_KERNEL);
+	xa_init(&mp->m_perags);
 	sbp = &mp->m_sb;
 	spin_lock_init(&mp->m_sb_lock);
 	spin_lock_init(&mp->m_agirotor_lock);
diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index a63d9c0dc6fe44..516c76790cc0d8 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -44,7 +44,7 @@ xfs_perag_get(
 	struct xfs_perag	*pag;
 
 	rcu_read_lock();
-	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
+	pag = xa_load(&mp->m_perags, agno);
 	if (pag) {
 		trace_xfs_perag_get(pag, _RET_IP_);
 		ASSERT(atomic_read(&pag->pag_ref) >= 0);
@@ -90,7 +90,7 @@ xfs_perag_grab(
 	struct xfs_perag	*pag;
 
 	rcu_read_lock();
-	pag = radix_tree_lookup(&mp->m_perag_tree, agno);
+	pag = xa_load(&mp->m_perags, agno);
 	if (pag) {
 		trace_xfs_perag_grab(pag, _RET_IP_);
 		if (!atomic_inc_not_zero(&pag->pag_active_ref))
@@ -193,9 +193,7 @@ xfs_free_perag(
 	xfs_agnumber_t		agno;
 
 	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		spin_lock(&mp->m_perag_lock);
-		pag = radix_tree_delete(&mp->m_perag_tree, agno);
-		spin_unlock(&mp->m_perag_lock);
+		pag = xa_erase(&mp->m_perags, agno);
 		ASSERT(pag);
 		XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
 		xfs_defer_drain_free(&pag->pag_intents_drain);
@@ -284,9 +282,7 @@ xfs_free_unused_perag_range(
 	xfs_agnumber_t		index;
 
 	for (index = agstart; index < agend; index++) {
-		spin_lock(&mp->m_perag_lock);
-		pag = radix_tree_delete(&mp->m_perag_tree, index);
-		spin_unlock(&mp->m_perag_lock);
+		pag = xa_erase(&mp->m_perags, index);
 		if (!pag)
 			break;
 		xfs_buf_cache_destroy(&pag->pag_bcache);
@@ -327,20 +323,11 @@ xfs_initialize_perag(
 		pag->pag_agno = index;
 		pag->pag_mount = mp;
 
-		error = radix_tree_preload(GFP_KERNEL | __GFP_RETRY_MAYFAIL);
-		if (error)
-			goto out_free_pag;
-
-		spin_lock(&mp->m_perag_lock);
-		if (radix_tree_insert(&mp->m_perag_tree, index, pag)) {
-			WARN_ON_ONCE(1);
-			spin_unlock(&mp->m_perag_lock);
-			radix_tree_preload_end();
-			error = -EEXIST;
+		error = xa_insert(&mp->m_perags, index, pag, GFP_KERNEL);
+		if (error) {
+			WARN_ON_ONCE(error == -EBUSY);
 			goto out_free_pag;
 		}
-		spin_unlock(&mp->m_perag_lock);
-		radix_tree_preload_end();
 
 #ifdef __KERNEL__
 		/* Place kernel structure only init below this point. */
@@ -388,9 +375,7 @@ xfs_initialize_perag(
 
 out_remove_pag:
 	xfs_defer_drain_free(&pag->pag_intents_drain);
-	spin_lock(&mp->m_perag_lock);
-	radix_tree_delete(&mp->m_perag_tree, index);
-	spin_unlock(&mp->m_perag_lock);
+	pag = xa_erase(&mp->m_perags, index);
 out_free_pag:
 	kfree(pag);
 out_unwind_new_pags:


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

* [PATCH 28/41] xfs: ensure st_blocks never goes to zero during COW writes
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (26 preceding siblings ...)
  2024-10-31 23:15   ` [PATCH 27/41] xfs: convert perag lookup to xarray Darrick J. Wong
@ 2024-10-31 23:15   ` Darrick J. Wong
  2024-10-31 23:16   ` [PATCH 29/41] xfs: enable block size larger than page size support Darrick J. Wong
                     ` (12 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:15 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 90fa22da6d6b41dc17435aff7b800f9ca3c00401

COW writes remove the amount overwritten either directly for delalloc
reservations, or in earlier deferred transactions than adding the new
amount back in the bmap map transaction.  This means st_blocks on an
inode where all data is overwritten using the COW path can temporarily
show a 0 st_blocks.  This can easily be reproduced with the pending
zoned device support where all writes use this path and trips the
check in generic/615, but could also happen on a reflink file without
that.

Fix this by temporarily add the pending blocks to be mapped to
i_delayed_blks while the item is queued.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
---
 libxfs/defer_item.c |   14 ++++++++++++++
 libxfs/xfs_bmap.c   |    1 +
 2 files changed, 15 insertions(+)


diff --git a/libxfs/defer_item.c b/libxfs/defer_item.c
index 98a291c7b785e1..2b48ed14d67bcb 100644
--- a/libxfs/defer_item.c
+++ b/libxfs/defer_item.c
@@ -520,6 +520,17 @@ xfs_bmap_defer_add(
 	trace_xfs_bmap_defer(bi);
 
 	xfs_bmap_update_get_group(tp->t_mountp, bi);
+
+	/*
+	 * Ensure the deferred mapping is pre-recorded in i_delayed_blks.
+	 *
+	 * Otherwise stat can report zero blocks for an inode that actually has
+	 * data when the entire mapping is in the process of being overwritten
+	 * using the out of place write path. This is undone in xfs_bmapi_remap
+	 * after it has incremented di_nblocks for a successful operation.
+	 */
+	if (bi->bi_type == XFS_BMAP_MAP)
+		bi->bi_owner->i_delayed_blks += bi->bi_bmap.br_blockcount;
 	xfs_defer_add(tp, &bi->bi_list, &xfs_bmap_update_defer_type);
 }
 
@@ -541,6 +552,9 @@ xfs_bmap_update_cancel_item(
 {
 	struct xfs_bmap_intent		*bi = bi_entry(item);
 
+	if (bi->bi_type == XFS_BMAP_MAP)
+		bi->bi_owner->i_delayed_blks -= bi->bi_bmap.br_blockcount;
+
 	xfs_bmap_update_put_group(bi);
 	kmem_cache_free(xfs_bmap_intent_cache, bi);
 }
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 4ee8d9b07a0ca7..c014325a5d7d9c 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -4850,6 +4850,7 @@ xfs_bmapi_remap(
 	}
 
 	ip->i_nblocks += len;
+	ip->i_delayed_blks -= len; /* see xfs_bmap_defer_add */
 	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 
 	if (ifp->if_format == XFS_DINODE_FMT_BTREE)


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

* [PATCH 29/41] xfs: enable block size larger than page size support
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (27 preceding siblings ...)
  2024-10-31 23:15   ` [PATCH 28/41] xfs: ensure st_blocks never goes to zero during COW writes Darrick J. Wong
@ 2024-10-31 23:16   ` Darrick J. Wong
  2024-10-31 23:16   ` [PATCH 30/41] xfs: merge xfs_attr_leaf_try_add into xfs_attr_leaf_addname Darrick J. Wong
                     ` (11 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:16 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Pankaj Raghav <p.raghav@samsung.com>

Source kernel commit: 7df7c204c678e24cd32d33360538670b7b90e330

Page cache now has the ability to have a minimum order when allocating
a folio which is a prerequisite to add support for block size > page
size.

Signed-off-by: Pankaj Raghav <p.raghav@samsung.com>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Link: https://lore.kernel.org/r/20240827-xfs-fix-wformat-bs-gt-ps-v1-1-aec6717609e0@kernel.org # fix folded
Link: https://lore.kernel.org/r/20240822135018.1931258-11-kernel@pankajraghav.com
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>
---
 libxfs/init.c        |    5 +++++
 libxfs/libxfs_priv.h |    1 +
 libxfs/xfs_ialloc.c  |    5 +++++
 libxfs/xfs_shared.h  |    3 +++
 4 files changed, 14 insertions(+)


diff --git a/libxfs/init.c b/libxfs/init.c
index 1e45f091dbb5bf..733ab3f1abc557 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -22,6 +22,7 @@
 #include "xfs_rmap_btree.h"
 #include "xfs_refcount_btree.h"
 #include "libfrog/platform.h"
+#include "libfrog/util.h"
 #include "libxfs/xfile.h"
 #include "libxfs/buf_mem.h"
 
@@ -44,6 +45,8 @@ int	use_xfs_buf_lock;	/* global flag: use xfs_buf locks for MT */
 
 static int nextfakedev = -1;	/* device number to give to next fake device */
 
+unsigned int PAGE_SHIFT;
+
 /*
  * Checks whether a given device has a mounted, writable
  * filesystem, returns 1 if it does & fatal (just warns
@@ -257,6 +260,8 @@ libxfs_close_devices(
 int
 libxfs_init(struct libxfs_init *a)
 {
+	if (!PAGE_SHIFT)
+		PAGE_SHIFT = log2_roundup(PAGE_SIZE);
 	xfs_check_ondisk_structs();
 	xmbuf_libinit();
 	rcu_init();
diff --git a/libxfs/libxfs_priv.h b/libxfs/libxfs_priv.h
index fa025aeb09712b..97f5003ea53862 100644
--- a/libxfs/libxfs_priv.h
+++ b/libxfs/libxfs_priv.h
@@ -224,6 +224,7 @@ uint32_t get_random_u32(void);
 #endif
 
 #define PAGE_SIZE		getpagesize()
+extern unsigned int PAGE_SHIFT;
 
 #define inode_peek_iversion(inode)	(inode)->i_version
 #define inode_set_iversion_queried(inode, version) do { \
diff --git a/libxfs/xfs_ialloc.c b/libxfs/xfs_ialloc.c
index 141b2d397b1fe7..43af698fa90903 100644
--- a/libxfs/xfs_ialloc.c
+++ b/libxfs/xfs_ialloc.c
@@ -3029,6 +3029,11 @@ xfs_ialloc_setup_geometry(
 		igeo->ialloc_align = mp->m_dalign;
 	else
 		igeo->ialloc_align = 0;
+
+	if (mp->m_sb.sb_blocksize > PAGE_SIZE)
+		igeo->min_folio_order = mp->m_sb.sb_blocklog - PAGE_SHIFT;
+	else
+		igeo->min_folio_order = 0;
 }
 
 /* Compute the location of the root directory inode that is laid out by mkfs. */
diff --git a/libxfs/xfs_shared.h b/libxfs/xfs_shared.h
index 2f7413afbf46cd..33b84a3a83ff63 100644
--- a/libxfs/xfs_shared.h
+++ b/libxfs/xfs_shared.h
@@ -224,6 +224,9 @@ struct xfs_ino_geometry {
 	/* precomputed value for di_flags2 */
 	uint64_t	new_diflags2;
 
+	/* minimum folio order of a page cache allocation */
+	unsigned int	min_folio_order;
+
 };
 
 #endif /* __XFS_SHARED_H__ */


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

* [PATCH 30/41] xfs: merge xfs_attr_leaf_try_add into xfs_attr_leaf_addname
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (28 preceding siblings ...)
  2024-10-31 23:16   ` [PATCH 29/41] xfs: enable block size larger than page size support Darrick J. Wong
@ 2024-10-31 23:16   ` Darrick J. Wong
  2024-10-31 23:16   ` [PATCH 31/41] xfs: return bool from xfs_attr3_leaf_add Darrick J. Wong
                     ` (10 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:16 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: b1c649da15c2e4c86344c8e5af69c8afa215efec

xfs_attr_leaf_try_add is only called by xfs_attr_leaf_addname, and
merging the two will simplify a following error handling fix.

To facilitate this move the remote block state save/restore helpers up in
the file so that they don't need forward declarations now.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_attr.c |  176 ++++++++++++++++++++++-------------------------------
 1 file changed, 74 insertions(+), 102 deletions(-)


diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 9e1cce5776b3df..21c708beac60c7 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -50,7 +50,6 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
-STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args);
 
 /*
  * Internal routines when attribute list is more than one block.
@@ -436,6 +435,33 @@ xfs_attr_hashval(
 	return xfs_attr_hashname(name, namelen);
 }
 
+/* Save the current remote block info and clear the current pointers. */
+static void
+xfs_attr_save_rmt_blk(
+	struct xfs_da_args	*args)
+{
+	args->blkno2 = args->blkno;
+	args->index2 = args->index;
+	args->rmtblkno2 = args->rmtblkno;
+	args->rmtblkcnt2 = args->rmtblkcnt;
+	args->rmtvaluelen2 = args->rmtvaluelen;
+	args->rmtblkno = 0;
+	args->rmtblkcnt = 0;
+	args->rmtvaluelen = 0;
+}
+
+/* Set stored info about a remote block */
+static void
+xfs_attr_restore_rmt_blk(
+	struct xfs_da_args	*args)
+{
+	args->blkno = args->blkno2;
+	args->index = args->index2;
+	args->rmtblkno = args->rmtblkno2;
+	args->rmtblkcnt = args->rmtblkcnt2;
+	args->rmtvaluelen = args->rmtvaluelen2;
+}
+
 /*
  * PPTR_REPLACE operations require the caller to set the old and new names and
  * values explicitly.  Update the canonical fields to the new name and value
@@ -481,49 +507,77 @@ xfs_attr_complete_op(
 	return replace_state;
 }
 
+/*
+ * Try to add an attribute to an inode in leaf form.
+ */
 static int
 xfs_attr_leaf_addname(
 	struct xfs_attr_intent	*attr)
 {
 	struct xfs_da_args	*args = attr->xattri_da_args;
+	struct xfs_buf		*bp;
 	int			error;
 
 	ASSERT(xfs_attr_is_leaf(args->dp));
 
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
+	if (error)
+		return error;
+
 	/*
-	 * Use the leaf buffer we may already hold locked as a result of
-	 * a sf-to-leaf conversion.
+	 * Look up the xattr name to set the insertion point for the new xattr.
 	 */
-	error = xfs_attr_leaf_try_add(args);
-
-	if (error == -ENOSPC) {
-		error = xfs_attr3_leaf_to_node(args);
-		if (error)
-			return error;
+	error = xfs_attr3_leaf_lookup_int(bp, args);
+	switch (error) {
+	case -ENOATTR:
+		if (args->op_flags & XFS_DA_OP_REPLACE)
+			goto out_brelse;
+		break;
+	case -EEXIST:
+		if (!(args->op_flags & XFS_DA_OP_REPLACE))
+			goto out_brelse;
 
+		trace_xfs_attr_leaf_replace(args);
 		/*
-		 * We're not in leaf format anymore, so roll the transaction and
-		 * retry the add to the newly allocated node block.
+		 * Save the existing remote attr state so that the current
+		 * values reflect the state of the new attribute we are about to
+		 * add, not the attribute we just found and will remove later.
 		 */
-		attr->xattri_dela_state = XFS_DAS_NODE_ADD;
-		goto out;
+		xfs_attr_save_rmt_blk(args);
+		break;
+	case 0:
+		break;
+	default:
+		goto out_brelse;
 	}
-	if (error)
-		return error;
 
 	/*
 	 * We need to commit and roll if we need to allocate remote xattr blocks
 	 * or perform more xattr manipulations. Otherwise there is nothing more
 	 * to do and we can return success.
 	 */
-	if (args->rmtblkno)
+	error = xfs_attr3_leaf_add(bp, args);
+	if (error) {
+		if (error != -ENOSPC)
+			return error;
+		error = xfs_attr3_leaf_to_node(args);
+		if (error)
+			return error;
+
+		attr->xattri_dela_state = XFS_DAS_NODE_ADD;
+	} else if (args->rmtblkno) {
 		attr->xattri_dela_state = XFS_DAS_LEAF_SET_RMT;
-	else
-		attr->xattri_dela_state = xfs_attr_complete_op(attr,
-							XFS_DAS_LEAF_REPLACE);
-out:
+	} else {
+		attr->xattri_dela_state =
+			xfs_attr_complete_op(attr, XFS_DAS_LEAF_REPLACE);
+	}
+
 	trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp);
 	return error;
+
+out_brelse:
+	xfs_trans_brelse(args->trans, bp);
+	return error;
 }
 
 /*
@@ -1169,88 +1223,6 @@ xfs_attr_shortform_addname(
  * External routines when attribute list is one block
  *========================================================================*/
 
-/* Save the current remote block info and clear the current pointers. */
-static void
-xfs_attr_save_rmt_blk(
-	struct xfs_da_args	*args)
-{
-	args->blkno2 = args->blkno;
-	args->index2 = args->index;
-	args->rmtblkno2 = args->rmtblkno;
-	args->rmtblkcnt2 = args->rmtblkcnt;
-	args->rmtvaluelen2 = args->rmtvaluelen;
-	args->rmtblkno = 0;
-	args->rmtblkcnt = 0;
-	args->rmtvaluelen = 0;
-}
-
-/* Set stored info about a remote block */
-static void
-xfs_attr_restore_rmt_blk(
-	struct xfs_da_args	*args)
-{
-	args->blkno = args->blkno2;
-	args->index = args->index2;
-	args->rmtblkno = args->rmtblkno2;
-	args->rmtblkcnt = args->rmtblkcnt2;
-	args->rmtvaluelen = args->rmtvaluelen2;
-}
-
-/*
- * Tries to add an attribute to an inode in leaf form
- *
- * This function is meant to execute as part of a delayed operation and leaves
- * the transaction handling to the caller.  On success the attribute is added
- * and the inode and transaction are left dirty.  If there is not enough space,
- * the attr data is converted to node format and -ENOSPC is returned. Caller is
- * responsible for handling the dirty inode and transaction or adding the attr
- * in node format.
- */
-STATIC int
-xfs_attr_leaf_try_add(
-	struct xfs_da_args	*args)
-{
-	struct xfs_buf		*bp;
-	int			error;
-
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->owner, 0, &bp);
-	if (error)
-		return error;
-
-	/*
-	 * Look up the xattr name to set the insertion point for the new xattr.
-	 */
-	error = xfs_attr3_leaf_lookup_int(bp, args);
-	switch (error) {
-	case -ENOATTR:
-		if (args->op_flags & XFS_DA_OP_REPLACE)
-			goto out_brelse;
-		break;
-	case -EEXIST:
-		if (!(args->op_flags & XFS_DA_OP_REPLACE))
-			goto out_brelse;
-
-		trace_xfs_attr_leaf_replace(args);
-		/*
-		 * Save the existing remote attr state so that the current
-		 * values reflect the state of the new attribute we are about to
-		 * add, not the attribute we just found and will remove later.
-		 */
-		xfs_attr_save_rmt_blk(args);
-		break;
-	case 0:
-		break;
-	default:
-		goto out_brelse;
-	}
-
-	return xfs_attr3_leaf_add(bp, args);
-
-out_brelse:
-	xfs_trans_brelse(args->trans, bp);
-	return error;
-}
-
 /*
  * Return EEXIST if attr is found, or ENOATTR if not
  */


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

* [PATCH 31/41] xfs: return bool from xfs_attr3_leaf_add
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (29 preceding siblings ...)
  2024-10-31 23:16   ` [PATCH 30/41] xfs: merge xfs_attr_leaf_try_add into xfs_attr_leaf_addname Darrick J. Wong
@ 2024-10-31 23:16   ` Darrick J. Wong
  2024-10-31 23:17   ` [PATCH 32/41] xfs: distinguish extra split from real ENOSPC from xfs_attr3_leaf_split Darrick J. Wong
                     ` (9 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:16 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 346c1d46d4c631c0c88592d371f585214d714da4

xfs_attr3_leaf_add only has two potential return values, indicating if the
entry could be added or not.  Replace the errno return with a bool so that
ENOSPC from it can't easily be confused with a real ENOSPC.

Remove the return value from the xfs_attr3_leaf_add_work helper entirely,
as it always return 0.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_attr.c      |   13 +++++--------
 libxfs/xfs_attr_leaf.c |   37 +++++++++++++++++++------------------
 libxfs/xfs_attr_leaf.h |    2 +-
 3 files changed, 25 insertions(+), 27 deletions(-)


diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 21c708beac60c7..9ac7124b0a7bc1 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -556,10 +556,7 @@ xfs_attr_leaf_addname(
 	 * or perform more xattr manipulations. Otherwise there is nothing more
 	 * to do and we can return success.
 	 */
-	error = xfs_attr3_leaf_add(bp, args);
-	if (error) {
-		if (error != -ENOSPC)
-			return error;
+	if (!xfs_attr3_leaf_add(bp, args)) {
 		error = xfs_attr3_leaf_to_node(args);
 		if (error)
 			return error;
@@ -573,7 +570,7 @@ xfs_attr_leaf_addname(
 	}
 
 	trace_xfs_attr_leaf_addname_return(attr->xattri_dela_state, args->dp);
-	return error;
+	return 0;
 
 out_brelse:
 	xfs_trans_brelse(args->trans, bp);
@@ -1398,21 +1395,21 @@ xfs_attr_node_try_addname(
 {
 	struct xfs_da_state		*state = attr->xattri_da_state;
 	struct xfs_da_state_blk		*blk;
-	int				error;
+	int				error = 0;
 
 	trace_xfs_attr_node_addname(state->args);
 
 	blk = &state->path.blk[state->path.active-1];
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
 
-	error = xfs_attr3_leaf_add(blk->bp, state->args);
-	if (error == -ENOSPC) {
+	if (!xfs_attr3_leaf_add(blk->bp, state->args)) {
 		if (state->path.active == 1) {
 			/*
 			 * Its really a single leaf node, but it had
 			 * out-of-line values so it looked like it *might*
 			 * have been a b-tree. Let the caller deal with this.
 			 */
+			error = -ENOSPC;
 			goto out;
 		}
 
diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index db2e48d719d36f..3028ef0cd3cb2c 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -44,7 +44,7 @@
  */
 STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args,
 				 xfs_dablk_t which_block, struct xfs_buf **bpp);
-STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer,
+STATIC void xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer,
 				   struct xfs_attr3_icleaf_hdr *ichdr,
 				   struct xfs_da_args *args, int freemap_index);
 STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args,
@@ -992,10 +992,8 @@ xfs_attr_shortform_to_leaf(
 		xfs_attr_sethash(&nargs);
 		error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
 		ASSERT(error == -ENOATTR);
-		error = xfs_attr3_leaf_add(bp, &nargs);
-		ASSERT(error != -ENOSPC);
-		if (error)
-			goto out;
+		if (!xfs_attr3_leaf_add(bp, &nargs))
+			ASSERT(0);
 		sfe = xfs_attr_sf_nextentry(sfe);
 	}
 	error = 0;
@@ -1337,8 +1335,9 @@ xfs_attr3_leaf_split(
 	struct xfs_da_state_blk	*oldblk,
 	struct xfs_da_state_blk	*newblk)
 {
-	xfs_dablk_t blkno;
-	int error;
+	bool			added;
+	xfs_dablk_t		blkno;
+	int			error;
 
 	trace_xfs_attr_leaf_split(state->args);
 
@@ -1373,10 +1372,10 @@ xfs_attr3_leaf_split(
 	 */
 	if (state->inleaf) {
 		trace_xfs_attr_leaf_add_old(state->args);
-		error = xfs_attr3_leaf_add(oldblk->bp, state->args);
+		added = xfs_attr3_leaf_add(oldblk->bp, state->args);
 	} else {
 		trace_xfs_attr_leaf_add_new(state->args);
-		error = xfs_attr3_leaf_add(newblk->bp, state->args);
+		added = xfs_attr3_leaf_add(newblk->bp, state->args);
 	}
 
 	/*
@@ -1384,13 +1383,15 @@ xfs_attr3_leaf_split(
 	 */
 	oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL);
 	newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL);
-	return error;
+	if (!added)
+		return -ENOSPC;
+	return 0;
 }
 
 /*
  * Add a name to the leaf attribute list structure.
  */
-int
+bool
 xfs_attr3_leaf_add(
 	struct xfs_buf		*bp,
 	struct xfs_da_args	*args)
@@ -1399,6 +1400,7 @@ xfs_attr3_leaf_add(
 	struct xfs_attr3_icleaf_hdr ichdr;
 	int			tablesize;
 	int			entsize;
+	bool			added = true;
 	int			sum;
 	int			tmp;
 	int			i;
@@ -1427,7 +1429,7 @@ xfs_attr3_leaf_add(
 		if (ichdr.freemap[i].base < ichdr.firstused)
 			tmp += sizeof(xfs_attr_leaf_entry_t);
 		if (ichdr.freemap[i].size >= tmp) {
-			tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i);
+			xfs_attr3_leaf_add_work(bp, &ichdr, args, i);
 			goto out_log_hdr;
 		}
 		sum += ichdr.freemap[i].size;
@@ -1439,7 +1441,7 @@ xfs_attr3_leaf_add(
 	 * no good and we should just give up.
 	 */
 	if (!ichdr.holes && sum < entsize)
-		return -ENOSPC;
+		return false;
 
 	/*
 	 * Compact the entries to coalesce free space.
@@ -1452,24 +1454,24 @@ xfs_attr3_leaf_add(
 	 * free region, in freemap[0].  If it is not big enough, give up.
 	 */
 	if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) {
-		tmp = -ENOSPC;
+		added = false;
 		goto out_log_hdr;
 	}
 
-	tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0);
+	xfs_attr3_leaf_add_work(bp, &ichdr, args, 0);
 
 out_log_hdr:
 	xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr);
 	xfs_trans_log_buf(args->trans, bp,
 		XFS_DA_LOGRANGE(leaf, &leaf->hdr,
 				xfs_attr3_leaf_hdr_size(leaf)));
-	return tmp;
+	return added;
 }
 
 /*
  * Add a name to a leaf attribute list structure.
  */
-STATIC int
+STATIC void
 xfs_attr3_leaf_add_work(
 	struct xfs_buf		*bp,
 	struct xfs_attr3_icleaf_hdr *ichdr,
@@ -1587,7 +1589,6 @@ xfs_attr3_leaf_add_work(
 		}
 	}
 	ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
-	return 0;
 }
 
 /*
diff --git a/libxfs/xfs_attr_leaf.h b/libxfs/xfs_attr_leaf.h
index bac219589896ad..589f810eedc0d8 100644
--- a/libxfs/xfs_attr_leaf.h
+++ b/libxfs/xfs_attr_leaf.h
@@ -76,7 +76,7 @@ int	xfs_attr3_leaf_split(struct xfs_da_state *state,
 int	xfs_attr3_leaf_lookup_int(struct xfs_buf *leaf,
 					struct xfs_da_args *args);
 int	xfs_attr3_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args);
-int	xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
+bool	xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer,
 				 struct xfs_da_args *args);
 int	xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer,
 				    struct xfs_da_args *args);


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

* [PATCH 32/41] xfs: distinguish extra split from real ENOSPC from xfs_attr3_leaf_split
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (30 preceding siblings ...)
  2024-10-31 23:16   ` [PATCH 31/41] xfs: return bool from xfs_attr3_leaf_add Darrick J. Wong
@ 2024-10-31 23:17   ` Darrick J. Wong
  2024-10-31 23:17   ` [PATCH 33/41] xfs: distinguish extra split from real ENOSPC from xfs_attr_node_try_addname Darrick J. Wong
                     ` (8 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:17 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: a5f73342abe1f796140f6585e43e2aa7bc1b7975

xfs_attr3_leaf_split propagates the need for an extra btree split as
-ENOSPC to it's only caller, but the same return value can also be
returned from xfs_da_grow_inode when it fails to find free space.

Distinguish the two cases by returning 1 for the extra split case instead
of overloading -ENOSPC.

This can be triggered relatively easily with the pending realtime group
support and a file system with a lot of small zones that use metadata
space on the main device.  In this case every about 5-10th run of
xfs/538 runs into the following assert:

ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC);

in xfs_attr3_leaf_split caused by an allocation failure.  Note that
the allocation failure is caused by another bug that will be fixed
subsequently, but this commit at least sorts out the error handling.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_attr_leaf.c |    5 ++++-
 libxfs/xfs_da_btree.c  |    5 +++--
 2 files changed, 7 insertions(+), 3 deletions(-)


diff --git a/libxfs/xfs_attr_leaf.c b/libxfs/xfs_attr_leaf.c
index 3028ef0cd3cb2c..01a87b45a6a5c0 100644
--- a/libxfs/xfs_attr_leaf.c
+++ b/libxfs/xfs_attr_leaf.c
@@ -1328,6 +1328,9 @@ xfs_attr3_leaf_create(
 
 /*
  * Split the leaf node, rebalance, then add the new entry.
+ *
+ * Returns 0 if the entry was added, 1 if a further split is needed or a
+ * negative error number otherwise.
  */
 int
 xfs_attr3_leaf_split(
@@ -1384,7 +1387,7 @@ xfs_attr3_leaf_split(
 	oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL);
 	newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL);
 	if (!added)
-		return -ENOSPC;
+		return 1;
 	return 0;
 }
 
diff --git a/libxfs/xfs_da_btree.c b/libxfs/xfs_da_btree.c
index 820e8575246b50..38f345a923c757 100644
--- a/libxfs/xfs_da_btree.c
+++ b/libxfs/xfs_da_btree.c
@@ -589,9 +589,8 @@ xfs_da3_split(
 		switch (oldblk->magic) {
 		case XFS_ATTR_LEAF_MAGIC:
 			error = xfs_attr3_leaf_split(state, oldblk, newblk);
-			if ((error != 0) && (error != -ENOSPC)) {
+			if (error < 0)
 				return error;	/* GROT: attr is inconsistent */
-			}
 			if (!error) {
 				addblk = newblk;
 				break;
@@ -613,6 +612,8 @@ xfs_da3_split(
 				error = xfs_attr3_leaf_split(state, newblk,
 							    &state->extrablk);
 			}
+			if (error == 1)
+				return -ENOSPC;
 			if (error)
 				return error;	/* GROT: attr inconsistent */
 			addblk = newblk;


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

* [PATCH 33/41] xfs: distinguish extra split from real ENOSPC from xfs_attr_node_try_addname
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (31 preceding siblings ...)
  2024-10-31 23:17   ` [PATCH 32/41] xfs: distinguish extra split from real ENOSPC from xfs_attr3_leaf_split Darrick J. Wong
@ 2024-10-31 23:17   ` Darrick J. Wong
  2024-10-31 23:17   ` [PATCH 34/41] xfs: fold xfs_bmap_alloc_userdata into xfs_bmapi_allocate Darrick J. Wong
                     ` (7 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:17 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: b3f4e84e2f438a119b7ca8684a25452b3e57c0f0

Just like xfs_attr3_leaf_split, xfs_attr_node_try_addname can return
-ENOSPC both for an actual failure to allocate a disk block, but also
to signal the caller to convert the format of the attr fork.  Use magic
1 to ask for the conversion here as well.

Note that unlike the similar issue in xfs_attr3_leaf_split, this one was
only found by code review.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_attr.c |   13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)


diff --git a/libxfs/xfs_attr.c b/libxfs/xfs_attr.c
index 9ac7124b0a7bc1..150aaddf7f9fed 100644
--- a/libxfs/xfs_attr.c
+++ b/libxfs/xfs_attr.c
@@ -596,7 +596,7 @@ xfs_attr_node_addname(
 		return error;
 
 	error = xfs_attr_node_try_addname(attr);
-	if (error == -ENOSPC) {
+	if (error == 1) {
 		error = xfs_attr3_leaf_to_node(args);
 		if (error)
 			return error;
@@ -1385,9 +1385,12 @@ xfs_attr_node_addname_find_attr(
 /*
  * Add a name to a Btree-format attribute list.
  *
- * This will involve walking down the Btree, and may involve splitting
- * leaf nodes and even splitting intermediate nodes up to and including
- * the root node (a special case of an intermediate node).
+ * This will involve walking down the Btree, and may involve splitting leaf
+ * nodes and even splitting intermediate nodes up to and including the root
+ * node (a special case of an intermediate node).
+ *
+ * If the tree was still in single leaf format and needs to converted to
+ * real node format return 1 and let the caller handle that.
  */
 static int
 xfs_attr_node_try_addname(
@@ -1409,7 +1412,7 @@ xfs_attr_node_try_addname(
 			 * out-of-line values so it looked like it *might*
 			 * have been a b-tree. Let the caller deal with this.
 			 */
-			error = -ENOSPC;
+			error = 1;
 			goto out;
 		}
 


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

* [PATCH 34/41] xfs: fold xfs_bmap_alloc_userdata into xfs_bmapi_allocate
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (32 preceding siblings ...)
  2024-10-31 23:17   ` [PATCH 33/41] xfs: distinguish extra split from real ENOSPC from xfs_attr_node_try_addname Darrick J. Wong
@ 2024-10-31 23:17   ` Darrick J. Wong
  2024-10-31 23:17   ` [PATCH 35/41] xfs: don't ifdef around the exact minlen allocations Darrick J. Wong
                     ` (6 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:17 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 865469cd41bce2b04bef9539cbf70676878bc8df

Userdata and metadata allocations end up in the same allocation helpers.
Remove the separate xfs_bmap_alloc_userdata function to make this more
clear.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_bmap.c |   73 ++++++++++++++++++++---------------------------------
 1 file changed, 28 insertions(+), 45 deletions(-)


diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index c014325a5d7d9c..af493836ecc7ea 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -4170,43 +4170,6 @@ xfs_bmapi_reserve_delalloc(
 	return error;
 }
 
-static int
-xfs_bmap_alloc_userdata(
-	struct xfs_bmalloca	*bma)
-{
-	struct xfs_mount	*mp = bma->ip->i_mount;
-	int			whichfork = xfs_bmapi_whichfork(bma->flags);
-	int			error;
-
-	/*
-	 * Set the data type being allocated. For the data fork, the first data
-	 * in the file is treated differently to all other allocations. For the
-	 * attribute fork, we only need to ensure the allocated range is not on
-	 * the busy list.
-	 */
-	bma->datatype = XFS_ALLOC_NOBUSY;
-	if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK) {
-		bma->datatype |= XFS_ALLOC_USERDATA;
-		if (bma->offset == 0)
-			bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
-
-		if (mp->m_dalign && bma->length >= mp->m_dalign) {
-			error = xfs_bmap_isaeof(bma, whichfork);
-			if (error)
-				return error;
-		}
-
-		if (XFS_IS_REALTIME_INODE(bma->ip))
-			return xfs_bmap_rtalloc(bma);
-	}
-
-	if (unlikely(XFS_TEST_ERROR(false, mp,
-			XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
-		return xfs_bmap_exact_minlen_extent_alloc(bma);
-
-	return xfs_bmap_btalloc(bma);
-}
-
 static int
 xfs_bmapi_allocate(
 	struct xfs_bmalloca	*bma)
@@ -4224,15 +4187,35 @@ xfs_bmapi_allocate(
 	else
 		bma->minlen = 1;
 
-	if (bma->flags & XFS_BMAPI_METADATA) {
-		if (unlikely(XFS_TEST_ERROR(false, mp,
-				XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
-			error = xfs_bmap_exact_minlen_extent_alloc(bma);
-		else
-			error = xfs_bmap_btalloc(bma);
-	} else {
-		error = xfs_bmap_alloc_userdata(bma);
+	if (!(bma->flags & XFS_BMAPI_METADATA)) {
+		/*
+		 * For the data and COW fork, the first data in the file is
+		 * treated differently to all other allocations. For the
+		 * attribute fork, we only need to ensure the allocated range
+		 * is not on the busy list.
+		 */
+		bma->datatype = XFS_ALLOC_NOBUSY;
+		if (whichfork == XFS_DATA_FORK || whichfork == XFS_COW_FORK) {
+			bma->datatype |= XFS_ALLOC_USERDATA;
+			if (bma->offset == 0)
+				bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA;
+
+			if (mp->m_dalign && bma->length >= mp->m_dalign) {
+				error = xfs_bmap_isaeof(bma, whichfork);
+				if (error)
+					return error;
+			}
+		}
 	}
+
+	if ((bma->datatype & XFS_ALLOC_USERDATA) &&
+	    XFS_IS_REALTIME_INODE(bma->ip))
+		error = xfs_bmap_rtalloc(bma);
+	else if (unlikely(XFS_TEST_ERROR(false, mp,
+			XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
+		error = xfs_bmap_exact_minlen_extent_alloc(bma);
+	else
+		error = xfs_bmap_btalloc(bma);
 	if (error)
 		return error;
 	if (bma->blkno == NULLFSBLOCK)


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

* [PATCH 35/41] xfs: don't ifdef around the exact minlen allocations
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (33 preceding siblings ...)
  2024-10-31 23:17   ` [PATCH 34/41] xfs: fold xfs_bmap_alloc_userdata into xfs_bmapi_allocate Darrick J. Wong
@ 2024-10-31 23:17   ` Darrick J. Wong
  2024-10-31 23:18   ` [PATCH 36/41] xfs: call xfs_bmap_exact_minlen_extent_alloc from xfs_bmap_btalloc Darrick J. Wong
                     ` (5 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:17 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: b611fddc0435738e64453bbf1dadd4b12a801858

Exact minlen allocations only exist as an error injection tool for debug
builds.  Currently this is implemented using ifdefs, which means the code
isn't even compiled for non-XFS_DEBUG builds.  Enhance the compile test
coverage by always building the code and use the compilers' dead code
elimination to remove it from the generated binary instead.

The only downside is that the alloc_minlen_only field is unconditionally
added to struct xfs_alloc_args now, but by moving it around and packing
it tightly this doesn't actually increase the size of the structure.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_alloc.c |    7 ++-----
 libxfs/xfs_alloc.h |    4 +---
 libxfs/xfs_bmap.c  |    6 ------
 3 files changed, 3 insertions(+), 14 deletions(-)


diff --git a/libxfs/xfs_alloc.c b/libxfs/xfs_alloc.c
index 3806a6bc0835a7..61453709ae515c 100644
--- a/libxfs/xfs_alloc.c
+++ b/libxfs/xfs_alloc.c
@@ -2762,7 +2762,6 @@ xfs_alloc_commit_autoreap(
 		xfs_defer_item_unpause(tp, aarp->dfp);
 }
 
-#ifdef DEBUG
 /*
  * Check if an AGF has a free extent record whose length is equal to
  * args->minlen.
@@ -2802,7 +2801,6 @@ xfs_exact_minlen_extent_available(
 
 	return error;
 }
-#endif
 
 /*
  * Decide whether to use this allocation group for this allocation.
@@ -2876,15 +2874,14 @@ xfs_alloc_fix_freelist(
 	if (!xfs_alloc_space_available(args, need, alloc_flags))
 		goto out_agbp_relse;
 
-#ifdef DEBUG
-	if (args->alloc_minlen_only) {
+	if (IS_ENABLED(CONFIG_XFS_DEBUG) && args->alloc_minlen_only) {
 		int stat;
 
 		error = xfs_exact_minlen_extent_available(args, agbp, &stat);
 		if (error || !stat)
 			goto out_agbp_relse;
 	}
-#endif
+
 	/*
 	 * Make the freelist shorter if it's too long.
 	 *
diff --git a/libxfs/xfs_alloc.h b/libxfs/xfs_alloc.h
index fae170825be064..0165452e7cd055 100644
--- a/libxfs/xfs_alloc.h
+++ b/libxfs/xfs_alloc.h
@@ -53,11 +53,9 @@ typedef struct xfs_alloc_arg {
 	int		datatype;	/* mask defining data type treatment */
 	char		wasdel;		/* set if allocation was prev delayed */
 	char		wasfromfl;	/* set if allocation is from freelist */
+	bool		alloc_minlen_only; /* allocate exact minlen extent */
 	struct xfs_owner_info	oinfo;	/* owner of blocks being allocated */
 	enum xfs_ag_resv_type	resv;	/* block reservation to use */
-#ifdef DEBUG
-	bool		alloc_minlen_only; /* allocate exact minlen extent */
-#endif
 } xfs_alloc_arg_t;
 
 /*
diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index af493836ecc7ea..3c4922424f3fd0 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -3471,7 +3471,6 @@ xfs_bmap_process_allocated_extent(
 	xfs_bmap_alloc_account(ap);
 }
 
-#ifdef DEBUG
 static int
 xfs_bmap_exact_minlen_extent_alloc(
 	struct xfs_bmalloca	*ap)
@@ -3533,11 +3532,6 @@ xfs_bmap_exact_minlen_extent_alloc(
 
 	return 0;
 }
-#else
-
-#define xfs_bmap_exact_minlen_extent_alloc(bma) (-EFSCORRUPTED)
-
-#endif
 
 /*
  * If we are not low on available data blocks and we are allocating at


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

* [PATCH 36/41] xfs: call xfs_bmap_exact_minlen_extent_alloc from xfs_bmap_btalloc
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (34 preceding siblings ...)
  2024-10-31 23:17   ` [PATCH 35/41] xfs: don't ifdef around the exact minlen allocations Darrick J. Wong
@ 2024-10-31 23:18   ` Darrick J. Wong
  2024-10-31 23:18   ` [PATCH 37/41] xfs: support lowmode allocations in xfs_bmap_exact_minlen_extent_alloc Darrick J. Wong
                     ` (4 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:18 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 405ee87c6938f67e6ab62a3f8f85b3c60a093886

xfs_bmap_exact_minlen_extent_alloc duplicates the args setup in
xfs_bmap_btalloc.  Switch to call it from xfs_bmap_btalloc after
doing the basic setup.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_bmap.c |   61 +++++++++++------------------------------------------
 1 file changed, 13 insertions(+), 48 deletions(-)


diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 3c4922424f3fd0..02f26854c53cfe 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -3473,28 +3473,17 @@ xfs_bmap_process_allocated_extent(
 
 static int
 xfs_bmap_exact_minlen_extent_alloc(
-	struct xfs_bmalloca	*ap)
+	struct xfs_bmalloca	*ap,
+	struct xfs_alloc_arg	*args)
 {
-	struct xfs_mount	*mp = ap->ip->i_mount;
-	struct xfs_alloc_arg	args = { .tp = ap->tp, .mp = mp };
-	xfs_fileoff_t		orig_offset;
-	xfs_extlen_t		orig_length;
-	int			error;
-
-	ASSERT(ap->length);
-
 	if (ap->minlen != 1) {
-		ap->blkno = NULLFSBLOCK;
-		ap->length = 0;
+		args->fsbno = NULLFSBLOCK;
 		return 0;
 	}
 
-	orig_offset = ap->offset;
-	orig_length = ap->length;
-
-	args.alloc_minlen_only = 1;
-
-	xfs_bmap_compute_alignments(ap, &args);
+	args->alloc_minlen_only = 1;
+	args->minlen = args->maxlen = ap->minlen;
+	args->total = ap->total;
 
 	/*
 	 * Unlike the longest extent available in an AG, we don't track
@@ -3504,33 +3493,9 @@ xfs_bmap_exact_minlen_extent_alloc(
 	 * we need not be concerned about a drop in performance in
 	 * "debug only" code paths.
 	 */
-	ap->blkno = XFS_AGB_TO_FSB(mp, 0, 0);
+	ap->blkno = XFS_AGB_TO_FSB(ap->ip->i_mount, 0, 0);
 
-	args.oinfo = XFS_RMAP_OINFO_SKIP_UPDATE;
-	args.minlen = args.maxlen = ap->minlen;
-	args.total = ap->total;
-
-	args.alignment = 1;
-	args.minalignslop = 0;
-
-	args.minleft = ap->minleft;
-	args.wasdel = ap->wasdel;
-	args.resv = XFS_AG_RESV_NONE;
-	args.datatype = ap->datatype;
-
-	error = xfs_alloc_vextent_first_ag(&args, ap->blkno);
-	if (error)
-		return error;
-
-	if (args.fsbno != NULLFSBLOCK) {
-		xfs_bmap_process_allocated_extent(ap, &args, orig_offset,
-			orig_length);
-	} else {
-		ap->blkno = NULLFSBLOCK;
-		ap->length = 0;
-	}
-
-	return 0;
+	return xfs_alloc_vextent_first_ag(args, ap->blkno);
 }
 
 /*
@@ -3789,8 +3754,11 @@ xfs_bmap_btalloc(
 	/* Trim the allocation back to the maximum an AG can fit. */
 	args.maxlen = min(ap->length, mp->m_ag_max_usable);
 
-	if ((ap->datatype & XFS_ALLOC_USERDATA) &&
-	    xfs_inode_is_filestream(ap->ip))
+	if (unlikely(XFS_TEST_ERROR(false, mp,
+			XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
+		error = xfs_bmap_exact_minlen_extent_alloc(ap, &args);
+	else if ((ap->datatype & XFS_ALLOC_USERDATA) &&
+			xfs_inode_is_filestream(ap->ip))
 		error = xfs_bmap_btalloc_filestreams(ap, &args, stripe_align);
 	else
 		error = xfs_bmap_btalloc_best_length(ap, &args, stripe_align);
@@ -4205,9 +4173,6 @@ xfs_bmapi_allocate(
 	if ((bma->datatype & XFS_ALLOC_USERDATA) &&
 	    XFS_IS_REALTIME_INODE(bma->ip))
 		error = xfs_bmap_rtalloc(bma);
-	else if (unlikely(XFS_TEST_ERROR(false, mp,
-			XFS_ERRTAG_BMAP_ALLOC_MINLEN_EXTENT)))
-		error = xfs_bmap_exact_minlen_extent_alloc(bma);
 	else
 		error = xfs_bmap_btalloc(bma);
 	if (error)


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

* [PATCH 37/41] xfs: support lowmode allocations in xfs_bmap_exact_minlen_extent_alloc
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (35 preceding siblings ...)
  2024-10-31 23:18   ` [PATCH 36/41] xfs: call xfs_bmap_exact_minlen_extent_alloc from xfs_bmap_btalloc Darrick J. Wong
@ 2024-10-31 23:18   ` Darrick J. Wong
  2024-10-31 23:18   ` [PATCH 38/41] xfs: pass the exact range to initialize to xfs_initialize_perag Darrick J. Wong
                     ` (3 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:18 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 6aac77059881e4419df499392c995bf02fb9630b

Currently the debug-only xfs_bmap_exact_minlen_extent_alloc allocation
variant fails to drop into the lowmode last resort allocator, and
thus can sometimes fail allocations for which the caller has a
transaction block reservation.

Fix this by using xfs_bmap_btalloc_low_space to do the actual allocation.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_bmap.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)


diff --git a/libxfs/xfs_bmap.c b/libxfs/xfs_bmap.c
index 02f26854c53cfe..aec378ff4a9193 100644
--- a/libxfs/xfs_bmap.c
+++ b/libxfs/xfs_bmap.c
@@ -3495,7 +3495,13 @@ xfs_bmap_exact_minlen_extent_alloc(
 	 */
 	ap->blkno = XFS_AGB_TO_FSB(ap->ip->i_mount, 0, 0);
 
-	return xfs_alloc_vextent_first_ag(args, ap->blkno);
+	/*
+	 * Call xfs_bmap_btalloc_low_space here as it first does a "normal" AG
+	 * iteration and then drops args->total to args->minlen, which might be
+	 * required to find an allocation for the transaction reservation when
+	 * the file system is very full.
+	 */
+	return xfs_bmap_btalloc_low_space(ap, args);
 }
 
 /*


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

* [PATCH 38/41] xfs: pass the exact range to initialize to xfs_initialize_perag
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (36 preceding siblings ...)
  2024-10-31 23:18   ` [PATCH 37/41] xfs: support lowmode allocations in xfs_bmap_exact_minlen_extent_alloc Darrick J. Wong
@ 2024-10-31 23:18   ` Darrick J. Wong
  2024-10-31 23:18   ` [PATCH 39/41] xfs: merge the perag freeing helpers Darrick J. Wong
                     ` (2 subsequent siblings)
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:18 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 82742f8c3f1a93787a05a00aca50c2a565231f84

Currently only the new agcount is passed to xfs_initialize_perag, which
requires lookups of existing AGs to skip them and complicates error
handling.  Also pass the previous agcount so that the range that
xfs_initialize_perag operates on is exactly defined.  That way the
extra lookups can be avoided, and error handling can clean up the
exact range from the old count to the last added perag structure.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_ag.c |   28 ++++++----------------------
 libxfs/xfs_ag.h |    5 +++--
 2 files changed, 9 insertions(+), 24 deletions(-)


diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index 516c76790cc0d8..3bbfefe5e46935 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -294,27 +294,16 @@ xfs_free_unused_perag_range(
 int
 xfs_initialize_perag(
 	struct xfs_mount	*mp,
-	xfs_agnumber_t		agcount,
+	xfs_agnumber_t		old_agcount,
+	xfs_agnumber_t		new_agcount,
 	xfs_rfsblock_t		dblocks,
 	xfs_agnumber_t		*maxagi)
 {
 	struct xfs_perag	*pag;
 	xfs_agnumber_t		index;
-	xfs_agnumber_t		first_initialised = NULLAGNUMBER;
 	int			error;
 
-	/*
-	 * Walk the current per-ag tree so we don't try to initialise AGs
-	 * that already exist (growfs case). Allocate and insert all the
-	 * AGs we don't find ready for initialisation.
-	 */
-	for (index = 0; index < agcount; index++) {
-		pag = xfs_perag_get(mp, index);
-		if (pag) {
-			xfs_perag_put(pag);
-			continue;
-		}
-
+	for (index = old_agcount; index < new_agcount; index++) {
 		pag = kzalloc(sizeof(*pag), GFP_KERNEL | __GFP_RETRY_MAYFAIL);
 		if (!pag) {
 			error = -ENOMEM;
@@ -351,21 +340,17 @@ xfs_initialize_perag(
 		/* Active ref owned by mount indicates AG is online. */
 		atomic_set(&pag->pag_active_ref, 1);
 
-		/* first new pag is fully initialized */
-		if (first_initialised == NULLAGNUMBER)
-			first_initialised = index;
-
 		/*
 		 * Pre-calculated geometry
 		 */
-		pag->block_count = __xfs_ag_block_count(mp, index, agcount,
+		pag->block_count = __xfs_ag_block_count(mp, index, new_agcount,
 				dblocks);
 		pag->min_block = XFS_AGFL_BLOCK(mp);
 		__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
 				&pag->agino_max);
 	}
 
-	index = xfs_set_inode_alloc(mp, agcount);
+	index = xfs_set_inode_alloc(mp, new_agcount);
 
 	if (maxagi)
 		*maxagi = index;
@@ -379,8 +364,7 @@ xfs_initialize_perag(
 out_free_pag:
 	kfree(pag);
 out_unwind_new_pags:
-	/* unwind any prior newly initialized pags */
-	xfs_free_unused_perag_range(mp, first_initialised, agcount);
+	xfs_free_unused_perag_range(mp, old_agcount, index);
 	return error;
 }
 
diff --git a/libxfs/xfs_ag.h b/libxfs/xfs_ag.h
index d9cccd093b60e0..69fc31e7b84728 100644
--- a/libxfs/xfs_ag.h
+++ b/libxfs/xfs_ag.h
@@ -146,8 +146,9 @@ __XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
 
 void xfs_free_unused_perag_range(struct xfs_mount *mp, xfs_agnumber_t agstart,
 			xfs_agnumber_t agend);
-int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
-			xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
+int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
+		xfs_agnumber_t agcount, xfs_rfsblock_t dcount,
+		xfs_agnumber_t *maxagi);
 int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
 void xfs_free_perag(struct xfs_mount *mp);
 


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

* [PATCH 39/41] xfs: merge the perag freeing helpers
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (37 preceding siblings ...)
  2024-10-31 23:18   ` [PATCH 38/41] xfs: pass the exact range to initialize to xfs_initialize_perag Darrick J. Wong
@ 2024-10-31 23:18   ` Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 40/41] xfs: don't use __GFP_RETRY_MAYFAIL in xfs_initialize_perag Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 41/41] xfs: update the pag for the last AG at recovery time Darrick J. Wong
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:18 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: aa67ec6a25617e36eba4fb28a88159f500a6cac6

There is no good reason to have two different routines for freeing perag
structures for the unmount and error cases.  Add two arguments to specify
the range of AGs to free to xfs_free_perag, and use that to replace
xfs_free_unused_perag_range.

The addition RCU grace period for the error case is harmless, and the
extra check for the AG to actually exist is not required now that the
callers pass the exact known allocated range.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/init.c            |    6 +++---
 libxfs/libxfs_api_defs.h |    2 +-
 libxfs/xfs_ag.c          |   40 ++++++++++------------------------------
 libxfs/xfs_ag.h          |    5 ++---
 4 files changed, 16 insertions(+), 37 deletions(-)


diff --git a/libxfs/init.c b/libxfs/init.c
index 733ab3f1abc557..483cd99546052f 100644
--- a/libxfs/init.c
+++ b/libxfs/init.c
@@ -789,8 +789,8 @@ libxfs_mount(
 			libxfs_buf_relse(bp);
 	}
 
-	error = libxfs_initialize_perag(mp, sbp->sb_agcount, sbp->sb_dblocks,
-			&mp->m_maxagi);
+	error = libxfs_initialize_perag(mp, 0, sbp->sb_agcount,
+			sbp->sb_dblocks, &mp->m_maxagi);
 	if (error) {
 		fprintf(stderr, _("%s: perag init failed\n"),
 			progname);
@@ -930,7 +930,7 @@ libxfs_umount(
 	 * first place.
 	 */
 	if (xfs_is_perag_data_loaded(mp))
-		libxfs_free_perag(mp);
+		libxfs_free_perag_range(mp, 0, mp->m_sb.sb_agcount);
 
 	xfs_da_unmount(mp);
 
diff --git a/libxfs/libxfs_api_defs.h b/libxfs/libxfs_api_defs.h
index a4173e5f7a595c..b9986a00681c1e 100644
--- a/libxfs/libxfs_api_defs.h
+++ b/libxfs/libxfs_api_defs.h
@@ -166,7 +166,7 @@
 #define xfs_finobt_init_cursor		libxfs_finobt_init_cursor
 #define xfs_free_extent			libxfs_free_extent
 #define xfs_free_extent_later		libxfs_free_extent_later
-#define xfs_free_perag			libxfs_free_perag
+#define xfs_free_perag_range		libxfs_free_perag_range
 #define xfs_fs_geometry			libxfs_fs_geometry
 #define xfs_get_initial_prid		libxfs_get_initial_prid
 #define xfs_highbit32			libxfs_highbit32
diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index 3bbfefe5e46935..a9993215bf9a30 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -183,17 +183,20 @@ xfs_initialize_perag_data(
 }
 
 /*
- * Free up the per-ag resources associated with the mount structure.
+ * Free up the per-ag resources  within the specified AG range.
  */
 void
-xfs_free_perag(
-	struct xfs_mount	*mp)
+xfs_free_perag_range(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		first_agno,
+	xfs_agnumber_t		end_agno)
+
 {
-	struct xfs_perag	*pag;
 	xfs_agnumber_t		agno;
 
-	for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) {
-		pag = xa_erase(&mp->m_perags, agno);
+	for (agno = first_agno; agno < end_agno; agno++) {
+		struct xfs_perag	*pag = xa_erase(&mp->m_perags, agno);
+
 		ASSERT(pag);
 		XFS_IS_CORRUPT(pag->pag_mount, atomic_read(&pag->pag_ref) != 0);
 		xfs_defer_drain_free(&pag->pag_intents_drain);
@@ -268,29 +271,6 @@ xfs_agino_range(
 	return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
 }
 
-/*
- * Free perag within the specified AG range, it is only used to free unused
- * perags under the error handling path.
- */
-void
-xfs_free_unused_perag_range(
-	struct xfs_mount	*mp,
-	xfs_agnumber_t		agstart,
-	xfs_agnumber_t		agend)
-{
-	struct xfs_perag	*pag;
-	xfs_agnumber_t		index;
-
-	for (index = agstart; index < agend; index++) {
-		pag = xa_erase(&mp->m_perags, index);
-		if (!pag)
-			break;
-		xfs_buf_cache_destroy(&pag->pag_bcache);
-		xfs_defer_drain_free(&pag->pag_intents_drain);
-		kfree(pag);
-	}
-}
-
 int
 xfs_initialize_perag(
 	struct xfs_mount	*mp,
@@ -364,7 +344,7 @@ xfs_initialize_perag(
 out_free_pag:
 	kfree(pag);
 out_unwind_new_pags:
-	xfs_free_unused_perag_range(mp, old_agcount, index);
+	xfs_free_perag_range(mp, old_agcount, index);
 	return error;
 }
 
diff --git a/libxfs/xfs_ag.h b/libxfs/xfs_ag.h
index 69fc31e7b84728..6e68d6a3161a0f 100644
--- a/libxfs/xfs_ag.h
+++ b/libxfs/xfs_ag.h
@@ -144,13 +144,12 @@ __XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA)
 __XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES)
 __XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)
 
-void xfs_free_unused_perag_range(struct xfs_mount *mp, xfs_agnumber_t agstart,
-			xfs_agnumber_t agend);
 int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
 		xfs_agnumber_t agcount, xfs_rfsblock_t dcount,
 		xfs_agnumber_t *maxagi);
+void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
+		xfs_agnumber_t end_agno);
 int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
-void xfs_free_perag(struct xfs_mount *mp);
 
 /* Passive AG references */
 struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);


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

* [PATCH 40/41] xfs: don't use __GFP_RETRY_MAYFAIL in xfs_initialize_perag
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (38 preceding siblings ...)
  2024-10-31 23:18   ` [PATCH 39/41] xfs: merge the perag freeing helpers Darrick J. Wong
@ 2024-10-31 23:19   ` Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 41/41] xfs: update the pag for the last AG at recovery time Darrick J. Wong
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:19 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 069cf5e32b700f94c6ac60f6171662bdfb04f325

__GFP_RETRY_MAYFAIL increases the likelyhood of allocations to fail,
which isn't really helpful during log recovery.  Remove the flag and
stick to the default GFP_KERNEL policies.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_ag.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index a9993215bf9a30..a22c2be153a50c 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -284,7 +284,7 @@ xfs_initialize_perag(
 	int			error;
 
 	for (index = old_agcount; index < new_agcount; index++) {
-		pag = kzalloc(sizeof(*pag), GFP_KERNEL | __GFP_RETRY_MAYFAIL);
+		pag = kzalloc(sizeof(*pag), GFP_KERNEL);
 		if (!pag) {
 			error = -ENOMEM;
 			goto out_unwind_new_pags;


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

* [PATCH 41/41] xfs: update the pag for the last AG at recovery time
  2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
                     ` (39 preceding siblings ...)
  2024-10-31 23:19   ` [PATCH 40/41] xfs: don't use __GFP_RETRY_MAYFAIL in xfs_initialize_perag Darrick J. Wong
@ 2024-10-31 23:19   ` Darrick J. Wong
  40 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:19 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

From: Christoph Hellwig <hch@lst.de>

Source kernel commit: 4a201dcfa1ff0dcfe4348c40f3ad8bd68b97eb6c

Currently log recovery never updates the in-core perag values for the
last allocation group when they were grown by growfs.  This leads to
btree record validation failures for the alloc, ialloc or finotbt
trees if a transaction references this new space.

Found by Brian's new growfs recovery stress test.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Carlos Maiolino <cem@kernel.org>
---
 libxfs/xfs_ag.c |   17 +++++++++++++++++
 libxfs/xfs_ag.h |    1 +
 2 files changed, 18 insertions(+)


diff --git a/libxfs/xfs_ag.c b/libxfs/xfs_ag.c
index a22c2be153a50c..79ee483b42695a 100644
--- a/libxfs/xfs_ag.c
+++ b/libxfs/xfs_ag.c
@@ -271,6 +271,23 @@ xfs_agino_range(
 	return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
 }
 
+int
+xfs_update_last_ag_size(
+	struct xfs_mount	*mp,
+	xfs_agnumber_t		prev_agcount)
+{
+	struct xfs_perag	*pag = xfs_perag_grab(mp, prev_agcount - 1);
+
+	if (!pag)
+		return -EFSCORRUPTED;
+	pag->block_count = __xfs_ag_block_count(mp, prev_agcount - 1,
+			mp->m_sb.sb_agcount, mp->m_sb.sb_dblocks);
+	__xfs_agino_range(mp, pag->block_count, &pag->agino_min,
+			&pag->agino_max);
+	xfs_perag_rele(pag);
+	return 0;
+}
+
 int
 xfs_initialize_perag(
 	struct xfs_mount	*mp,
diff --git a/libxfs/xfs_ag.h b/libxfs/xfs_ag.h
index 6e68d6a3161a0f..9edfe0e9643964 100644
--- a/libxfs/xfs_ag.h
+++ b/libxfs/xfs_ag.h
@@ -150,6 +150,7 @@ int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t old_agcount,
 void xfs_free_perag_range(struct xfs_mount *mp, xfs_agnumber_t first_agno,
 		xfs_agnumber_t end_agno);
 int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
+int xfs_update_last_ag_size(struct xfs_mount *mp, xfs_agnumber_t prev_agcount);
 
 /* Passive AG references */
 struct xfs_perag *xfs_perag_get(struct xfs_mount *mp, xfs_agnumber_t agno);


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

* [PATCH 1/7] man: document file range commit ioctls
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
@ 2024-10-31 23:19   ` Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:19 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 2/7] libfrog: add support for commit range ioctl family
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
@ 2024-10-31 23:19   ` Darrick J. Wong
  2024-10-31 23:20   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:19 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 3/7] libxfs: remove unused xfs_inode fields
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
  2024-10-31 23:19   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
@ 2024-10-31 23:20   ` Darrick J. Wong
  2024-10-31 23:20   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:20 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 4/7] libxfs: validate inumber in xfs_iget
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (2 preceding siblings ...)
  2024-10-31 23:20   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
@ 2024-10-31 23:20   ` Darrick J. Wong
  2024-10-31 23:20   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:20 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 5/7] xfs_fsr: port to new file exchange library function
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (3 preceding siblings ...)
  2024-10-31 23:20   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
@ 2024-10-31 23:20   ` Darrick J. Wong
  2024-10-31 23:20   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:20 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-31 23:20   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
@ 2024-10-31 23:20   ` Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:20 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range
  2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
                     ` (5 preceding siblings ...)
  2024-10-31 23:20   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
@ 2024-10-31 23:21   ` Darrick J. Wong
  6 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:21 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 1/8] xfs_db: support passing the realtime device to the debugger
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
@ 2024-10-31 23:21   ` Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:21 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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..cece66a1cf825a 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);
+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] 73+ messages in thread

* [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
@ 2024-10-31 23:21   ` Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:21 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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 cece66a1cf825a..653724e90bd270 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] 73+ messages in thread

* [PATCH 3/8] xfs_db: make the daddr command target the realtime device
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
  2024-10-31 23:21   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
@ 2024-10-31 23:21   ` Darrick J. Wong
  2024-10-31 23:22   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:21 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 4/8] xfs_db: access realtime file blocks
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (2 preceding siblings ...)
  2024-10-31 23:21   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
@ 2024-10-31 23:22   ` Darrick J. Wong
  2024-10-31 23:22   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:22 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/block.c |   17 +++++++++++++++--
 db/block.h |   20 ++++++++++++++++++++
 db/faddr.c |    5 ++++-
 3 files changed, 39 insertions(+), 3 deletions(-)


diff --git a/db/block.c b/db/block.c
index 6ad9f038c6da67..87118a4751ef94 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], xfs_rtb_to_daddr(mp, dfsbno),
+				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/block.h b/db/block.h
index 7c4e8cb2acb051..55843a6b521393 100644
--- a/db/block.h
+++ b/db/block.h
@@ -3,8 +3,28 @@
  * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc.
  * All Rights Reserved.
  */
+#ifndef __XFS_DB_BLOCK_H
+#define __XFS_DB_BLOCK_H
 
 struct field;
 
 extern void	block_init(void);
 extern void	print_block(const struct field *fields, int argc, char **argv);
+
+static inline xfs_daddr_t
+xfs_rtb_to_daddr(
+	struct xfs_mount	*mp,
+	xfs_rtblock_t		rtb)
+{
+	return rtb << mp->m_blkbb_log;
+}
+
+static inline xfs_rtblock_t
+xfs_daddr_to_rtb(
+	struct xfs_mount	*mp,
+	xfs_daddr_t		daddr)
+{
+	return daddr >> mp->m_blkbb_log;
+}
+
+#endif /* __XFS_DB_BLOCK_H */
diff --git a/db/faddr.c b/db/faddr.c
index ec4aae68bb5a81..e2f9587da0a67c 100644
--- a/db/faddr.c
+++ b/db/faddr.c
@@ -15,6 +15,7 @@
 #include "bmap.h"
 #include "output.h"
 #include "init.h"
+#include "block.h"
 
 void
 fa_agblock(
@@ -323,7 +324,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], xfs_rtb_to_daddr(mp, bno), blkbb,
+			DB_RING_ADD, NULL);
 }
 
 /*ARGSUSED*/


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

* [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (3 preceding siblings ...)
  2024-10-31 23:22   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
@ 2024-10-31 23:22   ` Darrick J. Wong
  2024-10-31 23:22   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:22 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/block.c        |  109 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 man/man8/xfs_db.8 |   22 +++++++++++
 2 files changed, 131 insertions(+)


diff --git a/db/block.c b/db/block.c
index 87118a4751ef94..79ae0ea5802a83 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,103 @@ 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_daddr_to_rtb(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_rtb_to_daddr(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"
+));
+}
+
+/*
+ * Move the cursor to a specific location on the realtime block device given
+ * a linear address in units of realtime extents.
+ */
+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_daddr_to_rtb(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_rtb_to_daddr(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..48afcb6e81787b 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1099,6 +1099,28 @@ .SH COMMANDS
 Exit
 .BR xfs_db .
 .TP
+.BI "rtblock [" rtbno ]
+Set current address to the location on the realtime device given by
+.IR rtbno .
+This value must be a realtime block number.
+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 location on the realtime device given by
+.IR rtextent .
+This value must be a linear address in units of realtime extents.
+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] 73+ messages in thread

* [PATCH 6/8] xfs_db: enable conversion of rt space units
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-31 23:22   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
@ 2024-10-31 23:22   ` Darrick J. Wong
  2024-10-31 23:23   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
  2024-10-31 23:23   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
  7 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:22 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 db/convert.c      |  253 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 man/man8/xfs_db.8 |   51 +++++++++++
 2 files changed, 281 insertions(+), 23 deletions(-)


diff --git a/db/convert.c b/db/convert.c
index e1466057031da6..4c2ff1c5804c47 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -8,6 +8,7 @@
 #include "command.h"
 #include "output.h"
 #include "init.h"
+#include "block.h"
 
 #define	M(A)	(1 << CT_ ## A)
 #define	agblock_to_bytes(x)	\
@@ -26,6 +27,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 +45,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 +67,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 +84,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 +93,119 @@ 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 +232,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 +264,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 +335,99 @@ 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 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 +441,7 @@ void
 convert_init(void)
 {
 	add_command(&convert_cmd);
+	add_command(&rtconvert_cmd);
 }
 
 static int
@@ -290,6 +489,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 +504,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 48afcb6e81787b..0bf434299a3fb4 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1127,6 +1127,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] 73+ 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
                     ` (5 preceding siblings ...)
  2024-10-31 23:22   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
@ 2024-10-31 23:23   ` Darrick J. Wong
  2024-10-31 23:23   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
  7 siblings, 0 replies; 73+ 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] 73+ messages in thread

* [PATCH 8/8] xfs_db: convert rtsummary geometry
  2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
                     ` (6 preceding siblings ...)
  2024-10-31 23:23   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
@ 2024-10-31 23:23   ` Darrick J. Wong
  7 siblings, 0 replies; 73+ 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 summary.

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


diff --git a/db/convert.c b/db/convert.c
index 7c10690f574f7a..3014367e7d7652 100644
--- a/db/convert.c
+++ b/db/convert.c
@@ -53,6 +53,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;
 
@@ -77,6 +80,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);
@@ -105,6 +109,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] = {
@@ -181,39 +191,60 @@ static const ctydesc_t	ctydescs[NCTS] = {
 static const ctydesc_t	ctydescs_rt[NCTS] = {
 	[CT_BBOFF] = {
 		.allowed = M(DADDR) |
-			   M(RTBLOCK),
+			   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 = 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),
+			   M(BLKOFF) |
+			   M(RSUMLOG),
 		.names   = rtblock_names,
 	},
 	[CT_RTX] = {
 		.allowed = M(BBOFF) |
-			   M(BLKOFF),
+			   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 =
@@ -224,6 +255,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)
 {
@@ -258,6 +322,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;
@@ -361,6 +435,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;
@@ -373,6 +450,52 @@ convert_f(int argc, char **argv)
 	return 0;
 }
 
+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)
 {
@@ -384,6 +507,9 @@ rtconvert_f(int argc, char **argv)
 	uint64_t	v;
 	ctype_t		wtype;
 
+	rsumlog = -1;
+	rsuminfo = -1;
+
 	/* move past the "rtconvert" command */
 	argc--;
 	argv++;
@@ -452,6 +578,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:
@@ -535,6 +671,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 12fc4f3b51016b..ffa04879ce76c8 100644
--- a/man/man8/xfs_db.8
+++ b/man/man8/xfs_db.8
@@ -1183,10 +1183,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] 73+ messages in thread

* [PATCH 1/1] xfs_db: allow setting current address to log blocks
  2024-10-31 23:07 ` [PATCHSET v5.3 4/7] xfs_metadump: support external devices Darrick J. Wong
@ 2024-10-31 23:23   ` Darrick J. Wong
  0 siblings, 0 replies; 73+ 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>

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

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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 79ae0ea5802a83..b50b2c16060ac7 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;
 }
@@ -411,6 +430,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 ffa04879ce76c8..998553684586c7 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] 73+ messages in thread

* [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4
  2024-10-31 23:08 ` [PATCHSET v5.3 5/7] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
@ 2024-10-31 23:23   ` Darrick J. Wong
  2024-10-31 23:24   ` [PATCH 2/6] xfs_repair: use xfs_validate_rt_geometry Darrick J. Wong
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:23 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs, linux-xfs

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>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

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

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 b9986a00681c1e..a4e8fd08a90541 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] 73+ messages in thread

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

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] 73+ messages in thread

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

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 a4e8fd08a90541..8f3e9e8694675d 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] 73+ messages in thread

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

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] 73+ messages in thread

* [PATCH 6/6] xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino
  2024-10-31 23:08 ` [PATCHSET v5.3 5/7] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
                     ` (4 preceding siblings ...)
  2024-10-31 23:24   ` [PATCH 5/6] xfs_repair: use libxfs_rtfile_initialize_blocks Darrick J. Wong
@ 2024-10-31 23:25   ` Darrick J. Wong
  5 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:25 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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] 73+ messages in thread

* [PATCH 1/1] xfs_scrub_all: wait for services to start activating
  2024-10-31 23:08 ` [PATCHSET v31.3 6/7] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
@ 2024-10-31 23:25   ` Darrick J. Wong
  0 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:25 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs, linux-xfs

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")
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 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] 73+ messages in thread

* [PATCH 1/1] mkfs: add a config file for 6.12 LTS kernels
  2024-10-31 23:08 ` [PATCHSET 7/7] mkfs: new config file for 6.12 LTS Darrick J. Wong
@ 2024-10-31 23:25   ` Darrick J. Wong
  0 siblings, 0 replies; 73+ messages in thread
From: Darrick J. Wong @ 2024-10-31 23:25 UTC (permalink / raw)
  To: djwong, aalbersh; +Cc: linux-xfs

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

We didn't add any new ondisk features in 2023, so the config file is the
same.

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 mkfs/Makefile      |    3 ++-
 mkfs/lts_6.12.conf |   19 +++++++++++++++++++
 2 files changed, 21 insertions(+), 1 deletion(-)
 create mode 100644 mkfs/lts_6.12.conf


diff --git a/mkfs/Makefile b/mkfs/Makefile
index a6173083e4c2d4..754a17ea5137b7 100644
--- a/mkfs/Makefile
+++ b/mkfs/Makefile
@@ -16,7 +16,8 @@ CFGFILES = \
 	lts_5.10.conf \
 	lts_5.15.conf \
 	lts_6.1.conf \
-	lts_6.6.conf
+	lts_6.6.conf \
+	lts_6.12.conf
 
 LLDLIBS += $(LIBXFS) $(LIBXCMD) $(LIBFROG) $(LIBRT) $(LIBBLKID) \
 	$(LIBUUID) $(LIBINIH) $(LIBURCU) $(LIBPTHREAD)
diff --git a/mkfs/lts_6.12.conf b/mkfs/lts_6.12.conf
new file mode 100644
index 00000000000000..35b79082495d24
--- /dev/null
+++ b/mkfs/lts_6.12.conf
@@ -0,0 +1,19 @@
+# V5 features that were the mkfs defaults when the upstream Linux 6.12 LTS
+# kernel was released at the end of 2024.
+
+[metadata]
+bigtime=1
+crc=1
+finobt=1
+inobtcount=1
+reflink=1
+rmapbt=1
+autofsck=0
+
+[inode]
+sparse=1
+nrext64=1
+exchange=0
+
+[naming]
+parent=0


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

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

Thread overview: 73+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-31 22:57 [PATCHBOMB v3] xfsprogs: everything I have for 6.12 Darrick J. Wong
2024-10-31 23:07 ` [PATCHSET 1/7] libxfs: new code " Darrick J. Wong
2024-10-31 23:08   ` [PATCH 01/41] libxfs: require -std=gnu11 for compilation by default Darrick J. Wong
2024-10-31 23:09   ` [PATCH 02/41] libxfs: test compiling public headers with a C++ compiler Darrick J. Wong
2024-10-31 23:09   ` [PATCH 03/41] libxfs: port IS_ENABLED from the kernel Darrick J. Wong
2024-10-31 23:09   ` [PATCH 04/41] libfrog: add xarray emulation Darrick J. Wong
2024-10-31 23:10   ` [PATCH 05/41] xfs: introduce new file range commit ioctls Darrick J. Wong
2024-10-31 23:10   ` [PATCH 06/41] xfs: pass the icreate args object to xfs_dialloc Darrick J. Wong
2024-10-31 23:10   ` [PATCH 07/41] xfs: remove xfs_validate_rtextents Darrick J. Wong
2024-10-31 23:10   ` [PATCH 08/41] xfs: factor out a xfs_validate_rt_geometry helper Darrick J. Wong
2024-10-31 23:11   ` [PATCH 09/41] xfs: remove the limit argument to xfs_rtfind_back Darrick J. Wong
2024-10-31 23:11   ` [PATCH 10/41] xfs: assert a valid limit in xfs_rtfind_forw Darrick J. Wong
2024-10-31 23:11   ` [PATCH 11/41] xfs: add bounds checking to xfs_rt{bitmap,summary}_read_buf Darrick J. Wong
2024-10-31 23:11   ` [PATCH 12/41] xfs: factor out rtbitmap/summary initialization helpers Darrick J. Wong
2024-10-31 23:12   ` [PATCH 13/41] xfs: push transaction join out of xfs_rtbitmap_lock and xfs_rtgroup_lock Darrick J. Wong
2024-10-31 23:12   ` [PATCH 14/41] xfs: ensure rtx mask/shift are correct after growfs Darrick J. Wong
2024-10-31 23:12   ` [PATCH 15/41] xfs: remove xfs_rtb_to_rtxrem Darrick J. Wong
2024-10-31 23:12   ` [PATCH 16/41] xfs: simplify xfs_rtalloc_query_range Darrick J. Wong
2024-10-31 23:13   ` [PATCH 17/41] xfs: clean up the ISVALID macro in xfs_bmap_adjacent Darrick J. Wong
2024-10-31 23:13   ` [PATCH 18/41] xfs: remove xfs_{rtbitmap,rtsummary}_wordcount Darrick J. Wong
2024-10-31 23:13   ` [PATCH 19/41] xfs: replace m_rsumsize with m_rsumblocks Darrick J. Wong
2024-10-31 23:13   ` [PATCH 20/41] xfs: fix a sloppy memory handling bug in xfs_iroot_realloc Darrick J. Wong
2024-10-31 23:14   ` [PATCH 21/41] xfs: replace shouty XFS_BM{BT,DR} macros Darrick J. Wong
2024-10-31 23:14   ` [PATCH 22/41] xfs: standardize the btree maxrecs function parameters Darrick J. Wong
2024-10-31 23:14   ` [PATCH 23/41] xfs: use kvmalloc for xattr buffers Darrick J. Wong
2024-10-31 23:14   ` [PATCH 24/41] xfs: remove unnecessary check Darrick J. Wong
2024-10-31 23:15   ` [PATCH 25/41] xfs: use kfree_rcu_mightsleep to free the perag structures Darrick J. Wong
2024-10-31 23:15   ` [PATCH 26/41] xfs: move the tagged perag lookup helpers to xfs_icache.c Darrick J. Wong
2024-10-31 23:15   ` [PATCH 27/41] xfs: convert perag lookup to xarray Darrick J. Wong
2024-10-31 23:15   ` [PATCH 28/41] xfs: ensure st_blocks never goes to zero during COW writes Darrick J. Wong
2024-10-31 23:16   ` [PATCH 29/41] xfs: enable block size larger than page size support Darrick J. Wong
2024-10-31 23:16   ` [PATCH 30/41] xfs: merge xfs_attr_leaf_try_add into xfs_attr_leaf_addname Darrick J. Wong
2024-10-31 23:16   ` [PATCH 31/41] xfs: return bool from xfs_attr3_leaf_add Darrick J. Wong
2024-10-31 23:17   ` [PATCH 32/41] xfs: distinguish extra split from real ENOSPC from xfs_attr3_leaf_split Darrick J. Wong
2024-10-31 23:17   ` [PATCH 33/41] xfs: distinguish extra split from real ENOSPC from xfs_attr_node_try_addname Darrick J. Wong
2024-10-31 23:17   ` [PATCH 34/41] xfs: fold xfs_bmap_alloc_userdata into xfs_bmapi_allocate Darrick J. Wong
2024-10-31 23:17   ` [PATCH 35/41] xfs: don't ifdef around the exact minlen allocations Darrick J. Wong
2024-10-31 23:18   ` [PATCH 36/41] xfs: call xfs_bmap_exact_minlen_extent_alloc from xfs_bmap_btalloc Darrick J. Wong
2024-10-31 23:18   ` [PATCH 37/41] xfs: support lowmode allocations in xfs_bmap_exact_minlen_extent_alloc Darrick J. Wong
2024-10-31 23:18   ` [PATCH 38/41] xfs: pass the exact range to initialize to xfs_initialize_perag Darrick J. Wong
2024-10-31 23:18   ` [PATCH 39/41] xfs: merge the perag freeing helpers Darrick J. Wong
2024-10-31 23:19   ` [PATCH 40/41] xfs: don't use __GFP_RETRY_MAYFAIL in xfs_initialize_perag Darrick J. Wong
2024-10-31 23:19   ` [PATCH 41/41] xfs: update the pag for the last AG at recovery time Darrick J. Wong
2024-10-31 23:07 ` [PATCHSET v31.3 2/7] xfsprogs: atomic file content commits Darrick J. Wong
2024-10-31 23:19   ` [PATCH 1/7] man: document file range commit ioctls Darrick J. Wong
2024-10-31 23:19   ` [PATCH 2/7] libfrog: add support for commit range ioctl family Darrick J. Wong
2024-10-31 23:20   ` [PATCH 3/7] libxfs: remove unused xfs_inode fields Darrick J. Wong
2024-10-31 23:20   ` [PATCH 4/7] libxfs: validate inumber in xfs_iget Darrick J. Wong
2024-10-31 23:20   ` [PATCH 5/7] xfs_fsr: port to new file exchange library function Darrick J. Wong
2024-10-31 23:20   ` [PATCH 6/7] xfs_io: add a commitrange option to the exchangerange command Darrick J. Wong
2024-10-31 23:21   ` [PATCH 7/7] xfs_io: add atomic file update commands to exercise file commit range Darrick J. Wong
2024-10-31 23:07 ` [PATCHSET v5.3 3/7] xfs_db: debug realtime geometry Darrick J. Wong
2024-10-31 23:21   ` [PATCH 1/8] xfs_db: support passing the realtime device to the debugger Darrick J. Wong
2024-10-31 23:21   ` [PATCH 2/8] xfs_db: report the realtime device when associated with each io cursor Darrick J. Wong
2024-10-31 23:21   ` [PATCH 3/8] xfs_db: make the daddr command target the realtime device Darrick J. Wong
2024-10-31 23:22   ` [PATCH 4/8] xfs_db: access realtime file blocks Darrick J. Wong
2024-10-31 23:22   ` [PATCH 5/8] xfs_db: access arbitrary realtime blocks and extents Darrick J. Wong
2024-10-31 23:22   ` [PATCH 6/8] xfs_db: enable conversion of rt space units Darrick J. Wong
2024-10-31 23:23   ` [PATCH 7/8] xfs_db: convert rtbitmap geometry Darrick J. Wong
2024-10-31 23:23   ` [PATCH 8/8] xfs_db: convert rtsummary geometry Darrick J. Wong
2024-10-31 23:07 ` [PATCHSET v5.3 4/7] xfs_metadump: support external devices Darrick J. Wong
2024-10-31 23:23   ` [PATCH 1/1] xfs_db: allow setting current address to log blocks Darrick J. Wong
2024-10-31 23:08 ` [PATCHSET v5.3 5/7] mkfs/repair: use new rtbitmap helpers Darrick J. Wong
2024-10-31 23:23   ` [PATCH 1/6] xfs_repair: checking rt free space metadata must happen during phase 4 Darrick J. Wong
2024-10-31 23:24   ` [PATCH 2/6] xfs_repair: use xfs_validate_rt_geometry Darrick J. Wong
2024-10-31 23:24   ` [PATCH 3/6] mkfs: remove a pointless rtfreesp_init forward declaration Darrick J. Wong
2024-10-31 23:24   ` [PATCH 4/6] mkfs: use xfs_rtfile_initialize_blocks Darrick J. Wong
2024-10-31 23:24   ` [PATCH 5/6] xfs_repair: use libxfs_rtfile_initialize_blocks Darrick J. Wong
2024-10-31 23:25   ` [PATCH 6/6] xfs_repair: stop preallocating blocks in mk_rbmino and mk_rsumino Darrick J. Wong
2024-10-31 23:08 ` [PATCHSET v31.3 6/7] xfs_scrub_all: bug fix for 6.12 Darrick J. Wong
2024-10-31 23:25   ` [PATCH 1/1] xfs_scrub_all: wait for services to start activating Darrick J. Wong
2024-10-31 23:08 ` [PATCHSET 7/7] mkfs: new config file for 6.12 LTS Darrick J. Wong
2024-10-31 23:25   ` [PATCH 1/1] mkfs: add a config file for 6.12 LTS kernels 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