From patchwork Sat Apr 11 00:36:39 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2161 Return-Path: X-Original-To: u-boot-concept@u-boot.org Delivered-To: u-boot-concept@u-boot.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867836; bh=+0QzsUPkMU4w9TemMNw1SnfhB/YEvFzO2U0LpOHoauM=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=lmdALhqGZ3dJwI4PlSQiVausmXeNWXD45zgkJPOtT8EuC6o+mi8AS+s2ES8J7SVxl OzJnSvvhClhxzJFlzjYgeyyp4Er2BEkE3P3/CoeHZcVZMQxdAjRiaYfie2mpNPrYZI tam/mVPxgwtPKTxwkCeJtW0JgCmRqtS5ReaS8YwH9d8Rz0HTfMx+FmBwBTHaFgNfSh 2ld8Pt/eq+JtQl2ArKYqpxFoE4druSfB6cImW3enPbLI7z6opPBDmS587ia9J+sIq8 OTQQbNaH+iDriF9AX5YJQv+dEotPodKgZBcGo34mTvc9DD5oHj029vqDdN7iEPjGc6 fBC/r8LrtJQ9A== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 036846A42A for ; Fri, 10 Apr 2026 18:37:16 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10024) with ESMTP id Uz3GCD4LS9ER for ; Fri, 10 Apr 2026 18:37:15 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867835; bh=+0QzsUPkMU4w9TemMNw1SnfhB/YEvFzO2U0LpOHoauM=; h=From:To:Date:In-Reply-To:References:CC:Subject:List-Id: List-Archive:List-Help:List-Owner:List-Post:List-Subscribe: List-Unsubscribe:From; b=NBdU9wp+oXhn6MDfe3irzuCUvRdt+Q/X5Gnac3u6kmWhBVqQNV5ky8jfWpUAHayxu 6scmbP4l//QQXsLZZy0hBy5qiIFduxAewSrELklRzDAwDZLJRT6DJEAqYDz7DsbQcJ sbcap7vItIMODGeAWuXpvSQME1Wo1FfaJ5gfVil7MYc8L4bZtgxV8jQdLF35gmPILv 9SO1fJnMrR2v/LMhsyUGLWf4iXKeYVBoWOcpsDAdDhUMKtvk33ifV+OcJHX7nY67TA dPQyABYXGRacwpHASPBGbvpQl4My8DtPspa8I45BhZ2pTNbHrOJnHl3GCFZX8169RM HiJkIrgbFew8g== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DF49C6A425 for ; Fri, 10 Apr 2026 18:37:15 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867834; bh=+ULVTpTfKHXmC1ro4tb60jibCKA2e2/Q2tqULCU6dV8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=DwXn2HEBnUS4C49DTDM46puC8WRCETzhl2TNr3ALRKerr7Ky4x1SxiZC7KDFX6PeQ sUltBJCF6SAaD2tgj5NGvEqU1gS85NJOTNDjMK9ypdAK7Cq1iJ2ChVM82/sD34axlo VvC7YCOqk9a8nmYD97f7/8oPJaxt50IWJePrSsKmK9kkcsOa4Kzpc/14xF1fB5o3Kk FjtH9pX6JGDw7JwUzQNZwE6X7Nh6t8fMiTzIaBJbstO/Li3EqZn+SqOkEZDTHFM7+F qtui69aEm7uSS9cFyP9pVJZvWpu918Z3CtztQA7iNqhF+L5PjzU5bdDe6rOoY/lGU2 zmfxbBV3slT5Q== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 508C86A40D; Fri, 10 Apr 2026 18:37:14 -0600 (MDT) X-Virus-Scanned: Debian amavis at Received: from mail.u-boot.org ([127.0.0.1]) by localhost (mail.u-boot.org [127.0.0.1]) (amavis, port 10026) with ESMTP id HDN2oIp_2TwG; Fri, 10 Apr 2026 18:37:14 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867829; bh=mIIpPGPqMkvshz89voZKTCWwJe8+juoN0UU6LxGnZX0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=b7fFydZBrNaJZGkYkvf2li+Q/vk75y2GIejj2FNR0Mc9SOB4yFgZVrvMjmUCMQLvB RYDS5pgCVmNPDCYN3RBXcFRu61GCIgwnWwJcmM9uIRdt/u8tKYLLLnMARpWfZ/RkNI 1Iad/ODrwCYfe6yGW0gMKzYtahLypFOatV08U6xXJJNdUJyf3kYBP0JY4XorSXRTxp 24BMbiX3LLxT/s67Ix9IwLIT13ICzflzmsDgHQFufuEzzsu4PozqUKHaKq6tOtjRbG W6ejSinc7TkprjAOdJJb9hZBKsgIWzFh1WuBHp9PjnoiwHAc6gfpyqN9kOnpRRPcfT 5tEkjTFBwbf7g== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id AE1DD6A43A; Fri, 10 Apr 2026 18:37:09 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:39 -0600 Message-ID: <20260411003647.2592586-8-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260411003647.2592586-1-sjg@u-boot.org> References: <20260411003647.2592586-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: NIW753HFKATH3BSDHNDDAWLF34XS5UVK X-Message-ID-Hash: NIW753HFKATH3BSDHNDDAWLF34XS5UVK X-MailFrom: sjg@u-boot.org X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Simon Glass X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 7/8] ext4l: Route block I/O through the superblock, not globals List-Id: Discussion and patches related to U-Boot Concept Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Simon Glass Add bd_blk and bd_part_start fields to struct block_device so the buffer cache can perform I/O through the superblock without global state. Set these fields in ext4l_mount() and pass the block_device through ext4l_read_block() / ext4l_write_block(). Fix the dir_actor callbacks to obtain the superblock from context structs rather than the global efs.sb, using container_of() to access wrapper structs that carry the sb pointer. Make bh_cache_clear() and bh_cache_release_jbd() take a block_device pointer so they only clear buffers belonging to the mount being unmounted. Move cache clearing into ext4l_free_sb() before the block_device is freed. This prevents unmounting one filesystem from corrupting another's cached buffers. Include the block_device pointer in buffer cache lookups so cached blocks from different mounts do not collide. Update the VFS fs.c to call ext4l_mount() / ext4l_umount() and the state-taking API directly, with per-device state stored in priv_auto. Each UCLASS_FS device now has its own ext4l_state, enabling multiple concurrent ext4l mounts through the VFS layer. The legacy interface (ext4l_probe / ext4l_close and _legacy wrappers) still uses the global state for the single-mount fs_legacy path. Signed-off-by: Simon Glass --- fs/ext4l/ext4_uboot.h | 23 +++----- fs/ext4l/fs.c | 5 +- fs/ext4l/interface.c | 119 ++++++++++++++---------------------------- fs/ext4l/support.c | 96 +++++++++++++++++----------------- include/linux/fs.h | 6 ++- 5 files changed, 101 insertions(+), 148 deletions(-) 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 */