[Concept,03/12] ext4l: Add write support and buffer mapping for mount

Message ID 20251223011632.380026-4-sjg@u-boot.org
State New
Headers
Series ext4l: Add support for listing directoties (Part H) |

Commit Message

Simon Glass Dec. 23, 2025, 1:16 a.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add ext4l_write_block() to enable writing blocks to disk, which is
needed for ext4_commit_super() during read-write mounts. Also update
submit_bh() to call the write function and return proper error codes.

Set the BH_Mapped flag in sb_getblk() and bdev_getblk() since ext4
checks this flag in ext4_commit_super() to verify the buffer is valid.

Co-developed-by: Claude <noreply@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 fs/ext4l/ext4_uboot.h |  2 +-
 fs/ext4l/support.c    | 55 +++++++++++++++++++++++++++++++++++++++----
 2 files changed, 52 insertions(+), 5 deletions(-)
  

Patch

diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h
index 4dd03494586..6dd498c8f52 100644
--- a/fs/ext4l/ext4_uboot.h
+++ b/fs/ext4l/ext4_uboot.h
@@ -2150,7 +2150,7 @@  struct blockgroup_lock {
 };
 
 /* Buffer submission stubs - declarations for stub.c implementations */
-void submit_bh(int op_flags, struct buffer_head *bh);
+int submit_bh(int op_flags, struct buffer_head *bh);
 struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
 				unsigned int size, gfp_t gfp);
 int trylock_buffer(struct buffer_head *bh);
diff --git a/fs/ext4l/support.c b/fs/ext4l/support.c
index 9e93426b565..05efa8d067c 100644
--- a/fs/ext4l/support.c
+++ b/fs/ext4l/support.c
@@ -352,6 +352,40 @@  int ext4l_read_block(sector_t block, size_t size, void *buffer)
 	return 0;
 }
 
+/**
+ * ext4l_write_block() - Write a block to the block device
+ * @block: Block number (filesystem block, not sector)
+ * @size: Block size in bytes
+ * @buffer: Source buffer
+ * Return: 0 on success, negative on error
+ */
+int ext4l_write_block(sector_t block, size_t size, void *buffer)
+{
+	struct blk_desc *blk_dev;
+	struct disk_partition *part;
+	lbaint_t sector;
+	lbaint_t sector_count;
+	unsigned long n;
+
+	blk_dev = ext4l_get_blk_dev();
+	part = ext4l_get_partition();
+	if (!blk_dev)
+		return -EIO;
+
+	/* Convert block to sector */
+	sector = (block * size) / blk_dev->blksz + part->start;
+	sector_count = size / blk_dev->blksz;
+
+	if (sector_count == 0)
+		sector_count = 1;
+
+	n = blk_dwrite(blk_dev, sector, sector_count, buffer);
+	if (n != sector_count)
+		return -EIO;
+
+	return 0;
+}
+
 /**
  * sb_getblk() - Get a buffer, using cache if available
  * @sb: Super block
@@ -379,6 +413,9 @@  struct buffer_head *sb_getblk(struct super_block *sb, sector_t block)
 	bh->b_bdev = sb->s_bdev;
 	bh->b_size = sb->s_blocksize;
 
+	/* Mark buffer as having a valid disk mapping */
+	set_buffer_mapped(bh);
+
 	/* Don't read - just allocate with zeroed data */
 	memset(bh->b_data, '\0', bh->b_size);
 
@@ -474,6 +511,9 @@  struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
 	bh->b_bdev = bdev;
 	bh->b_size = size;
 
+	/* Mark buffer as having a valid disk mapping */
+	set_buffer_mapped(bh);
+
 	/* Don't read - just allocate with zeroed data */
 	memset(bh->b_data, 0, bh->b_size);
 
@@ -520,8 +560,9 @@  struct buffer_head *__bread(struct block_device *bdev, sector_t block,
  * submit_bh() - Submit a buffer_head for I/O
  * @op: Operation (REQ_OP_READ, REQ_OP_WRITE, etc.)
  * @bh: Buffer head to submit
+ * Return: 0 on success, negative on error
  */
-void submit_bh(int op, struct buffer_head *bh)
+int submit_bh(int op, struct buffer_head *bh)
 {
 	int ret;
 	int op_type = op & 0xff;  /* Mask out flags, keep operation type */
@@ -530,13 +571,19 @@  void submit_bh(int op, struct buffer_head *bh)
 		ret = ext4l_read_block(bh->b_blocknr, bh->b_size, bh->b_data);
 		if (ret) {
 			clear_buffer_uptodate(bh);
-			return;
+			return ret;
 		}
 		set_buffer_uptodate(bh);
 	} else if (op_type == REQ_OP_WRITE) {
-		/* Write support not implemented yet */
-		clear_buffer_uptodate(bh);
+		ret = ext4l_write_block(bh->b_blocknr, bh->b_size, bh->b_data);
+		if (ret) {
+			clear_buffer_uptodate(bh);
+			return ret;
+		}
+		/* Mark buffer as clean (not dirty) after write */
 	}
+
+	return 0;
 }
 
 /**