From: Kanchan Joshi <joshi.k@samsung.com>
To: brauner@kernel.org, hch@lst.de, djwong@kernel.org,
dgc@kernel.org, cem@kernel.org, jack@suse.cz, axboe@kernel.dk,
kbusch@kernel.org
Cc: linux-xfs@vger.kernel.org, linux-fsdevel@vger.kernel.org,
gost.dev@samsung.com, Kanchan Joshi <joshi.k@samsung.com>,
Anuj Gupta <anuj20.g@samsung.com>
Subject: [PATCH v5 5/8] xfs: write stream based AG placement
Date: Mon, 21 Sep 2026 15:01:44 +0530 [thread overview]
Message-ID: <20260921093147.59935-6-joshi.k@samsung.com> (raw)
In-Reply-To: <20260921093147.59935-1-joshi.k@samsung.com>
Choose the starting AG from the write stream set on the file.
Isolating streams into separate allocation groups reduces block
interleaving between concurrent writers, AGF lock contention and logical
file fragmentation.
AGs are partitioned among the streams. The stream value selects the AG
set and the inode number selects the AG within it, so intra-stream
concurrency comes from the AG set size.
Example: 8 Allocation Groups, 4 write streams
AG set size = 2 AGs per write stream
Stream 1 (ID: 1) Stream 2 (ID: 2) Streams 3 & 4
+---------+---------+ +---------+---------+ +-------------
| AG0 | AG1 | | AG2 | AG3 | | AG4...AG7
+---------+---------+ +---------+---------+ +-------------
^ ^ ^ ^
| | | |
| File B (ino: 101) | File D (ino: 201)
| 101 % 2 = 1 -> AG 1 | 201 % 2 = 1 -> AG 3
| |
File A (ino: 100) File C (ino: 200)
100 % 2 = 0 -> AG 0 200 % 2 = 0 -> AG 2
If the AGs do not divide evenly, the last stream absorbs the remainder.
Set boundaries are a hint, not a partition: file contiguity is preserved
and the full space stays usable with a single stream.
Signed-off-by: Kanchan Joshi <joshi.k@samsung.com>
Signed-off-by: Anuj Gupta <anuj20.g@samsung.com>
---
fs/xfs/libxfs/xfs_bmap.c | 58 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 56 insertions(+), 2 deletions(-)
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index d64defeda645..2e83811cefcb 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -3579,8 +3579,31 @@ xfs_bmap_btalloc_filestreams(
return xfs_bmap_btalloc_low_space(ap, args);
}
+static xfs_agnumber_t
+xfs_bmap_write_stream_agno(
+ struct xfs_inode *ip,
+ unsigned int stream_id)
+{
+ struct xfs_mount *mp = ip->i_mount;
+ xfs_agnumber_t nr_ags = mp->m_sb.sb_agcount;
+ unsigned int nr_streams =
+ write_stream_pool_count(&mp->m_ddev_targp->bt_stream_pool);
+ xfs_agnumber_t ag_set_size, start_agno;
+
+ stream_id -= 1; /* convert from 1-based to 0-based */
+ ag_set_size = nr_ags / nr_streams;
+ start_agno = stream_id * ag_set_size;
+
+ /* last stream absorbs any uneven remainder */
+ if (stream_id == nr_streams - 1)
+ ag_set_size = nr_ags - start_agno;
+
+ return start_agno + I_INO(ip) % ag_set_size;
+}
+
+/* Core AG allocator. The caller sets ap->blkno to the target AG start. */
static int
-xfs_bmap_btalloc_best_length(
+xfs_bmap_btalloc_from_blkno(
struct xfs_bmalloca *ap,
struct xfs_alloc_arg *args,
int stripe_align)
@@ -3588,7 +3611,6 @@ xfs_bmap_btalloc_best_length(
xfs_extlen_t blen = 0;
int error;
- ap->blkno = XFS_INODE_TO_FSB(ap->ip);
if (!xfs_bmap_adjacent(ap))
ap->eof = false;
@@ -3621,6 +3643,32 @@ xfs_bmap_btalloc_best_length(
return xfs_bmap_btalloc_low_space(ap, args);
}
+/* Start a write-stream file in the AG set that backs its stream. */
+static int
+xfs_bmap_btalloc_write_stream(
+ struct xfs_bmalloca *ap,
+ struct xfs_alloc_arg *args,
+ int stripe_align,
+ unsigned int stream_id)
+{
+ struct xfs_mount *mp = ap->ip->i_mount;
+ xfs_agnumber_t agno;
+
+ agno = xfs_bmap_write_stream_agno(ap->ip, stream_id);
+ ap->blkno = XFS_AGB_TO_FSB(mp, agno, 0);
+ return xfs_bmap_btalloc_from_blkno(ap, args, stripe_align);
+}
+
+static int
+xfs_bmap_btalloc_best_length(
+ struct xfs_bmalloca *ap,
+ struct xfs_alloc_arg *args,
+ int stripe_align)
+{
+ ap->blkno = XFS_INODE_TO_FSB(ap->ip);
+ return xfs_bmap_btalloc_from_blkno(ap, args, stripe_align);
+}
+
static int
xfs_bmap_btalloc(
struct xfs_bmalloca *ap)
@@ -3640,6 +3688,7 @@ xfs_bmap_btalloc(
};
xfs_fileoff_t orig_offset;
xfs_extlen_t orig_length;
+ unsigned int stream_id;
int error;
int stripe_align;
@@ -3652,11 +3701,16 @@ xfs_bmap_btalloc(
/* Trim the allocation back to the maximum an AG can fit. */
args.maxlen = min(ap->length, mp->m_ag_max_usable);
+ stream_id = READ_ONCE(VFS_I(ap->ip)->i_write_stream);
+
if (unlikely(XFS_TEST_ERROR(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 if ((ap->datatype & XFS_ALLOC_USERDATA) && stream_id)
+ error = xfs_bmap_btalloc_write_stream(ap, &args, stripe_align,
+ stream_id);
else
error = xfs_bmap_btalloc_best_length(ap, &args, stripe_align);
if (error)
--
2.25.1
next prev parent reply other threads:[~2026-09-21 9:32 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20260921093229epcas5p387ee10f88335ddc5fc930ca919769a60@epcas5p3.samsung.com>
2026-09-21 9:31 ` [PATCH v5 0/8] xfs write streams Kanchan Joshi
2026-09-21 9:31 ` [PATCH v5 1/8] fs: add write-stream management ioctls Kanchan Joshi
2026-09-21 9:31 ` [PATCH v5 2/8] fs: add generic write-stream management Kanchan Joshi
2026-09-21 9:31 ` [PATCH v5 3/8] fs: add i_write_stream, exclusive with the write life time hint Kanchan Joshi
2026-09-21 9:31 ` [PATCH v5 4/8] xfs: implement software write-stream management Kanchan Joshi
2026-09-21 9:31 ` Kanchan Joshi [this message]
2026-09-21 9:31 ` [PATCH v5 6/8] xfs: support write streams on realtime volumes Kanchan Joshi
2026-09-21 9:31 ` [PATCH v5 7/8] iomap: introduce and propagate write_stream Kanchan Joshi
2026-09-21 9:31 ` [PATCH v5 8/8] xfs: support hardware write streams Kanchan Joshi
2026-09-21 9:43 ` [PATCH v5 0/8] xfs " Kanchan Joshi
2026-09-21 23:23 ` Dave Chinner
2026-09-25 15:13 ` Kanchan Joshi
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260921093147.59935-6-joshi.k@samsung.com \
--to=joshi.k@samsung.com \
--cc=anuj20.g@samsung.com \
--cc=axboe@kernel.dk \
--cc=brauner@kernel.org \
--cc=cem@kernel.org \
--cc=dgc@kernel.org \
--cc=djwong@kernel.org \
--cc=gost.dev@samsung.com \
--cc=hch@lst.de \
--cc=jack@suse.cz \
--cc=kbusch@kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox