diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h
index 2ca7f018bc8..01868087ec4 100644
--- a/fs/ext4l/ext4_uboot.h
+++ b/fs/ext4l/ext4_uboot.h
@@ -253,28 +253,17 @@ void ext4_unregister_li_request(struct super_block *sb);
 
 /* ext4l support functions (support.c) */
 int bh_cache_sync(void);
-int ext4l_read_block(sector_t block, size_t size, void *buffer);
-int ext4l_write_block(sector_t block, size_t size, void *buffer);
+int ext4l_read_block(struct block_device *bdev, sector_t block, size_t size,
+		     void *buffer);
+int ext4l_write_block(struct block_device *bdev, sector_t block, size_t size,
+		      void *buffer);
 struct membuf *ext4l_get_msg_buf(void);
-void bh_cache_clear(void);
-void bh_cache_release_jbd(void);
+void bh_cache_clear(struct block_device *bdev);
+void bh_cache_release_jbd(struct block_device *bdev);
 void ext4l_crc32c_init(void);
 void ext4l_msg_init(void);
 void ext4l_print_msgs(void);
 void ext4l_record_msg(const char *msg, int len);
 
-/**
- * ext4l_get_blk() - Get the current block device
- *
- * Return: Block udevice, or NULL if not mounted
- */
-struct udevice *ext4l_get_blk(void);
-
-/**
- * ext4l_get_partition() - Get the current partition info
- *
- * Return: Partition info pointer, or NULL if not mounted
- */
-struct disk_partition *ext4l_get_partition(void);
 
 #endif /* __EXT4_UBOOT_H__ */
diff --git a/fs/ext4l/fs.c b/fs/ext4l/fs.c
index 85af18a017a..0a237add9cd 100644
--- a/fs/ext4l/fs.c
+++ b/fs/ext4l/fs.c
@@ -233,9 +233,8 @@ static ssize_t ext4l_read_iter(struct udevice *dev, struct iov_iter *iter,
 	loff_t actual;
 	int ret;
 
-	ret = ext4l_read(&fspriv->state, priv->path,
-			 iter_iov_ptr(iter), pos, iter_iov_avail(iter),
-			 &actual);
+	ret = ext4l_read(&fspriv->state, priv->path, iter_iov_ptr(iter), pos,
+			 iter_iov_avail(iter), &actual);
 	if (ret)
 		return log_msg_ret("efr", ret);
 	iter_advance(iter, actual);
diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c
index eded6538e99..f2a893ca752 100644
--- a/fs/ext4l/interface.c
+++ b/fs/ext4l/interface.c
@@ -31,29 +31,6 @@
 /* Global state for the legacy filesystem interface */
 static struct ext4l_state efs;
 
-/**
- * ext4l_get_blk() - Get the current block device
- *
- * Return: Block device descriptor or NULL if not mounted
- */
-struct udevice *ext4l_get_blk(void)
-{
-	if (!efs.mounted)
-		return NULL;
-
-	return efs.blk;
-}
-
-/**
- * ext4l_get_partition() - Get the current partition info
- *
- * Return: Partition info pointer
- */
-struct disk_partition *ext4l_get_partition(void)
-{
-	return &efs.partition;
-}
-
 /**
  * ext4l_get_uuid() - Get the filesystem UUID
  *
@@ -110,34 +87,6 @@ int ext4l_statfs(struct ext4l_state *state, struct fs_statfs *stats)
 	return 0;
 }
 
-/**
- * ext4l_set_blk() - Set the block device for ext4l operations
- *
- * @blk: Block device descriptor
- * @partition: Partition info (can be NULL for whole disk)
- */
-void ext4l_set_blk(struct udevice *blk, struct disk_partition *partition)
-{
-	efs.blk = blk;
-	if (partition)
-		memcpy(&efs.partition, partition, sizeof(efs.partition));
-	else
-		memset(&efs.partition, 0, sizeof(efs.partition));
-	efs.mounted = true;
-}
-
-/**
- * ext4l_clear_blk() - Clear block device (unmount)
- */
-void ext4l_clear_blk(void)
-{
-	/* Clear buffer cache before unmounting */
-	bh_cache_clear();
-
-	efs.blk = NULL;
-	efs.mounted = false;
-}
-
 /**
  * ext4l_free_sb() - Free superblock and associated resources
  * @sb: Superblock to free
@@ -209,6 +158,10 @@ static void ext4l_free_sb(struct super_block *sb, bool skip_io)
 	kfree(sbi->s_blockgroup_lock);
 	kfree(sbi);
 
+	/* Clear cached buffers for this device before freeing it */
+	bh_cache_release_jbd(sb->s_bdev);
+	bh_cache_clear(sb->s_bdev);
+
 	/* Free structures allocated in ext4l_mount() */
 	kfree(sb->s_bdev->bd_mapping);
 	kfree(sb->s_bdev);
@@ -235,17 +188,8 @@ static void ext4l_umount_internal(struct ext4l_state *state, bool skip_io)
 		ext4l_free_sb(sb, skip_io);
 
 	state->sb = NULL;
-
-	/*
-	 * Force cleanup of any remaining journal_heads before clearing
-	 * the buffer cache. This ensures no stale journal_head references
-	 * survive to the next mount. This is critical even when skip_io
-	 * is true - we MUST disconnect journal_heads before freeing
-	 * buffer_heads to avoid dangling pointers.
-	 */
-	bh_cache_release_jbd();
-
-	ext4l_clear_blk();
+	state->blk = NULL;
+	state->mounted = false;
 
 	/*
 	 * Clean up ext4 and JBD2 global state so it can be properly
@@ -269,7 +213,7 @@ static void ext4l_umount_internal(struct ext4l_state *state, bool skip_io)
 int ext4l_mount(struct ext4l_state *state, struct udevice *dev,
 		struct disk_partition *fs_partition)
 {
-	struct blk_desc *fs_dev_desc = dev_get_uclass_plat(dev);
+	struct blk_desc *desc = dev_get_uclass_plat(dev);
 	struct ext4_fs_context *ctx;
 	struct super_block *sb;
 	struct fs_context *fc;
@@ -336,10 +280,12 @@ int ext4l_mount(struct ext4l_state *state, struct udevice *dev,
 
 	/* Initialise super_block fields */
 	sb->s_bdev->bd_super = sb;
+	sb->s_bdev->bd_blk = dev;
+	sb->s_bdev->bd_part_start = fs_partition ? fs_partition->start : 0;
 	sb->s_blocksize = 1024;
 	sb->s_blocksize_bits = 10;
 	snprintf(sb->s_id, sizeof(sb->s_id), "ext4l_mmc%d",
-		 fs_dev_desc->devnum);
+		 desc->devnum);
 	sb->s_flags = 0;
 	sb->s_fs_info = NULL;
 
@@ -369,18 +315,18 @@ int ext4l_mount(struct ext4l_state *state, struct udevice *dev,
 	}
 
 	/* Calculate partition offset in bytes */
-	part_offset = fs_partition ? (loff_t)fs_partition->start * fs_dev_desc->blksz : 0;
+	part_offset = fs_partition ?
+		(loff_t)fs_partition->start * desc->blksz : 0;
 
 	/* Read sectors containing the superblock */
-	if (blk_dread(fs_dev_desc,
-		      div_u64(part_offset + BLOCK_SIZE, fs_dev_desc->blksz),
-		      2, buf) != 2) {
+	if (blk_read(dev, div_u64(part_offset + BLOCK_SIZE, desc->blksz),
+		     2, buf) != 2) {
 		ret = -EIO;
 		goto err_free_buf;
 	}
 
 	/* Check magic number within superblock */
-	magic = (__le16 *)(buf + (BLOCK_SIZE % fs_dev_desc->blksz) +
+	magic = (__le16 *)(buf + (BLOCK_SIZE % desc->blksz) +
 			   offsetof(struct ext4_super_block, s_magic));
 	if (le16_to_cpu(*magic) != EXT4_SUPER_MAGIC) {
 		ret = -EINVAL;
@@ -388,15 +334,20 @@ int ext4l_mount(struct ext4l_state *state, struct udevice *dev,
 	}
 
 	/* Set block device for buffer I/O */
-	ext4l_set_blk(dev, fs_partition);
+	state->blk = dev;
+	if (fs_partition)
+		memcpy(&state->partition, fs_partition,
+		       sizeof(state->partition));
+	else
+		memset(&state->partition, 0, sizeof(state->partition));
+	state->mounted = true;
 
 	/*
 	 * Test if device supports writes by writing back the same data.
 	 * If write returns 0, the device is read-only (e.g. LUKS/blkmap_crypt)
 	 */
-	if (blk_dwrite(fs_dev_desc,
-		       div_u64(part_offset + BLOCK_SIZE, fs_dev_desc->blksz),
-		       2, buf) != 2) {
+	if (blk_write(dev, div_u64(part_offset + BLOCK_SIZE, desc->blksz),
+		      2, buf) != 2) {
 		sb->s_bdev->read_only = true;
 		sb->s_flags |= SB_RDONLY;
 	}
@@ -706,6 +657,12 @@ static int ext4l_resolve_path(struct ext4l_state *state, const char *path,
 	return ext4l_resolve_path_internal(state, path, inodep, 0);
 }
 
+/* Context for ext4l_dir_actor carrying the superblock */
+struct ext4l_ls_ctx {
+	struct dir_context ctx;
+	struct super_block *sb;
+};
+
 /**
  * ext4l_dir_actor() - Directory entry callback for ext4_readdir
  *
@@ -721,6 +678,7 @@ static int ext4l_dir_actor(struct dir_context *ctx, const char *name,
 			   int namelen, loff_t offset, u64 ino,
 			   unsigned int d_type)
 {
+	struct ext4l_ls_ctx *ls_ctx = container_of(ctx, struct ext4l_ls_ctx, ctx);
 	struct inode *inode;
 	char namebuf[256];
 
@@ -731,7 +689,7 @@ static int ext4l_dir_actor(struct dir_context *ctx, const char *name,
 	namebuf[namelen] = '\0';
 
 	/* Look up the inode to get file size */
-	inode = ext4_iget(efs.sb, ino, 0);
+	inode = ext4_iget(ls_ctx->sb, ino, 0);
 	if (IS_ERR(inode)) {
 		printf(" %8s   %s\n", "?", namebuf);
 		return 0;
@@ -749,9 +707,9 @@ static int ext4l_dir_actor(struct dir_context *ctx, const char *name,
 
 int ext4l_ls(struct ext4l_state *state, const char *dirname)
 {
+	struct ext4l_ls_ctx ls_ctx;
 	struct inode *dir;
 	struct file file;
-	struct dir_context ctx;
 	int ret;
 
 	ret = ext4l_resolve_path(state, dirname, &dir);
@@ -770,10 +728,11 @@ int ext4l_ls(struct ext4l_state *state, const char *dirname)
 	if (!file.private_data)
 		return -ENOMEM;
 
-	memset(&ctx, 0, sizeof(ctx));
-	ctx.actor = ext4l_dir_actor;
+	memset(&ls_ctx, 0, sizeof(ls_ctx));
+	ls_ctx.ctx.actor = ext4l_dir_actor;
+	ls_ctx.sb = state->sb;
 
-	ret = ext4_readdir(&file, &ctx);
+	ret = ext4_readdir(&file, &ls_ctx.ctx);
 
 	if (file.private_data)
 		ext4_htree_free_dir_info(file.private_data);
@@ -1435,6 +1394,7 @@ struct ext4l_dir {
 struct ext4l_readdir_ctx {
 	struct dir_context ctx;
 	struct ext4l_dir *dir;
+	struct super_block *sb;
 };
 
 /**
@@ -1487,7 +1447,7 @@ static int ext4l_opendir_actor(struct dir_context *ctx, const char *name,
 	}
 
 	/* Look up inode to get size and other attributes */
-	inode = ext4_iget(efs.sb, ino, 0);
+	inode = ext4_iget(rctx->sb, ino, 0);
 	if (!IS_ERR(inode)) {
 		dent->size = inode->i_size;
 		/* Refine type from inode mode if needed */
@@ -1575,6 +1535,7 @@ int ext4l_readdir(struct ext4l_state *state, struct fs_dir_stream *dirs,
 	/* Set up extended dir_context for this iteration */
 	memset(&ctx, '\0', sizeof(ctx));
 	ctx.ctx.actor = ext4l_opendir_actor;
+	ctx.sb = state->sb;
 	ctx.ctx.pos = dir->file.f_pos;
 	ctx.dir = dir;
 
diff --git a/fs/ext4l/support.c b/fs/ext4l/support.c
index cd7c0b4b802..4fb97c6eae8 100644
--- a/fs/ext4l/support.c
+++ b/fs/ext4l/support.c
@@ -231,17 +231,20 @@ static inline unsigned int bh_cache_hash(sector_t block)
 
 /**
  * bh_cache_lookup() - Look up a buffer in the cache
+ * @bdev: Block device to match
  * @block: Block number to look up
  * @size: Expected block size
- * Return: Buffer head if found with matching size, NULL otherwise
+ * Return: Buffer head if found with matching device and size, NULL otherwise
  */
-static struct buffer_head *bh_cache_lookup(sector_t block, size_t size)
+static struct buffer_head *bh_cache_lookup(struct block_device *bdev,
+					   sector_t block, size_t size)
 {
 	unsigned int hash = bh_cache_hash(block);
 	struct bh_cache_entry *entry;
 
 	for (entry = bh_cache[hash]; entry; entry = entry->next) {
-		if (entry->bh && entry->bh->b_blocknr == block &&
+		if (entry->bh && entry->bh->b_bdev == bdev &&
+		    entry->bh->b_blocknr == block &&
 		    entry->bh->b_size == size) {
 			atomic_inc(&entry->bh->b_count);
 			return entry->bh;
@@ -259,9 +262,10 @@ static void bh_cache_insert(struct buffer_head *bh)
 	unsigned int hash = bh_cache_hash(bh->b_blocknr);
 	struct bh_cache_entry *entry;
 
-	/* Check if already in cache - must match block AND size */
+	/* Check if already in cache - must match device, block AND size */
 	for (entry = bh_cache[hash]; entry; entry = entry->next) {
-		if (entry->bh && entry->bh->b_blocknr == bh->b_blocknr &&
+		if (entry->bh && entry->bh->b_bdev == bh->b_bdev &&
+		    entry->bh->b_blocknr == bh->b_blocknr &&
 		    entry->bh->b_size == bh->b_size)
 			return;  /* Already cached */
 	}
@@ -309,30 +313,28 @@ static void bh_clear_stale_jbd(struct buffer_head *bh)
 	}
 }
 
-void bh_cache_clear(void)
+void bh_cache_clear(struct block_device *bdev)
 {
 	int i;
-	struct bh_cache_entry *entry, *next;
+	struct bh_cache_entry *entry, *next, **prev;
 
 	for (i = 0; i < BH_CACHE_SIZE; i++) {
-		for (entry = bh_cache[i]; entry; entry = next) {
+		prev = &bh_cache[i];
+		for (entry = *prev; entry; entry = next) {
 			next = entry->next;
-			if (entry->bh) {
+			if (entry->bh && entry->bh->b_bdev == bdev) {
 				struct buffer_head *bh = entry->bh;
 
 				bh_clear_stale_jbd(bh);
-				/*
-				 * Force count to 1 so the buffer will be freed.
-				 * On unmount, ext4 code won't access these
-				 * buffers again, so extra references are stale.
-				 */
 				atomic_set(&bh->b_count, 1);
 				if (atomic_dec_and_test(&bh->b_count))
 					free_buffer_head(bh);
+				*prev = next;
+				free(entry);
+			} else {
+				prev = &entry->next;
 			}
-			free(entry);
 		}
-		bh_cache[i] = NULL;
 	}
 }
 
@@ -343,14 +345,15 @@ void bh_cache_clear(void)
  * It ensures all journal_heads are properly released from buffer_heads
  * even if the journal destroy didn't fully clean up (e.g., on abort).
  */
-void bh_cache_release_jbd(void)
+void bh_cache_release_jbd(struct block_device *bdev)
 {
 	int i;
 	struct bh_cache_entry *entry;
 
 	for (i = 0; i < BH_CACHE_SIZE; i++) {
 		for (entry = bh_cache[i]; entry; entry = entry->next) {
-			if (entry->bh && buffer_jbd(entry->bh)) {
+			if (entry->bh && entry->bh->b_bdev == bdev &&
+			    buffer_jbd(entry->bh)) {
 				struct buffer_head *bh = entry->bh;
 				struct journal_head *jh = bh2jh(bh);
 
@@ -388,7 +391,8 @@ int bh_cache_sync(void)
 	for (i = 0; i < BH_CACHE_SIZE; i++) {
 		for (entry = bh_cache[i]; entry; entry = entry->next) {
 			if (entry->bh && buffer_dirty(entry->bh)) {
-				int err = ext4l_write_block(entry->bh->b_blocknr,
+				int err = ext4l_write_block(entry->bh->b_bdev,
+							    entry->bh->b_blocknr,
 							    entry->bh->b_size,
 							    entry->bh->b_data);
 				if (err && !ret)
@@ -499,29 +503,26 @@ void free_buffer_head(struct buffer_head *bh)
  * @buffer: Destination buffer
  * Return: 0 on success, negative on error
  */
-int ext4l_read_block(sector_t block, size_t size, void *buffer)
+int ext4l_read_block(struct block_device *bdev, sector_t block, size_t size,
+		     void *buffer)
 {
-	struct disk_partition *part;
-	lbaint_t sector, count;
 	struct blk_desc *desc;
-	struct udevice *blk;
-	ulong n;
+	lbaint_t sector, count;
+	long n;
 
-	blk = ext4l_get_blk();
-	part = ext4l_get_partition();
-	if (!blk)
+	if (!bdev || !bdev->bd_blk)
 		return -EIO;
 
-	desc = dev_get_uclass_plat(blk);
+	desc = dev_get_uclass_plat(bdev->bd_blk);
 
 	/* Convert block to sector */
-	sector = (block * size) / desc->blksz + part->start;
+	sector = (block * size) / desc->blksz + bdev->bd_part_start;
 	count = size / desc->blksz;
 
 	if (count == 0)
 		count = 1;
 
-	n = blk_read(blk, sector, count, buffer);
+	n = blk_read(bdev->bd_blk, sector, count, buffer);
 	if (n != count)
 		return -EIO;
 
@@ -535,29 +536,26 @@ int ext4l_read_block(sector_t block, size_t size, void *buffer)
  * @buffer: Source buffer
  * Return: 0 on success, negative on error
  */
-int ext4l_write_block(sector_t block, size_t size, void *buffer)
+int ext4l_write_block(struct block_device *bdev, sector_t block, size_t size,
+		      void *buffer)
 {
-	struct disk_partition *part;
-	lbaint_t sector, count;
 	struct blk_desc *desc;
-	struct udevice *blk;
-	ulong n;
+	lbaint_t sector, count;
+	long n;
 
-	blk = ext4l_get_blk();
-	part = ext4l_get_partition();
-	if (!blk)
+	if (!bdev || !bdev->bd_blk)
 		return -EIO;
 
-	desc = dev_get_uclass_plat(blk);
+	desc = dev_get_uclass_plat(bdev->bd_blk);
 
 	/* Convert block to sector */
-	sector = (block * size) / desc->blksz + part->start;
+	sector = (block * size) / desc->blksz + bdev->bd_part_start;
 	count = size / desc->blksz;
 
 	if (count == 0)
 		count = 1;
 
-	n = blk_write(blk, sector, count, buffer);
+	n = blk_write(bdev->bd_blk, sector, count, buffer);
 	if (n != count)
 		return -EIO;
 
@@ -578,7 +576,7 @@ struct buffer_head *sb_getblk(struct super_block *sb, sector_t block)
 		return NULL;
 
 	/* Check cache first - must match block number AND size */
-	bh = bh_cache_lookup(block, sb->s_blocksize);
+	bh = bh_cache_lookup(sb->s_bdev, block, sb->s_blocksize);
 	if (bh)
 		return bh;
 
@@ -622,7 +620,7 @@ struct buffer_head *__getblk(struct block_device *bdev, sector_t block,
 		return NULL;
 
 	/* Check cache first - must match block number AND size */
-	bh = bh_cache_lookup(block, size);
+	bh = bh_cache_lookup(bdev, block, size);
 	if (bh)
 		return bh;
 
@@ -673,7 +671,7 @@ struct buffer_head *sb_bread(struct super_block *sb, sector_t block)
 	bh->b_bdev = sb->s_bdev;
 	bh->b_size = sb->s_blocksize;
 
-	ret = ext4l_read_block(block, sb->s_blocksize, bh->b_data);
+	ret = ext4l_read_block(sb->s_bdev, block, sb->s_blocksize, bh->b_data);
 	if (ret) {
 		brelse(bh);
 		return NULL;
@@ -737,7 +735,7 @@ struct buffer_head *bdev_getblk(struct block_device *bdev, sector_t block,
 	struct buffer_head *bh;
 
 	/* Check cache first - must match block number AND size */
-	bh = bh_cache_lookup(block, size);
+	bh = bh_cache_lookup(bdev, block, size);
 	if (bh)
 		return bh;
 
@@ -782,7 +780,7 @@ struct buffer_head *__bread(struct block_device *bdev, sector_t block,
 	bh->b_bdev = bdev;
 	bh->b_size = size;
 
-	ret = ext4l_read_block(block, size, bh->b_data);
+	ret = ext4l_read_block(bdev, block, size, bh->b_data);
 	if (ret) {
 		free_buffer_head(bh);
 		return NULL;
@@ -824,7 +822,8 @@ int submit_bh(int op, struct buffer_head *bh)
 	int uptodate;
 
 	if (op_type == REQ_OP_READ) {
-		ret = ext4l_read_block(bh->b_blocknr, bh->b_size, bh->b_data);
+		ret = ext4l_read_block(bh->b_bdev, bh->b_blocknr, bh->b_size,
+				       bh->b_data);
 		if (ret) {
 			clear_buffer_uptodate(bh);
 			uptodate = 0;
@@ -833,7 +832,8 @@ int submit_bh(int op, struct buffer_head *bh)
 			uptodate = 1;
 		}
 	} else if (op_type == REQ_OP_WRITE) {
-		ret = ext4l_write_block(bh->b_blocknr, bh->b_size, bh->b_data);
+		ret = ext4l_write_block(bh->b_bdev, bh->b_blocknr, bh->b_size,
+					bh->b_data);
 		if (ret) {
 			clear_buffer_uptodate(bh);
 			set_buffer_write_io_error(bh);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0d6da467026..1bc50d46281 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -273,13 +273,17 @@ static inline void inode_state_assign(struct inode *inode, unsigned long flags)
 	inode->i_state = flags;
 }
 
-/* block_device - minimal stub */
+struct udevice;
+
+/* block_device - minimal stub with U-Boot block I/O fields */
 struct block_device {
 	struct address_space *bd_mapping;
 	void *bd_disk;
 	struct super_block *bd_super;
 	dev_t bd_dev;
 	bool read_only;
+	struct udevice *bd_blk;		/* U-Boot block device */
+	unsigned long bd_part_start;	/* partition start (in device sectors) */
 };
 
 /* errseq functions - stubs */
