public inbox for linux-btrfs@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] btrfs: get rid of btrfs_dio_private
@ 2025-10-20  5:57 Qu Wenruo
  2025-10-20  7:11 ` Johannes Thumshirn
  0 siblings, 1 reply; 4+ messages in thread
From: Qu Wenruo @ 2025-10-20  5:57 UTC (permalink / raw)
  To: linux-btrfs

For direct IO we need to record the file offset and size of the IO, thus
we have btrfs_dio_private structure and a dedicated bioset for it.

However for the file offset, we already btrfs_bio::file_offset, thus we
really only need a size.

Thankfully there is a hole inside btrfs_bio, between @fs_info and @bio, as
both members requires 8 bytes alignment (for 64bit systems).

The member @status and @csum_search_commit_root are both in single byte size,
leaving us 6 bytes to use.

So here we use a u32 to store the bio size, which should be more than
enough, and put the new @size member into that hole, so we can store a
new member without increasing the size of btrfs_bio.

Then we can safely remove btrfs_dio_private, the only exception is we
can not get rid of btrfs_dio_bioset, but this time we can just reuse the
existing btrfs_bio to handle everything.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/bio.c       |  4 ++++
 fs/btrfs/bio.h       |  2 ++
 fs/btrfs/direct-io.c | 34 +++++++++++-----------------------
 3 files changed, 17 insertions(+), 23 deletions(-)

diff --git a/fs/btrfs/bio.c b/fs/btrfs/bio.c
index 21df48e6c4fa..fc7182b5a8e3 100644
--- a/fs/btrfs/bio.c
+++ b/fs/btrfs/bio.c
@@ -809,7 +809,11 @@ void btrfs_submit_bbio(struct btrfs_bio *bbio, int mirror_num)
 	/* If bbio->inode is not populated, its file_offset must be 0. */
 	ASSERT(bbio->inode || bbio->file_offset == 0);
 
+	/* The bio should not exceed U32 size limit. */
+	ASSERT(bbio->bio.bi_iter.bi_size < U32_MAX);
+
 	assert_bbio_alignment(bbio);
+	bbio->size = bbio->bio.bi_iter.bi_size;
 
 	while (!btrfs_submit_chunk(bbio, mirror_num))
 		;
diff --git a/fs/btrfs/bio.h b/fs/btrfs/bio.h
index 00883aea55d7..e675937c356a 100644
--- a/fs/btrfs/bio.h
+++ b/fs/btrfs/bio.h
@@ -79,6 +79,8 @@ struct btrfs_bio {
 	/* File system that this I/O operates on. */
 	struct btrfs_fs_info *fs_info;
 
+	u32 size;
+
 	/* Save the first error status of split bio. */
 	blk_status_t status;
 
diff --git a/fs/btrfs/direct-io.c b/fs/btrfs/direct-io.c
index 802d4dbe5b38..4dd901dc4abc 100644
--- a/fs/btrfs/direct-io.c
+++ b/fs/btrfs/direct-io.c
@@ -19,15 +19,6 @@ struct btrfs_dio_data {
 	bool nocow_done;
 };
 
-struct btrfs_dio_private {
-	/* Range of I/O */
-	u64 file_offset;
-	u32 bytes;
-
-	/* This must be last */
-	struct btrfs_bio bbio;
-};
-
 static struct bio_set btrfs_dio_bioset;
 
 static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
@@ -642,25 +633,26 @@ static int btrfs_dio_iomap_end(struct inode *inode, loff_t pos, loff_t length,
 
 static void btrfs_dio_end_io(struct btrfs_bio *bbio)
 {
-	struct btrfs_dio_private *dip =
-		container_of(bbio, struct btrfs_dio_private, bbio);
 	struct btrfs_inode *inode = bbio->inode;
 	struct bio *bio = &bbio->bio;
 
+	/* We should have bbio->bytes populated. */
+	ASSERT(bbio->size);
+
 	if (bio->bi_status) {
 		btrfs_warn(inode->root->fs_info,
 		"direct IO failed ino %llu op 0x%0x offset %#llx len %u err no %d",
 			   btrfs_ino(inode), bio->bi_opf,
-			   dip->file_offset, dip->bytes, bio->bi_status);
+			   bbio->file_offset, bbio->size, bio->bi_status);
 	}
 
 	if (btrfs_op(bio) == BTRFS_MAP_WRITE) {
 		btrfs_finish_ordered_extent(bbio->ordered, NULL,
-					    dip->file_offset, dip->bytes,
+					    bbio->file_offset, bbio->size,
 					    !bio->bi_status);
 	} else {
-		btrfs_unlock_dio_extent(&inode->io_tree, dip->file_offset,
-					dip->file_offset + dip->bytes - 1, NULL);
+		btrfs_unlock_dio_extent(&inode->io_tree, bbio->file_offset,
+					bbio->file_offset + bbio->size - 1, NULL);
 	}
 
 	bbio->bio.bi_private = bbio->private;
@@ -709,19 +701,15 @@ static void btrfs_dio_submit_io(const struct iomap_iter *iter, struct bio *bio,
 				loff_t file_offset)
 {
 	struct btrfs_bio *bbio = btrfs_bio(bio);
-	struct btrfs_dio_private *dip =
-		container_of(bbio, struct btrfs_dio_private, bbio);
 	struct btrfs_dio_data *dio_data = iter->private;
+	const u32 bio_size = bio->bi_iter.bi_size;
 
 	btrfs_bio_init(bbio, BTRFS_I(iter->inode)->root->fs_info,
 		       btrfs_dio_end_io, bio->bi_private);
 	bbio->inode = BTRFS_I(iter->inode);
 	bbio->file_offset = file_offset;
 
-	dip->file_offset = file_offset;
-	dip->bytes = bio->bi_iter.bi_size;
-
-	dio_data->submitted += bio->bi_iter.bi_size;
+	dio_data->submitted += bio_size;
 
 	/*
 	 * Check if we are doing a partial write.  If we are, we need to split
@@ -736,7 +724,7 @@ static void btrfs_dio_submit_io(const struct iomap_iter *iter, struct bio *bio,
 		ret = btrfs_extract_ordered_extent(bbio, dio_data->ordered);
 		if (ret) {
 			btrfs_finish_ordered_extent(dio_data->ordered, NULL,
-						    file_offset, dip->bytes,
+						    file_offset, bio_size,
 						    !ret);
 			bio->bi_status = errno_to_blk_status(ret);
 			iomap_dio_bio_end_io(bio);
@@ -1093,7 +1081,7 @@ ssize_t btrfs_direct_read(struct kiocb *iocb, struct iov_iter *to)
 int __init btrfs_init_dio(void)
 {
 	if (bioset_init(&btrfs_dio_bioset, BIO_POOL_SIZE,
-			offsetof(struct btrfs_dio_private, bbio.bio),
+			offsetof(struct btrfs_bio, bio),
 			BIOSET_NEED_BVECS))
 		return -ENOMEM;
 
-- 
2.51.0


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

* Re: [PATCH] btrfs: get rid of btrfs_dio_private
  2025-10-20  5:57 [PATCH] btrfs: get rid of btrfs_dio_private Qu Wenruo
@ 2025-10-20  7:11 ` Johannes Thumshirn
  2025-10-20  7:16   ` Qu Wenruo
  0 siblings, 1 reply; 4+ messages in thread
From: Johannes Thumshirn @ 2025-10-20  7:11 UTC (permalink / raw)
  To: WenRuo Qu, linux-btrfs@vger.kernel.org

     /* size: 336, cachelines: 6, members: 13 */
     /* sum members: 334, holes: 1, sum holes: 2 */
     /* member types with holes: 1, total: 1 */
     /* forced alignments: 2, forced holes: 1, sum forced holes: 2 */
     /* last cacheline: 16 bytes */


We might want to shuffle some things around though.

Anyways, not relevant to this patch

Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>




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

* Re: [PATCH] btrfs: get rid of btrfs_dio_private
  2025-10-20  7:11 ` Johannes Thumshirn
@ 2025-10-20  7:16   ` Qu Wenruo
  2025-10-20  7:27     ` Christoph Hellwig
  0 siblings, 1 reply; 4+ messages in thread
From: Qu Wenruo @ 2025-10-20  7:16 UTC (permalink / raw)
  To: Johannes Thumshirn, linux-btrfs@vger.kernel.org



在 2025/10/20 17:41, Johannes Thumshirn 写道:
>       /* size: 336, cachelines: 6, members: 13 */
>       /* sum members: 334, holes: 1, sum holes: 2 */
>       /* member types with holes: 1, total: 1 */
>       /* forced alignments: 2, forced holes: 1, sum forced holes: 2 */
>       /* last cacheline: 16 bytes */
> 
> 
> We might want to shuffle some things around though.
> 
> Anyways, not relevant to this patch

Unfortunately fstests is not passing, test cases like btrfs/06[01] can 
fail with pretty high chance.

It looks like the bbio->file_offset is not safe, as btrfs_split_bio() 
can modify the original file offset, causing some bio ranges not 
properly released during dio reads.

Please ignore the patchset for now, we really want some stable 
file_offset/size that will not change due to split.

Thanks,
Qu

> 
> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> 
> 
> 


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

* Re: [PATCH] btrfs: get rid of btrfs_dio_private
  2025-10-20  7:16   ` Qu Wenruo
@ 2025-10-20  7:27     ` Christoph Hellwig
  0 siblings, 0 replies; 4+ messages in thread
From: Christoph Hellwig @ 2025-10-20  7:27 UTC (permalink / raw)
  To: Qu Wenruo; +Cc: Johannes Thumshirn, linux-btrfs@vger.kernel.org

On Mon, Oct 20, 2025 at 05:46:23PM +1030, Qu Wenruo wrote:
> 
> It looks like the bbio->file_offset is not safe, as btrfs_split_bio() can
> modify the original file offset, causing some bio ranges not properly
> released during dio reads.
> 
> Please ignore the patchset for now, we really want some stable
> file_offset/size that will not change due to split.

You can't make them stable because they must change for splits.

You could do what XFS/iomapo do: split the ordered extents on bio
boundaries, and then in the completion handler merge them again
for more efficient handling if there are enough queued up.

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

end of thread, other threads:[~2025-10-20  7:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-20  5:57 [PATCH] btrfs: get rid of btrfs_dio_private Qu Wenruo
2025-10-20  7:11 ` Johannes Thumshirn
2025-10-20  7:16   ` Qu Wenruo
2025-10-20  7:27     ` Christoph Hellwig

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