From patchwork Sat Apr 11 00:36:33 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2156 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=1775867827; bh=YyXc4Uou6tmR+ID7W7EUzxVcsqDd6dfoIYRDmezL7Lw=; 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=Zfx2greHSwrNItFKrdQV7JjhWohkfpw+UjAa0+xGnloIg8u+LpR0eFg6CuphkMHRv fg2el7m6PaTBsXNQavdr3RVDhEFNM0w7LGZxVpJ097O1SAJV0uaP5igzd+cQCNdvjV 9PxCKPKtNOtmosfw09+SOl0pZ/cuLtvA7T84vemNSmXgD49ri3O+u3Mbj7YZf40Cv5 r6xmCg99IEsRXu/NuZW64OydxpzWTCizCV9AFwa41IiXag/R+MXoNryouleRLyEYMI 1cRXGEsiOcXiXlccBJ91Xd16X2roKC7Iw6eJ6Dw8n7MxUV55ioxYm0+1IQAQkkv0b3 TBtuWcUFT2G2w== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B19D56A42C for ; Fri, 10 Apr 2026 18:37:07 -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 zhiC11OMGn1t for ; Fri, 10 Apr 2026 18:37:07 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867825; bh=YyXc4Uou6tmR+ID7W7EUzxVcsqDd6dfoIYRDmezL7Lw=; 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=MsimwAUUhI43JdIn9vNkolmEwI17rxQz+6TGb+UJRCxDEgXk7U6UftJVHuiFR6dRD NwIql4Oj0YT1L0VyA3OXwfHFO1Gx0VUbQtVJ9n6Thw0lk4sJHrvgJKGeWAOlm0J61Q BPljuTpMPuTm/8pDwSDZMdfpu84PzBg4zxMiqfDdiHYvWIazKs5nk8+Lqrl2BNrAXU uImzl4HdAE3yJpod2aDvLGnBWHSWZxXuuKY+jwG9oyMpR4Fi590i/x+bh2q3pdRgl5 yPv2rryXScqAU/J6qCW0SKih23wf2ZLRLpXlGYJbuafcfC6roHa2eUnTPyfQ9Avc7l QLDPSbGqu6ukA== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id B07C96A3B8 for ; Fri, 10 Apr 2026 18:37:05 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867823; bh=2ROWUzImjObY5SHhn1ie5v2cSj7nr0DF81+s0feaw0U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=d0D606O4NRuUidiYFPoMhwoaWPRpdU7ID3uxfxdlEfpzt24NzMPizTZ7joawU6YCh VoIliQAESd/fp2wcwpTzfuGcvtO2fO/CR5h6mO6qIxuNUO3z9op+NL6LA4DLQzDG/P djaKKAntaFO78MuRT1GNiY36cT1LwfWhYLkLFY/a9Ohb/QvUMcYM22VPKFvgsMbUBb Kx6M1H3WOXZoKVbZMx4E2wuNIkKalhVwMmgXt9WPiJTwtW6ufQVxFBcM7ATsqGmutN 4sJXcg3rqvXaLWW/+dR5fVQ+rNDqcqx8ZF+tNJoOPBEKz+T5heDcvX+MC1qrJuOBxU yRhxfWwyACbZw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 0D50B6A42C; Fri, 10 Apr 2026 18:37:03 -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 rhVKtzPZya4R; Fri, 10 Apr 2026 18:37:02 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867820; bh=b6B8JJPSQBz1pOAHy2Xj0D0Loc6BVwprd/3Td32X1cE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o0CgQIex7LCC1sXVkK0Q/5EP4nacb7oumSRkDITk6UeY5GRtACZWBvSHatpOe7XG2 T4/e4rshS9NxsKcrbqN+AJW4yNE2XgM2ntfyhZF0fJiKwkHUzJGEqfKUkAkUmv7rdP elEBofugwR6/8rWUKnpeMEhEN0dePn+MKmPKmk+ZtOaOUEMkxmtPiwHlicE9L2C9xF h2eqXDskhM8badHKK84+YPl1yyvqd04JbxAg6oZdDZfYjewru6kQHdRbTVmR0eVhGJ DTH0KDKw1AwHw96IuTD8aZO1CUUn/nbnutbhQ1guZEKF+msciwAVx8TXD9CVxkDFUH VvbAWiBDcJKTA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 8A49A6A3B8; Fri, 10 Apr 2026 18:37:00 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:33 -0600 Message-ID: <20260411003647.2592586-2-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: 4WVPPVVT77AIB5ZYMKZTNEAEQVTO4L3F X-Message-ID-Hash: 4WVPPVVT77AIB5ZYMKZTNEAEQVTO4L3F 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 1/8] ext4l: Remove ext4l_resolve_path_internal() forward decl 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 Move ext4l_resolve_path_internal() before ext4l_resolve_path() so the forward declaration is no longer needed. Signed-off-by: Simon Glass --- fs/ext4l/interface.c | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c index 9a3fda48300..d854c310be3 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -502,22 +502,6 @@ static int ext4l_read_symlink(struct inode *inode, char *target, size_t max_len) return len; } -/* Forward declaration for recursive resolution */ -static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, - int depth); - -/** - * ext4l_resolve_path() - Resolve path to inode - * - * @path: Path to resolve - * @inodep: Output inode pointer - * Return: 0 on success, negative on error - */ -static int ext4l_resolve_path(const char *path, struct inode **inodep) -{ - return ext4l_resolve_path_internal(path, inodep, 0); -} - /** * ext4l_resolve_path_internal() - Resolve path with symlink following * @@ -709,6 +693,18 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, return 0; } +/** + * ext4l_resolve_path() - Resolve path to inode + * + * @path: Path to resolve + * @inodep: Output inode pointer + * Return: 0 on success, negative on error + */ +static int ext4l_resolve_path(const char *path, struct inode **inodep) +{ + return ext4l_resolve_path_internal(path, inodep, 0); +} + /** * ext4l_dir_actor() - Directory entry callback for ext4_readdir * From patchwork Sat Apr 11 00:36:34 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2158 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=1775867830; bh=vu+UuXsjT/kwCvM0OF8XAMBDBMUWVGHnRysQQVyZQQI=; 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=LVPZ0yqA+7yzdyvmUvHrj/yH7Z0lq6LwNrc+JFwjUPvgM1qy7cGkzY+iDOvDtrWUZ BL2Zb+kgNzQWJb0Mf7XR3O5yoWsShg3rTolfCgfzJ/AWhge+phHc1FFun0CGdyBuJD oizhL7jjKKyU/zNFqPOuxXJp/eZhrHiu2FIJIaUFPfmsjPEjJ/btSblo/0iacuuDLq YdyM2Rt93RcrRQM/fbPeiplk4GTcK3zuwrWMPg12Y6e125WxIJyslFp7NXDpr/zIl7 8z6fTtkQF/irquKtZW5wRX4Aijx1hYgrfG0DM9hBgEe+gPwfcH6+iK8l+aMnL+LBXo S0lj3fHggMgSQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9B5DB6A446 for ; Fri, 10 Apr 2026 18:37:10 -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 6c5s45xX4RVZ for ; Fri, 10 Apr 2026 18:37:10 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867829; bh=vu+UuXsjT/kwCvM0OF8XAMBDBMUWVGHnRysQQVyZQQI=; 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=kbI5ToHvNvOeKcPz1gxoVYi/xJse0johyVr4xtgGREyrB6YF9fy+jDQutfZNGd1Ho j+j9zxbDLfMyUZWHMHHq17x/1GmqFUDDPfVrnQ6NTA5HP4xaVeayLdSVmPZaIbuyYt L0wF9BCy9p3hwEMVjKRol/WSzG7gvRfjo77XwYg1QttLStwvnoCQbTZKARG4qaWG+T aJtIkXxQaMbwEWnnv5aXVbkrcTB9vzIbNlsg2gPBqfo2Iyf6U9SPcIvjMElnJ0Kqgy vCtPsMtZ5dgXl/sAKbWT5UHu1x8vu75IF0jUM3bKGZYImbc67oc1MBVapd1YDM9krT ZD3uzt4Jbg4+Q== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 432176A434 for ; Fri, 10 Apr 2026 18:37:09 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867825; bh=r3dNsy+gn0xB5oE2FIkYkq82NOH7taPK2MzQrvXO4+o=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=tsBakkxgB7Vwx5Mnhqeymv5JcTGBJUPjJsSdg0CFOxww7a/F0YSln+N8WZOOxR+zn Ao0YvD4/bT1aSnsMBBe354oDAtxxIs3/tayulD9uHprRgvqZxKJKq2Z+ldinD4QSqi Ew9fRKo3Q27g3fy5tNQtso8D14uIVKL0QuYB/vHrY2De9u5onmhN+S8UOnGXhZlXZi /iB1U6D0IYAXHF4FX7NuFxDurJ0CXyR3hqN9wkOmTs2ybrZ78t1VSAYvUU0R1m0Igp 5jNYkKz1BvZZ0qrnXrstui8lMDd384QofUSLAKCSxCCNY9bg569eyTYCUhUCv8MOT5 nZm0/pEZUIbtQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 83BC66A429; Fri, 10 Apr 2026 18:37:05 -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 eANq4s2bRLuL; Fri, 10 Apr 2026 18:37:05 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867821; bh=xEjCQBrMWNIdUmwX2XZ0LI/TAsZ+ITQ/3obWEKJpvwE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=f3vjBuz843iPexiay7dl/gfHVyodWr8mIYJZRE6RtCVS++mz+ARTXJrewnvwoUYbX Qljoq1INzp0VXLD30gNJ3Izde2tYjGxaRHonYCKlVEquqrabXXKsYvQIVXssnzh4dn y6AFK8QdywDFEjvriYER5Axwz4wn6tqmh0/HhxWPAEBcqv8q/1I5mwfEFS9fn8plVL vjPyrha93JmK0xy8N/8mHNQDeESG8CEjA2cyDuEpVTsgalHcv1GI6+bVqq1jTJG4b2 AXiL1Vd2uPcgMnAGd92HPcW6S3HMmoS1sMv2i+iQD5gD1+oA2UEoiEnUmLyse4HkRW ck863YlmMPwWQ== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id A0F4B6A42B; Fri, 10 Apr 2026 18:37:01 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:34 -0600 Message-ID: <20260411003647.2592586-3-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: PX556J556OAVY2CT2W5Y4JUO2ZHD2MWO X-Message-ID-Hash: PX556J556OAVY2CT2W5Y4JUO2ZHD2MWO 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 2/8] ext4l: Use struct udevice for block I/O instead of blk_desc 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 The blk_dread() and blk_dwrite() functions take a struct blk_desc, but this is a legacy interface meant to be replaced by blk_read() and blk_write() which take a struct udevice. Convert ext4l's block I/O layer to store a struct udevice pointer instead of struct blk_desc, and use blk_read() / blk_write() for block device access in support.c. The blk_desc is obtained from the udevice via dev_get_uclass_plat() for the block size. The probe path obtains the udevice from the blk_desc's bdev field. Tidy up the code style in the read/write functions while here. Signed-off-by: Simon Glass --- fs/ext4l/ext4_uboot.h | 14 ++++++++++-- fs/ext4l/interface.c | 11 +++++---- fs/ext4l/support.c | 53 +++++++++++++++++++++++-------------------- 3 files changed, 47 insertions(+), 31 deletions(-) diff --git a/fs/ext4l/ext4_uboot.h b/fs/ext4l/ext4_uboot.h index 24402f21790..2ca7f018bc8 100644 --- a/fs/ext4l/ext4_uboot.h +++ b/fs/ext4l/ext4_uboot.h @@ -263,8 +263,18 @@ void ext4l_msg_init(void); void ext4l_print_msgs(void); void ext4l_record_msg(const char *msg, int len); -/* ext4l interface functions (interface.c) */ -struct blk_desc *ext4l_get_blk_dev(void); +/** + * 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/interface.c b/fs/ext4l/interface.c index d854c310be3..893f71c1f1c 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -31,7 +31,7 @@ static struct blk_desc *ext4l_dev_desc; static struct disk_partition ext4l_part; /* Global block device tracking for buffer I/O */ -static struct blk_desc *ext4l_blk_dev; +static struct udevice *ext4l_blk_dev; static struct disk_partition ext4l_partition; static int ext4l_mounted; @@ -42,11 +42,11 @@ static int ext4l_open_dirs; static struct super_block *ext4l_sb; /** - * ext4l_get_blk_dev() - Get the current block device + * ext4l_get_blk() - Get the current block device * * Return: Block device descriptor or NULL if not mounted */ -struct blk_desc *ext4l_get_blk_dev(void) +struct udevice *ext4l_get_blk(void) { if (!ext4l_mounted) return NULL; @@ -123,7 +123,8 @@ int ext4l_statfs(struct fs_statfs *stats) * @blk_dev: Block device descriptor * @partition: Partition info (can be NULL for whole disk) */ -void ext4l_set_blk_dev(struct blk_desc *blk_dev, struct disk_partition *partition) +void ext4l_set_blk_dev(struct udevice *blk_dev, + struct disk_partition *partition) { ext4l_blk_dev = blk_dev; if (partition) @@ -408,7 +409,7 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, memcpy(&ext4l_part, fs_partition, sizeof(ext4l_part)); /* Set block device for buffer I/O */ - ext4l_set_blk_dev(fs_dev_desc, fs_partition); + ext4l_set_blk_dev(fs_dev_desc->bdev, fs_partition); /* * Test if device supports writes by writing back the same data. diff --git a/fs/ext4l/support.c b/fs/ext4l/support.c index 4025d291fec..cd7c0b4b802 100644 --- a/fs/ext4l/support.c +++ b/fs/ext4l/support.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -500,26 +501,28 @@ void free_buffer_head(struct buffer_head *bh) */ int ext4l_read_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; + lbaint_t sector, count; + struct blk_desc *desc; + struct udevice *blk; + ulong n; - blk_dev = ext4l_get_blk_dev(); + blk = ext4l_get_blk(); part = ext4l_get_partition(); - if (!blk_dev) + if (!blk) return -EIO; + desc = dev_get_uclass_plat(blk); + /* Convert block to sector */ - sector = (block * size) / blk_dev->blksz + part->start; - sector_count = size / blk_dev->blksz; + sector = (block * size) / desc->blksz + part->start; + count = size / desc->blksz; - if (sector_count == 0) - sector_count = 1; + if (count == 0) + count = 1; - n = blk_dread(blk_dev, sector, sector_count, buffer); - if (n != sector_count) + n = blk_read(blk, sector, count, buffer); + if (n != count) return -EIO; return 0; @@ -534,26 +537,28 @@ int ext4l_read_block(sector_t block, size_t size, void *buffer) */ 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; + lbaint_t sector, count; + struct blk_desc *desc; + struct udevice *blk; + ulong n; - blk_dev = ext4l_get_blk_dev(); + blk = ext4l_get_blk(); part = ext4l_get_partition(); - if (!blk_dev) + if (!blk) return -EIO; + desc = dev_get_uclass_plat(blk); + /* Convert block to sector */ - sector = (block * size) / blk_dev->blksz + part->start; - sector_count = size / blk_dev->blksz; + sector = (block * size) / desc->blksz + part->start; + count = size / desc->blksz; - if (sector_count == 0) - sector_count = 1; + if (count == 0) + count = 1; - n = blk_dwrite(blk_dev, sector, sector_count, buffer); - if (n != sector_count) + n = blk_write(blk, sector, count, buffer); + if (n != count) return -EIO; return 0; From patchwork Sat Apr 11 00:36:35 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2157 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=1775867830; bh=NlEFWx0qORF4Q5+HwxJBoXVOnS3ZjRg8CFPcdIJJcEM=; 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=uCCbmb+ThuswA58FLgqALvzkA/tupzhZnRbzNSbe5GN/bwDd60/G6N307Tb+YRv3V MxzAYg9c8Yb05v52UBRVHdia8yatn572uZIkwHe5FDZjZmDKXl7Ce8ltd+YnmJCBkV DTdvypfpXMAwlgvM43NaLb1A0LJtK6aRJSO19Os8tlui9/D9A7QrrLLhb41l4UwgTa BTEF1N4FTn8TqLV/LYSHnsswzcvuT5AN8mrUUntaxqQiSQLOinNzY5va/D5KuIM4og m9zmCqg1pSsKuZTlQlxconmRvp7FOD/35qMrZtSgvlFFcWxHI33Kys3gt5HAGTxWpq Rb/J9alOLU2gQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 1790E6A440 for ; Fri, 10 Apr 2026 18:37:10 -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 wjMlGJVFIMYC for ; Fri, 10 Apr 2026 18:37:10 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867828; bh=NlEFWx0qORF4Q5+HwxJBoXVOnS3ZjRg8CFPcdIJJcEM=; 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=S3vsS5iet6Kdbce6IhWn9ZpH9kvKu2kAlcDx4jZECB/yRuL3U6sugarE6T2p0be4B 5Mjr8cWCM2V4/M44Eig4Il4I4ODzQYgxPj47cGWLaKDvyv3STFPGOJXYJ+Hxf4pmF8 mproUnD2pZg2USn+o+zDEQTRdT5+rteSA/KFIkw5/4WZnXbRun7JhSDWczvUoO1NtK ccB4gpEQ6iosgex/qWhnn+HLiuZLA4mNAq2UmkxBibg7yW4RLkLtmfy0bH047sCz6i 201dZLzQJac60/ob3mi/iguCgBibfzFGRTzkwpwQwNZugQnhUn9+lIiD90WQ7Y1vzi x70fqkqgxAjfQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C9D016A429 for ; Fri, 10 Apr 2026 18:37:08 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867825; bh=TvU4Ke8Sqenci+TKcDccJ4eqc8tV/xbYCF3UW+FVcW8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rnhkJfRb5OAtnLDFtFVhDTBF2SPbRpdWZlcmQx0N7Yg2SWxAY28++M3DiNnY8M5uM okwaDoM8fE5YQN0qEGi0QeDz3wxkpIWZWhyICp54GQ3BGJkUGk0CYTIq0/J5YNe/Ml tIIfNC9vRzQ60suEh04mkG8NudcsSgZrKMEPKCtAq7hs6vCpGlk+6b83Cj/w4lxQV5 Hj36ejZNOK80NG86p4O5a0ExVJFch3SD4mvho+UrIHzyOIsDGTl9ZFSJecPodQKsyA cbrDSyU4AHai90VMY50noQLgut9YrBeEx81VOjCnbHnVfpuw+aBOx40YdH7cS7JgGH t/H+bM5PhUiLg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 83FD56A42A; Fri, 10 Apr 2026 18:37:05 -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 ohShOiMc-o41; Fri, 10 Apr 2026 18:37:05 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867823; bh=2mlmY3ldGqSgc8Pn/GgYqdFDkd8LZnr43+OXjIA6xWI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fBepD93LYmu7fwmafQON/C/Z/03tcpaqBLJe5UcyDl5Bpycd1wzjLZkEsCelqw9Df cgVlfZER5+yIMBTr/y9b9HDT3cyYON7gwoZE10dchEuzoJwG53kVXAtz29KU4Vek98 Xkp+6JxzbTpPc76K3QwHyQfu7G6lz1i3ximQTZIvfFfsk0lTak/Towv8QeLCvX3Q1z jtSI5/gUy4yevESn4fgoMzYQwrXKS5yysM5zmlGlHMk+gVqmJEieh+2Hvi4iNabeL3 ittR/7v9+UcTs0R7gohC0/YiRMwcn/QWuC536XzDjhHMqR3jNjvaw8u2LajiCewBKy taVphqSE/5qNg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id C72606A42E; Fri, 10 Apr 2026 18:37:02 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:35 -0600 Message-ID: <20260411003647.2592586-4-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: XHFKWYBH3O7ZPRPXEFJ6LO5UKDFA4G6M X-Message-ID-Hash: XHFKWYBH3O7ZPRPXEFJ6LO5UKDFA4G6M 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 3/8] ext4l: Collect global state into struct ext4l_state 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 Gather the scattered global variables in interface.c into a single struct ext4l_state, making the mount state easier to follow and reset. Remove ext4l_dev_desc and ext4l_part which are set but never read. Change the mounted flag from int to bool. Signed-off-by: Simon Glass --- fs/ext4l/interface.c | 98 ++++++++++++++++++-------------------------- include/ext4l.h | 22 +++++++++- 2 files changed, 62 insertions(+), 58 deletions(-) diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c index 893f71c1f1c..7cc739042eb 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -26,20 +27,8 @@ #include "ext4_jbd2.h" #include "xattr.h" -/* Global state */ -static struct blk_desc *ext4l_dev_desc; -static struct disk_partition ext4l_part; - -/* Global block device tracking for buffer I/O */ -static struct udevice *ext4l_blk_dev; -static struct disk_partition ext4l_partition; -static int ext4l_mounted; - -/* Count of open directory streams (prevents unmount while iterating) */ -static int ext4l_open_dirs; - -/* Global super_block pointer for filesystem operations */ -static struct super_block *ext4l_sb; +/* Global state for the legacy filesystem interface */ +static struct ext4l_state efs; /** * ext4l_get_blk() - Get the current block device @@ -48,9 +37,10 @@ static struct super_block *ext4l_sb; */ struct udevice *ext4l_get_blk(void) { - if (!ext4l_mounted) + if (!efs.mounted) return NULL; - return ext4l_blk_dev; + + return efs.blk; } /** @@ -60,7 +50,7 @@ struct udevice *ext4l_get_blk(void) */ struct disk_partition *ext4l_get_partition(void) { - return &ext4l_partition; + return &efs.partition; } /** @@ -71,9 +61,9 @@ struct disk_partition *ext4l_get_partition(void) */ int ext4l_get_uuid(u8 *uuid) { - if (!ext4l_sb) + if (!efs.sb) return -ENODEV; - memcpy(uuid, ext4l_sb->s_uuid.b, 16); + memcpy(uuid, efs.sb->s_uuid.b, 16); return 0; } @@ -106,11 +96,11 @@ int ext4l_statfs(struct fs_statfs *stats) { struct ext4_super_block *es; - if (!ext4l_sb) + if (!efs.sb) return -ENODEV; - es = EXT4_SB(ext4l_sb)->s_es; - stats->bsize = ext4l_sb->s_blocksize; + es = EXT4_SB(efs.sb)->s_es; + stats->bsize = efs.sb->s_blocksize; stats->blocks = ext4_blocks_count(es); stats->bfree = ext4_free_blocks_count(es); @@ -126,12 +116,12 @@ int ext4l_statfs(struct fs_statfs *stats) void ext4l_set_blk_dev(struct udevice *blk_dev, struct disk_partition *partition) { - ext4l_blk_dev = blk_dev; + efs.blk = blk_dev; if (partition) - memcpy(&ext4l_partition, partition, sizeof(struct disk_partition)); + memcpy(&efs.partition, partition, sizeof(efs.partition)); else - memset(&ext4l_partition, 0, sizeof(struct disk_partition)); - ext4l_mounted = 1; + memset(&efs.partition, 0, sizeof(efs.partition)); + efs.mounted = true; } /** @@ -142,8 +132,8 @@ void ext4l_clear_blk_dev(void) /* Clear buffer cache before unmounting */ bh_cache_clear(); - ext4l_blk_dev = NULL; - ext4l_mounted = 0; + efs.blk = NULL; + efs.mounted = false; } /** @@ -233,16 +223,15 @@ static void ext4l_free_sb(struct super_block *sb, bool skip_io) */ static void ext4l_close_internal(bool skip_io) { - struct super_block *sb = ext4l_sb; + struct super_block *sb = efs.sb; - if (ext4l_open_dirs > 0) + if (efs.open_dirs > 0) return; if (sb) ext4l_free_sb(sb, skip_io); - ext4l_dev_desc = NULL; - ext4l_sb = NULL; + efs.sb = NULL; /* * Force cleanup of any remaining journal_heads before clearing @@ -296,7 +285,7 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, * trust the old device state (it may have been rebound to a different * file). Use skip_io=true to skip all I/O during close. */ - if (ext4l_sb) + if (efs.sb) ext4l_close_internal(true); /* Initialise message buffer for recording ext4 messages */ @@ -403,11 +392,6 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, goto err_free_buf; } - /* Save device info for later operations */ - ext4l_dev_desc = fs_dev_desc; - if (fs_partition) - memcpy(&ext4l_part, fs_partition, sizeof(ext4l_part)); - /* Set block device for buffer I/O */ ext4l_set_blk_dev(fs_dev_desc->bdev, fs_partition); @@ -431,7 +415,7 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, } /* Store super_block for later operations */ - ext4l_sb = sb; + efs.sb = sb; /* Free mount context - no longer needed after successful mount */ kfree(ctx); @@ -523,12 +507,12 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, if (depth > 8) return -ELOOP; - if (!ext4l_mounted) { + if (!efs.mounted) { ext4_debug("ext4l_resolve_path: filesystem not mounted\n"); return -ENODEV; } - dir = ext4l_sb->s_root->d_inode; + dir = efs.sb->s_root->d_inode; if (!path || !*path || (strcmp(path, "/") == 0)) { *inodep = dir; @@ -570,7 +554,7 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, } dentry->d_name.name = ".."; dentry->d_name.len = 2; - dentry->d_sb = ext4l_sb; + dentry->d_sb = efs.sb; dentry->d_parent = NULL; result = ext4_lookup(dir, dentry, 0); @@ -605,7 +589,7 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, dentry->d_name.name = component; dentry->d_name.len = strlen(component); - dentry->d_sb = ext4l_sb; + dentry->d_sb = efs.sb; dentry->d_parent = NULL; result = ext4_lookup(dir, dentry, 0); @@ -731,7 +715,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(ext4l_sb, ino, 0); + inode = ext4_iget(efs.sb, ino, 0); if (IS_ERR(inode)) { printf(" %8s %s\n", "?", namebuf); return 0; @@ -896,14 +880,14 @@ static int ext4l_resolve_file(const char *path, struct dentry **dir_dentryp, const char *basename; int ret; - if (!ext4l_sb) + if (!efs.sb) return -ENODEV; if (!path) return -EINVAL; /* Check if filesystem is mounted read-write */ - if (ext4l_sb->s_flags & SB_RDONLY) + if (efs.sb->s_flags & SB_RDONLY) return -EROFS; /* Parse path to get parent directory and basename */ @@ -1196,7 +1180,7 @@ int ext4l_unlink(const char *filename) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(ext4l_sb); + ext4_commit_super(efs.sb); } out: @@ -1239,7 +1223,7 @@ int ext4l_mkdir(const char *dirname) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(ext4l_sb); + ext4_commit_super(efs.sb); } out: @@ -1298,7 +1282,7 @@ int ext4l_ln(const char *filename, const char *linkname) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(ext4l_sb); + ext4_commit_super(efs.sb); } out: @@ -1349,7 +1333,7 @@ int ext4l_rename(const char *old_path, const char *new_path) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(ext4l_sb); + ext4_commit_super(efs.sb); } out_new: @@ -1379,7 +1363,7 @@ void ext4l_close(void) * @skip_last: true if we need to skip the last_ino entry * * The filesystem stays mounted while directory streams are open (ext4l_close - * checks ext4l_open_dirs), so we can keep direct pointers to inodes. + * checks efs.open_dirs), so we can keep direct pointers to inodes. */ struct ext4l_dir { struct fs_dir_stream parent; @@ -1451,7 +1435,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(ext4l_sb, ino, 0); + inode = ext4_iget(efs.sb, ino, 0); if (!IS_ERR(inode)) { dent->size = inode->i_size; /* Refine type from inode mode if needed */ @@ -1483,7 +1467,7 @@ int ext4l_opendir(const char *filename, struct fs_dir_stream **dirsp) struct inode *inode; int ret; - if (!ext4l_mounted) + if (!efs.mounted) return -ENODEV; ret = ext4l_resolve_path(filename, &inode); @@ -1511,7 +1495,7 @@ int ext4l_opendir(const char *filename, struct fs_dir_stream **dirsp) } /* Increment open dir count to prevent unmount */ - ext4l_open_dirs++; + efs.open_dirs++; *dirsp = (struct fs_dir_stream *)dir; @@ -1524,7 +1508,7 @@ int ext4l_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) struct ext4l_readdir_ctx ctx; int ret; - if (!ext4l_mounted) + if (!efs.mounted) return -ENODEV; memset(&dir->dirent, '\0', sizeof(dir->dirent)); @@ -1567,6 +1551,6 @@ void ext4l_closedir(struct fs_dir_stream *dirs) } /* Decrement open dir count */ - if (ext4l_open_dirs > 0) - ext4l_open_dirs--; + if (efs.open_dirs > 0) + efs.open_dirs--; } diff --git a/include/ext4l.h b/include/ext4l.h index 59990a3a6f4..19fbe8a7fa2 100644 --- a/include/ext4l.h +++ b/include/ext4l.h @@ -9,11 +9,31 @@ #ifndef __EXT4L_H__ #define __EXT4L_H__ +#include + struct blk_desc; -struct disk_partition; struct fs_dir_stream; struct fs_dirent; struct fs_statfs; +struct super_block; +struct udevice; + +/** + * struct ext4l_state - per-mount state for the ext4l driver + * + * @blk: Block device (udevice) for buffer I/O + * @partition: Partition info + * @sb: Superblock pointer + * @open_dirs: Count of open directory streams (prevents unmount) + * @mounted: Whether a filesystem is currently mounted + */ +struct ext4l_state { + struct udevice *blk; + struct disk_partition partition; + struct super_block *sb; + int open_dirs; + bool mounted; +}; /* Select op when EXT4_WRITE is enabled, fallback otherwise */ #if CONFIG_IS_ENABLED(EXT4_WRITE) From patchwork Sat Apr 11 00:36:36 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2159 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=1775867831; bh=oclxdzzI7s9gpMzmoeF7J0UmjBLoA0N3iICxjrOf1pw=; 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=hcm9yOEK1pV0iYJyVfCynyBJepUVWOL9w99D9fDfwXz1q3HWdsAL9d+ZYTfZd2ZG0 Cpvgk4JttCEsa+u/8PjmO6KSTuDBf3h/V0+EtKk1QMXp9fdEukXHs0axLLVHmGuQnm yc9ZkDQQM4UHHRIbwszMmLwG4GvH8+JhC6LfKnA0I22KYBpJ+o4etBO1dW0Po19X+c VjMqj3J1sUrjeMuCz6qN0InjaitOLD8UM2UJi0/FufUDmZNa+TjZ/y6RkHcKihNXrm CfXofJY5nGHEU6Olc/moKR6qYRnrHzWXaXqzBNX//11d3iIBtcmJUmyxd6n5pkcc0K +lS+Wlb/3JhZw== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 38AB36A438 for ; Fri, 10 Apr 2026 18:37:11 -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 ycE9AHAdLuJA for ; Fri, 10 Apr 2026 18:37:11 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867829; bh=oclxdzzI7s9gpMzmoeF7J0UmjBLoA0N3iICxjrOf1pw=; 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=RYLdPFYXJxTzu7sG7bzmnRjERXbvAHnXzQLPDKV7OpTA5y1F02ipfoYp60UHFHNUl AxHi80yScMZ6u25pQRsMzMK5Os2wW/MnsJ/bGPhUFyJuetPC+DR4z6fgyogFG+5BP8 aiiH/xlCDfvgr0qSpveq05kkj8kzk3LoMtrOi8aUZKwy6A0SNioPf2s4Es6krkoivH kbad41EPunaOc29bfC/o9bPKSUPYp4ZCI1JIOUftpaVe++Bf5EAc4w8hWeLQcaTjqZ S40qxtaedEtFvTER3xintJzyXug5eOIevnvpSlQ+2d5PyBT+M6l8lOzCK4I0sEzspm fAbQUBpPU/Xtw== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id A44D76A439 for ; Fri, 10 Apr 2026 18:37:09 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867825; bh=FT4IXqpKNcg5rNAqCRmsCo3Ocis9cMGpRKFUxuW3Lxs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D4cew0zuKi+iFfeNomq2yQ/0KajXqwmjamFLOHwZxos08paNw0BySqWnZAxzFCfqs vX2UDDOyfzmNkChxZiw1QsTQXYvP4ZydUVMWWA9oyC/UO1/gNjWxOCjuOdJwiQI1bM VovM9DA/OMiNoTa2hWQwj+5og65t6fFMRkZUuh2d50EpetoaB25sS/OL/QJMwFRnzd +CoC4YDADF6iMpbNEr8F5bBfh5e7r0Nbxp2hztF+cfXy9D9zJax/YigeJG6oKXbY9L PiUsNtnBPLHNRoawzb8Kyw47lWB9fWqxqpyhjE4cBx3DDK2CILB9LBu8U2ceL86LTP xkj+6jSb8u2KQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 9C5866A42C; Fri, 10 Apr 2026 18:37:05 -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 3Cy5oA4GD0GD; Fri, 10 Apr 2026 18:37:05 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867824; bh=9ZYzvAa90/Ur3jWW+AMJlieF2uYeZEScORn3Oeo8Vv8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nYhYiov5wNIne0EAcTjYVFzEC554tJSDiJBCVGy02SjlhFATMdBQju2AYZcn6Cge2 6BjeLie/oqpWKBi2B1OiVbFcCYeywWK4hRY7cDxq/DV58Gq/tPu19Bi0hz/s9vrkUH UbN/LB+REWHjqpQ6dxsTS6rCd0/gSY4hbk5al/rvS8o5Ntf7jzWllT7SzcU9InFM90 p15adDU+/8GW9fcZR+ttZb9z+XmFmuVRTBfKB24/OxCSdskfpWg2FC48VYh115gMAZ T6bN28KxSQp3kk/lbCy90qep6d5z8kitXczQbLp3N84kyrE8oMhbPZP7kf6+jLeQlL Bg/b/F06vlqrg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 12FF36A3B8; Fri, 10 Apr 2026 18:37:04 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:36 -0600 Message-ID: <20260411003647.2592586-5-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: LLJTTAOELZGAVHKRVIBCQSGBOBX2BB6K X-Message-ID-Hash: LLJTTAOELZGAVHKRVIBCQSGBOBX2BB6K 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 4/8] ext4l: Rename ext4l_probe() to ext4l_mount() 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 The name ext4l_probe() comes from the legacy filesystem interface where each operation re-mounts the filesystem. Rename the internal function to ext4l_mount() which better describes what it does. ext4l_mount() takes a struct ext4l_state pointer and a struct udevice so the caller can provide per-mount state and a proper block device. It zeroes the state at entry so callers do not need to pre-initialise it. The legacy ext4l_probe() wrapper allocates the global state, handles auto-unmount of any previous mount, and converts blk_desc to udevice before calling ext4l_mount() Also handle unmount in the same way. Signed-off-by: Simon Glass --- fs/ext4l/interface.c | 77 ++++++++++++++++++++++++++------------------ include/ext4l.h | 24 ++++++++++++-- 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c index 7cc739042eb..5a7d65fafdc 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -10,6 +10,7 @@ */ #include +#include #include #include #include @@ -108,15 +109,14 @@ int ext4l_statfs(struct fs_statfs *stats) } /** - * ext4l_set_blk_dev() - Set the block device for ext4l operations + * ext4l_set_blk() - Set the block device for ext4l operations * - * @blk_dev: Block device descriptor + * @blk: Block device descriptor * @partition: Partition info (can be NULL for whole disk) */ -void ext4l_set_blk_dev(struct udevice *blk_dev, - struct disk_partition *partition) +void ext4l_set_blk(struct udevice *blk, struct disk_partition *partition) { - efs.blk = blk_dev; + efs.blk = blk; if (partition) memcpy(&efs.partition, partition, sizeof(efs.partition)); else @@ -125,9 +125,9 @@ void ext4l_set_blk_dev(struct udevice *blk_dev, } /** - * ext4l_clear_blk_dev() - Clear block device (unmount) + * ext4l_clear_blk() - Clear block device (unmount) */ -void ext4l_clear_blk_dev(void) +void ext4l_clear_blk(void) { /* Clear buffer cache before unmounting */ bh_cache_clear(); @@ -207,31 +207,32 @@ static void ext4l_free_sb(struct super_block *sb, bool skip_io) kfree(sbi->s_blockgroup_lock); kfree(sbi); - /* Free structures allocated in ext4l_probe() */ + /* Free structures allocated in ext4l_mount() */ kfree(sb->s_bdev->bd_mapping); kfree(sb->s_bdev); kfree(sb); } /** - * ext4l_close_internal() - Internal close function + * ext4l_umount_internal() - Internal close function + * @state: Per-mount state to initialise * @skip_io: If true, skip all I/O operations (for forced close) * - * When called from the safeguard in ext4l_probe(), the device may be + * When called from the safeguard in ext4l_mount(), the device may be * invalid (rebound to a different file), so skip_io should be true to * avoid crashes when trying to write to the device. */ -static void ext4l_close_internal(bool skip_io) +static void ext4l_umount_internal(struct ext4l_state *state, bool skip_io) { - struct super_block *sb = efs.sb; + struct super_block *sb = state->sb; - if (efs.open_dirs > 0) + if (state->open_dirs > 0) return; if (sb) ext4l_free_sb(sb, skip_io); - efs.sb = NULL; + state->sb = NULL; /* * Force cleanup of any remaining journal_heads before clearing @@ -242,7 +243,7 @@ static void ext4l_close_internal(bool skip_io) */ bh_cache_release_jbd(); - ext4l_clear_blk_dev(); + ext4l_clear_blk(); /* * Clean up ext4 and JBD2 global state so it can be properly @@ -263,9 +264,10 @@ static void ext4l_close_internal(bool skip_io) destroy_inodecache(); } -int ext4l_probe(struct blk_desc *fs_dev_desc, +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 ext4_fs_context *ctx; struct super_block *sb; struct fs_context *fc; @@ -274,19 +276,10 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, u8 *buf; int ret; - if (!fs_dev_desc) - return -EINVAL; + memset(state, '\0', sizeof(*state)); - /* - * Ensure any previous mount is properly closed before mounting again. - * This prevents resource leaks if probe is called without close. - * - * Since we're being called while a previous mount exists, we can't - * trust the old device state (it may have been rebound to a different - * file). Use skip_io=true to skip all I/O during close. - */ - if (efs.sb) - ext4l_close_internal(true); + if (!dev) + return -EINVAL; /* Initialise message buffer for recording ext4 messages */ ext4l_msg_init(); @@ -393,7 +386,7 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, } /* Set block device for buffer I/O */ - ext4l_set_blk_dev(fs_dev_desc->bdev, fs_partition); + ext4l_set_blk(dev, fs_partition); /* * Test if device supports writes by writing back the same data. @@ -415,7 +408,7 @@ int ext4l_probe(struct blk_desc *fs_dev_desc, } /* Store super_block for later operations */ - efs.sb = sb; + state->sb = sb; /* Free mount context - no longer needed after successful mount */ kfree(ctx); @@ -444,6 +437,23 @@ err_exit_es: return ret; } +int ext4l_probe(struct blk_desc *fs_dev_desc, + struct disk_partition *fs_partition) +{ + if (!fs_dev_desc) + return -EINVAL; + + /* + * The legacy interface may call probe without a preceding close. + * Clean up any previous mount to prevent resource leaks. Use + * skip_io=true because the old device may have been rebound. + */ + if (efs.sb) + ext4l_umount_internal(&efs, true); + + return ext4l_mount(&efs, fs_dev_desc->bdev, fs_partition); +} + /** * ext4l_read_symlink() - Read the target of a symlink inode * @@ -1347,9 +1357,14 @@ out_old: return ret; } +void ext4l_umount(struct ext4l_state *state) +{ + ext4l_umount_internal(state, false); +} + void ext4l_close(void) { - ext4l_close_internal(false); + ext4l_umount(&efs); } /** diff --git a/include/ext4l.h b/include/ext4l.h index 19fbe8a7fa2..5ef1cc0a30f 100644 --- a/include/ext4l.h +++ b/include/ext4l.h @@ -43,18 +43,36 @@ struct ext4l_state { #endif /** - * ext4l_probe() - Probe a block device for an ext4 filesystem + * ext4l_mount() - Mount an ext4 filesystem * - * @fs_dev_desc: Block device descriptor + * @state: Per-mount state to initialise + * @dev: Block device (struct udevice) * @fs_partition: Partition information * Return: 0 on success, -EINVAL if no device or invalid magic, * -ENOMEM on allocation failure, -EIO on read error */ +int ext4l_mount(struct ext4l_state *state, struct udevice *dev, + struct disk_partition *fs_partition); + +/** + * ext4l_probe() - Legacy probe: mount using the global state + * + * @fs_dev_desc: Block device descriptor + * @fs_partition: Partition information + * Return: 0 on success, negative on error + */ int ext4l_probe(struct blk_desc *fs_dev_desc, struct disk_partition *fs_partition); /** - * ext4l_close() - Close the ext4 filesystem + * ext4l_umount() - Unmount an ext4 filesystem + * + * @state: Per-mount state to tear down + */ +void ext4l_umount(struct ext4l_state *state); + +/** + * ext4l_close() - Legacy close: unmount using the global state */ void ext4l_close(void); From patchwork Sat Apr 11 00:36:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2160 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=1775867831; bh=1H6hmnXtkeuYHM7eZLXMMEOo74aDVIly9WHFRD2ARCU=; 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=sHQNvu/TQc3ewbUFI7+masLVOhNcKF+9dbSlPW0cMIW8ZxQjEQ+1WfKlF7mKPt/G5 duGjo8e8N5vCnAmcaUMjOSbH3vGOE2xABgAeUfq4LsNMLMU1p2hyoVLjiCT+Me4Ept V/eTju8CBFLT2ZNv8J2RmOEWKWmSTH12+cxAmJ0ysvmwiT2sI4uNKWqAxJX6moUj+T RHndal98PH3b6YKn9uRRUlKpTNOP5c7Pnp6iUCCigfBBbn7/1UMPPGBBDjKD7lXKhW EvA2E8T6/rzFQqwExXaj+gNfAj4lqaog5UT53MQjxdvEgY1yXkdAFT0xEDi09S1aSi l/joROXBXdt7g== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C6E896A42D for ; Fri, 10 Apr 2026 18:37:11 -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 v_O6lRDBeuX2 for ; Fri, 10 Apr 2026 18:37:11 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867830; bh=1H6hmnXtkeuYHM7eZLXMMEOo74aDVIly9WHFRD2ARCU=; 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=CICZBrpdnKfTxyphiKJ+zs6Y/7OhjU7vbfGofkS92PLtdn0s56jNYz1JSYy/AHPqp LCdnKTyR+/GytdzhXndmZB/OB34J3U8Xm4urgAYOrdylIkeTGrH1BrVFc+laNY+uWI oJCuxUzOSYYwJhTvBTMZXciQAkFtkFv+NWHXdZsozzRdqdoXGPXsGZqRpUpl8DFBOJ vROp+l3MCTDTqYiSXJaJ5Dwn7WDV85tmgwIlQIllG5et+P3IWlAzsPILqTkcnN2riv A7uPrc0x0P3UvZnv3vWopyMReKgZ9JS4B9oK2pwYCo08fbQ26PTVDNo7/8gErKHnqH WfARg3SLCm5pQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 57CA96A42F for ; Fri, 10 Apr 2026 18:37:10 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867827; bh=Yy9D+eEcXPiOWz7b9dfHlzpTawBS/dTsoJjHlhshsk4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wn6EYOAbBwSDvfFl+HzfJTU+2ef/ewwRpQSFoKUxmWEnt0zzzYIT6tGkh2BDYmD+y bAEQf7eJZSIyKvMFluyPtwefSajivibMK8YbS9vNAhJZo9f3482GIFZBEg/GU+esPM fwgypmjOtltIu1PrNBgbSGtwWsKZ2TeADCEORcdm3o7NtybU9HpMW8mJkfWhu/p49S hegF9RR1+zLSBFLBAs1Ci44zYNFCynJ67zKkSGnx027HRdsfTUF/8rfpMgaciUXHvq PMjjxGwsYI6b1BmYZ2/tZZ7A316L7enYAytbdkf+la8TX+LxwuZNnj1v6e8w/YjrFE +O/yFX2ZNK9YQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C7D556A42B; Fri, 10 Apr 2026 18:37:07 -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 pWGfNNuaeK-D; Fri, 10 Apr 2026 18:37:07 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867825; bh=qMGg73Yt+nW/oqJHQMWAK4RD8AdPGP7UM5bwlGQYPzc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wR05GntpqAATK0RENlHC/TRjDIPmXmojR9k9RGfCejkfFpQMj5bWIxUMNQSq0FVzu mdwrK2xaZSBUOYvUPqLfhTCMWpTm5goi7VXPwMNL70Dt+yCM27z7wdkwtn7VM3ng7G Jn/iDv15+sTCNQmxNH8BdmACV23Z8r7RCvHhXrVxN+RNozkoedc/ZIV0+/jYTCyoP9 V9CQ+ZOkuuIlRTzpROT/bGDghcRJjpTzOW5g1DoV2W9B/VgUmQpqgBQIcW15W4k0yn LyCvuQyOWK9EPbwXQLCVPMkL9jvWtg0mE2/Dstdm9adr8ypAL2x6jdd813j5l4kr0c 0qGndpuayztag== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 491E16A425; Fri, 10 Apr 2026 18:37:05 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:37 -0600 Message-ID: <20260411003647.2592586-6-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: FXPOXBV63IMWAFB2WL2ZMASVVXGLZRE2 X-Message-ID-Hash: FXPOXBV63IMWAFB2WL2ZMASVVXGLZRE2 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 5/8] ext4l: Thread state through path resolution 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 Path resolution is the core operation underlying every file access: ls, read, write, mkdir, unlink, rename and symlink following all go through ext4l_resolve_path_internal(). Add a struct ext4l_state parameter so it uses per-mount state instead of the global, replacing direct references to efs.mounted, efs.sb and efs.sb->s_root with the state pointer. The public ext4l_resolve_path() wrapper still passes the global for now; it will be converted when the remaining public functions are updated. Signed-off-by: Simon Glass --- fs/ext4l/fs.c | 16 +++++++++++++--- fs/ext4l/interface.c | 20 +++++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/fs/ext4l/fs.c b/fs/ext4l/fs.c index e9be9d80798..ceb09ca85e6 100644 --- a/fs/ext4l/fs.c +++ b/fs/ext4l/fs.c @@ -21,6 +21,15 @@ #include #include +/** + * struct ext4l_fs_priv - Private data for ext4l UCLASS_FS devices + * + * @state: Per-mount state + */ +struct ext4l_fs_priv { + struct ext4l_state state; +}; + /** * struct ext4l_dir_priv - Private info for ext4l directory devices * @@ -119,9 +128,10 @@ static const struct fs_ops ext4l_vfs_ops = { }; U_BOOT_DRIVER(ext4_fs) = { - .name = "ext4_fs", - .id = UCLASS_FS, - .ops = &ext4l_vfs_ops, + .name = "ext4_fs", + .id = UCLASS_FS, + .ops = &ext4l_vfs_ops, + .priv_auto = sizeof(struct ext4l_fs_priv), }; /* ext4l directory driver */ diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c index 5a7d65fafdc..b53da76c7cf 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -500,13 +500,15 @@ static int ext4l_read_symlink(struct inode *inode, char *target, size_t max_len) /** * ext4l_resolve_path_internal() - Resolve path with symlink following * + * @state: Per-mount state * @path: Path to resolve * @inodep: Output inode pointer * @depth: Current recursion depth (for symlink loop detection) * Return: 0 on success, negative on error */ -static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, - int depth) +static int ext4l_resolve_path_internal(struct ext4l_state *state, + const char *path, + struct inode **inodep, int depth) { struct inode *dir; struct dentry *dentry, *result; @@ -517,12 +519,12 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, if (depth > 8) return -ELOOP; - if (!efs.mounted) { + if (!state->mounted) { ext4_debug("ext4l_resolve_path: filesystem not mounted\n"); return -ENODEV; } - dir = efs.sb->s_root->d_inode; + dir = state->sb->s_root->d_inode; if (!path || !*path || (strcmp(path, "/") == 0)) { *inodep = dir; @@ -564,7 +566,7 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, } dentry->d_name.name = ".."; dentry->d_name.len = 2; - dentry->d_sb = efs.sb; + dentry->d_sb = state->sb; dentry->d_parent = NULL; result = ext4_lookup(dir, dentry, 0); @@ -599,7 +601,7 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, dentry->d_name.name = component; dentry->d_name.len = strlen(component); - dentry->d_sb = efs.sb; + dentry->d_sb = state->sb; dentry->d_parent = NULL; result = ext4_lookup(dir, dentry, 0); @@ -674,8 +676,8 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, free(path_copy); /* Recursively resolve the new path */ - ret = ext4l_resolve_path_internal(new_path, inodep, - depth + 1); + ret = ext4l_resolve_path_internal(state, new_path, + inodep, depth + 1); free(new_path); return ret; } @@ -697,7 +699,7 @@ static int ext4l_resolve_path_internal(const char *path, struct inode **inodep, */ static int ext4l_resolve_path(const char *path, struct inode **inodep) { - return ext4l_resolve_path_internal(path, inodep, 0); + return ext4l_resolve_path_internal(&efs, path, inodep, 0); } /** From patchwork Sat Apr 11 00:36:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2162 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=1775867838; bh=at4o7KxNCfMFS0eISceptDB/svFmcz7BdZrTymG+QPw=; 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=tGbKccxFMlI0hyqa1fuifE6Wjk0mOFMbpfxv2rLuALTGqRE3wmBjTRBNHpMLTjLrA D8fIOUTXKI9SOupmuLzDYP8gdfbDZexN6ffH4kSfeO80GscCK5jfzsSnEX1P6j4em2 HfAAbF/ElMhbavHBXtJjMjocZWh1k00br6HXPBqyoSBKDatlTXhOY+p1l+6SyVXFJF qnPQeV5m277L4BGKb4xDKBjAgPPmi3s0O/9IEMp7aLg2sR9B9kN/rmoeXKSh18wKuJ Oz5pRj7R3GGl9FX8GOFZieNXqMYA+hRV1Mc3n6j9ayL5+n31JM2KtKtVv5kVOzHnJT qLHdp7BRzkuDQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 656AA6A43D for ; Fri, 10 Apr 2026 18:37:18 -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 26Q89Vsnsy3d for ; Fri, 10 Apr 2026 18:37:18 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867837; bh=at4o7KxNCfMFS0eISceptDB/svFmcz7BdZrTymG+QPw=; 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=QlOVzB7pPXYcWCQhbXmYC42aY2wx1rujNBEZebwlJ2XnZOVl8K2ny4z+oIUZFiMxA h7Hkv9x2BksWwIoycgs4hKZnKcRIvbqQ67dRS3fQpiP6NFUbgG4kfAKbY0ttjHY2Zb JP+Ht0VdqwmlmstL914EOwjRSOo9RYNj3vmUb+I3Mt7g1dUp5QPDV+7F2F11JE0Qrt sCiEs4ADK6rxVUsNUYMA0IWVXXkXYyHhw1f6ntmYAOw3xqEhciTxixOm4gLnP4MARm mNiKf4GJAfVT+WtFrsByGjrMNPfWSMQPVs4rpBDDx6AXw326SoNE8shcf1nKcn7ZrR MrBo6D5UTNUMQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 728BD6A42B for ; Fri, 10 Apr 2026 18:37:17 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867834; bh=xA7y8HWtkCAH26ZFRjGiVkYz9PaeG8lrWlrPkqMYVn0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mbqT2jQ37/nlgBs9MIzdM0gqTxgwdcELkTVCMqojKkVD/0HyEkOwR3vCsJWRCWkyb KyRMtKF2BxNaz1nu6/rWG/HHCSnndb67Y6sTrFjXF8ZGG2pb6PGweqiXFhVZeXVqKJ Qjer2ZIGF3uQKi109dt0QPFAe2N6KQbYKVFxj1NS/04wlzbJ1dlOamS1ClK4p+KRxa wDlDlP4iCMnboYbYCh5C5YasfZKIeRo4/berDXB3PJgSGVICBfb10/m4awCKMZNNLx 1/sBlWRGtChI8nEP47fsKAFaQH5WPiPDo7k8i5sal2ob2R9sNrEeC4BpiaV8k1qtpp T3YXrevY6bNqQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 549BB6A425; 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 3NIaafVtZ3PO; 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=1775867827; bh=IooFVRn0vtNJ+pMvRANlJh0EG98HyINhKgCrv5NBvLs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=wKVLZZpJhnPAHn0GFtBET0qBzrV2NiYQSCi3eThqOOUbHmeRMw+t9DXtrf1V7lDuS ZTHtqLlje1s/uEWQmS62MdLMW6d7QJq6+RiCZgTeuCgZL0N2jj4YcmB2OXaXckPi08 F6WeRb6Tl8tyLWh51OWca15W9VSySKlB48M1TYzlvimI7dCKHNAmnHmjFE4HPGRlKs ZhUxfJgyZJ09a0f2ASXaKbjytpDOWFEBTfSnqq3YUX/Iblxw3mEJXqAhV9pXQeedto GF+UJa/hFhS7VSvs6hp0dEpSrtFsa1tOPrqsoOWN7JbISe+rsHIzlbnKwh5f1Mb+OZ mjPrkw88pdmyA== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 852B66A42A; Fri, 10 Apr 2026 18:37:06 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:38 -0600 Message-ID: <20260411003647.2592586-7-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: N7TV7MPALARMWKHB4A3PUCZBTRKIC4AN X-Message-ID-Hash: N7TV7MPALARMWKHB4A3PUCZBTRKIC4AN 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 6/8] ext4l: Convert all public functions to take state parameter 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 a struct ext4l_state pointer as the first parameter to all public ext4l functions: ls, exists, size, read, write, unlink, mkdir, ln, rename, get_uuid, statfs, opendir, readdir, closedir and the internal resolve_path / resolve_file helpers. The state-taking version is the primary API (e.g. ext4l_read() takes state). Legacy wrappers with a _legacy suffix (e.g. ext4l_read_legacy) pass the global state for callers that have not been converted yet: fs_legacy.c, fs.c (VFS, for now) and the C unit tests. Signed-off-by: Simon Glass --- fs/ext4l/fs.c | 75 +++++++++++++---- fs/ext4l/interface.c | 186 ++++++++++++++++++++++++++++++++----------- fs/fs_legacy.c | 26 +++--- include/ext4l.h | 117 +++++++++++++-------------- test/fs/ext4l.c | 135 ++++++++++++++++--------------- 5 files changed, 334 insertions(+), 205 deletions(-) diff --git a/fs/ext4l/fs.c b/fs/ext4l/fs.c index ceb09ca85e6..85af18a017a 100644 --- a/fs/ext4l/fs.c +++ b/fs/ext4l/fs.c @@ -33,15 +33,31 @@ struct ext4l_fs_priv { /** * struct ext4l_dir_priv - Private info for ext4l directory devices * - * @strm: Directory stream from ext4l_opendir(), or NULL. Only one listing - * at a time is supported per directory device + * @strm: Directory stream from ext4l_opendir_legacy(), or NULL. Only one + * listing at a time is supported per directory device */ struct ext4l_dir_priv { struct fs_dir_stream *strm; }; +/** + * ext4l_get_fs_dev() - Get the UCLASS_FS device from a child + * + * Walks up from a DIR or FILE device to find its UCLASS_FS parent. + * + * Return: UCLASS_FS device (always valid for properly constructed trees) + */ +static struct udevice *ext4l_get_fs_dev(struct udevice *dev) +{ + while (device_get_uclass_id(dev) != UCLASS_FS) + dev = dev_get_parent(dev); + + return dev; +} + static int ext4l_vfs_mount(struct udevice *dev) { + struct ext4l_fs_priv *priv = dev_get_priv(dev); struct fs_priv *uc_priv = dev_get_uclass_priv(dev); struct fs_plat *plat = dev_get_uclass_plat(dev); int ret; @@ -52,7 +68,7 @@ static int ext4l_vfs_mount(struct udevice *dev) if (!plat->desc) return log_msg_ret("emd", -ENODEV); - ret = ext4l_probe(plat->desc, &plat->part); + ret = ext4l_mount(&priv->state, plat->desc->bdev, &plat->part); if (ret) return log_msg_ret("emp", ret); @@ -63,12 +79,13 @@ static int ext4l_vfs_mount(struct udevice *dev) static int ext4l_vfs_unmount(struct udevice *dev) { + struct ext4l_fs_priv *priv = dev_get_priv(dev); struct fs_priv *uc_priv = dev_get_uclass_priv(dev); if (!uc_priv->mounted) return log_msg_ret("euu", -ENOTCONN); - ext4l_close(); + ext4l_umount(&priv->state); uc_priv->mounted = false; return 0; @@ -92,28 +109,38 @@ static int ext4l_vfs_lookup_dir(struct udevice *dev, const char *path, static int ext4l_vfs_ln(struct udevice *dev, const char *path, const char *target) { - return ext4l_ln(target, path); + struct ext4l_fs_priv *priv = dev_get_priv(dev); + + return ext4l_ln(&priv->state, target, path); } static int ext4l_vfs_rename(struct udevice *dev, const char *old_path, const char *new_path) { - return ext4l_rename(old_path, new_path); + struct ext4l_fs_priv *priv = dev_get_priv(dev); + + return ext4l_rename(&priv->state, old_path, new_path); } static int ext4l_vfs_statfs(struct udevice *dev, struct fs_statfs *stats) { - return ext4l_statfs(stats); + struct ext4l_fs_priv *priv = dev_get_priv(dev); + + return ext4l_statfs(&priv->state, stats); } static int ext4l_vfs_unlink(struct udevice *dev, const char *path) { - return ext4l_unlink(path); + struct ext4l_fs_priv *priv = dev_get_priv(dev); + + return ext4l_unlink(&priv->state, path); } static int ext4l_vfs_mkdir(struct udevice *dev, const char *path) { - return ext4l_mkdir(path); + struct ext4l_fs_priv *priv = dev_get_priv(dev); + + return ext4l_mkdir(&priv->state, path); } static const struct fs_ops ext4l_vfs_ops = { @@ -138,6 +165,8 @@ U_BOOT_DRIVER(ext4_fs) = { static int ext4l_dir_open(struct udevice *dev, struct fs_dir_stream *strm) { + struct udevice *fsdev = ext4l_get_fs_dev(dev); + struct ext4l_fs_priv *fspriv = dev_get_priv(fsdev); struct ext4l_dir_priv *priv = dev_get_priv(dev); struct dir_uc_priv *uc_priv = dev_get_uclass_priv(dev); struct fs_dir_stream *ext4_strm; @@ -145,7 +174,7 @@ static int ext4l_dir_open(struct udevice *dev, struct fs_dir_stream *strm) int ret; path = *uc_priv->path ? uc_priv->path : "/"; - ret = ext4l_opendir(path, &ext4_strm); + ret = ext4l_opendir(&fspriv->state, path, &ext4_strm); if (ret) return log_msg_ret("edo", ret); @@ -157,11 +186,13 @@ static int ext4l_dir_open(struct udevice *dev, struct fs_dir_stream *strm) static int ext4l_dir_read(struct udevice *dev, struct fs_dir_stream *strm, struct fs_dirent *dent) { + struct udevice *fsdev = ext4l_get_fs_dev(dev); + struct ext4l_fs_priv *fspriv = dev_get_priv(fsdev); struct ext4l_dir_priv *priv = dev_get_priv(dev); struct fs_dirent *ext4_dent; int ret; - ret = ext4l_readdir(priv->strm, &ext4_dent); + ret = ext4l_readdir(&fspriv->state, priv->strm, &ext4_dent); if (ret) return ret; @@ -172,9 +203,11 @@ static int ext4l_dir_read(struct udevice *dev, struct fs_dir_stream *strm, static int ext4l_dir_close(struct udevice *dev, struct fs_dir_stream *strm) { + struct udevice *fsdev = ext4l_get_fs_dev(dev); + struct ext4l_fs_priv *fspriv = dev_get_priv(fsdev); struct ext4l_dir_priv *priv = dev_get_priv(dev); - ext4l_closedir(priv->strm); + ext4l_closedir(&fspriv->state, priv->strm); priv->strm = NULL; return 0; @@ -194,12 +227,15 @@ struct ext4l_file_priv { static ssize_t ext4l_read_iter(struct udevice *dev, struct iov_iter *iter, loff_t pos) { + struct udevice *fsdev = ext4l_get_fs_dev(dev); + struct ext4l_fs_priv *fspriv = dev_get_priv(fsdev); struct ext4l_file_priv *priv = dev_get_priv(dev); loff_t actual; int ret; - ret = ext4l_read(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); @@ -210,11 +246,14 @@ static ssize_t ext4l_read_iter(struct udevice *dev, struct iov_iter *iter, static ssize_t ext4l_write_iter(struct udevice *dev, struct iov_iter *iter, loff_t pos) { + struct udevice *fsdev = ext4l_get_fs_dev(dev); + struct ext4l_fs_priv *fspriv = dev_get_priv(fsdev); struct ext4l_file_priv *priv = dev_get_priv(dev); loff_t actual; int ret; - ret = ext4l_write(priv->path, (void *)iter_iov_ptr(iter), pos, + ret = ext4l_write(&fspriv->state, priv->path, + (void *)iter_iov_ptr(iter), pos, iter_iov_avail(iter), &actual); if (ret) return log_msg_ret("efw", ret); @@ -239,6 +278,8 @@ static int ext4l_dir_open_file(struct udevice *dir, const char *leaf, enum dir_open_flags_t oflags, struct udevice **filp) { + struct udevice *fsdev = ext4l_get_fs_dev(dir); + struct ext4l_fs_priv *fspriv = dev_get_priv(fsdev); struct dir_uc_priv *uc_priv = dev_get_uclass_priv(dir); struct ext4l_file_priv *priv; struct udevice *dev; @@ -253,9 +294,9 @@ static int ext4l_dir_open_file(struct udevice *dir, const char *leaf, /* For read, verify the file exists and get its size */ if (oflags == DIR_O_RDONLY) { - if (!ext4l_exists(path)) + if (!ext4l_exists(&fspriv->state, path)) return log_msg_ret("eoe", -ENOENT); - ret = ext4l_size(path, &size); + ret = ext4l_size(&fspriv->state, path, &size); if (ret) return log_msg_ret("eos", ret); } diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c index b53da76c7cf..eded6538e99 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -57,14 +57,15 @@ struct disk_partition *ext4l_get_partition(void) /** * ext4l_get_uuid() - Get the filesystem UUID * + * @state: Per-mount state * @uuid: Buffer to receive the 16-byte UUID * Return: 0 on success, -ENODEV if not mounted */ -int ext4l_get_uuid(u8 *uuid) +int ext4l_get_uuid(struct ext4l_state *state, u8 *uuid) { - if (!efs.sb) + if (!state->sb) return -ENODEV; - memcpy(uuid, efs.sb->s_uuid.b, 16); + memcpy(uuid, state->sb->s_uuid.b, 16); return 0; } @@ -79,7 +80,7 @@ int ext4l_uuid(char *uuid_str) u8 uuid[16]; int ret; - ret = ext4l_get_uuid(uuid); + ret = ext4l_get_uuid_legacy(uuid); if (ret) return ret; uuid_bin_to_str(uuid, uuid_str, UUID_STR_FORMAT_STD); @@ -90,18 +91,19 @@ int ext4l_uuid(char *uuid_str) /** * ext4l_statfs() - Get filesystem statistics * + * @state: Per-mount state * @stats: Pointer to fs_statfs structure to fill * Return: 0 on success, -ENODEV if not mounted */ -int ext4l_statfs(struct fs_statfs *stats) +int ext4l_statfs(struct ext4l_state *state, struct fs_statfs *stats) { struct ext4_super_block *es; - if (!efs.sb) + if (!state->sb) return -ENODEV; - es = EXT4_SB(efs.sb)->s_es; - stats->bsize = efs.sb->s_blocksize; + es = EXT4_SB(state->sb)->s_es; + stats->bsize = state->sb->s_blocksize; stats->blocks = ext4_blocks_count(es); stats->bfree = ext4_free_blocks_count(es); @@ -693,13 +695,15 @@ static int ext4l_resolve_path_internal(struct ext4l_state *state, /** * ext4l_resolve_path() - Resolve path to inode * + * @state: Per-mount state * @path: Path to resolve * @inodep: Output inode pointer * Return: 0 on success, negative on error */ -static int ext4l_resolve_path(const char *path, struct inode **inodep) +static int ext4l_resolve_path(struct ext4l_state *state, const char *path, + struct inode **inodep) { - return ext4l_resolve_path_internal(&efs, path, inodep, 0); + return ext4l_resolve_path_internal(state, path, inodep, 0); } /** @@ -743,14 +747,14 @@ static int ext4l_dir_actor(struct dir_context *ctx, const char *name, return 0; } -int ext4l_ls(const char *dirname) +int ext4l_ls(struct ext4l_state *state, const char *dirname) { struct inode *dir; struct file file; struct dir_context ctx; int ret; - ret = ext4l_resolve_path(dirname, &dir); + ret = ext4l_resolve_path(state, dirname, &dir); if (ret) return ret; @@ -777,25 +781,26 @@ int ext4l_ls(const char *dirname) return ret; } -int ext4l_exists(const char *filename) +int ext4l_exists(struct ext4l_state *state, const char *filename) { struct inode *inode; if (!filename) return 0; - if (ext4l_resolve_path(filename, &inode)) + if (ext4l_resolve_path(state, filename, &inode)) return 0; return 1; } -int ext4l_size(const char *filename, loff_t *sizep) +int ext4l_size(struct ext4l_state *state, const char *filename, + loff_t *sizep) { struct inode *inode; int ret; - ret = ext4l_resolve_path(filename, &inode); + ret = ext4l_resolve_path(state, filename, &inode); if (ret) return ret; @@ -804,8 +809,8 @@ int ext4l_size(const char *filename, loff_t *sizep) return 0; } -int ext4l_read(const char *filename, void *buf, loff_t offset, loff_t len, - loff_t *actread) +int ext4l_read(struct ext4l_state *state, const char *filename, void *buf, + loff_t offset, loff_t len, loff_t *actread) { uint copy_len, blk_off, blksize; loff_t bytes_left, file_size; @@ -817,7 +822,7 @@ int ext4l_read(const char *filename, void *buf, loff_t offset, loff_t len, *actread = 0; - ret = ext4l_resolve_path(filename, &inode); + ret = ext4l_resolve_path(state, filename, &inode); if (ret) { printf("** File not found %s **\n", filename); return ret; @@ -870,6 +875,29 @@ int ext4l_read(const char *filename, void *buf, loff_t offset, loff_t len, return 0; } +/* Legacy wrappers that pass the global state */ + +int ext4l_ls_legacy(const char *dirname) +{ + return ext4l_ls(&efs, dirname); +} + +int ext4l_exists_legacy(const char *filename) +{ + return ext4l_exists(&efs, filename); +} + +int ext4l_size_legacy(const char *filename, loff_t *sizep) +{ + return ext4l_size(&efs, filename, sizep); +} + +int ext4l_read_legacy(const char *filename, void *buf, loff_t offset, + loff_t len, loff_t *actread) +{ + return ext4l_read(&efs, filename, buf, offset, len, actread); +} + /** * ext4l_resolve_file() - Resolve a file path for write operations * @path: Path to process @@ -883,7 +911,8 @@ int ext4l_read(const char *filename, void *buf, loff_t offset, loff_t len, * * Return: 0 on success, negative on error */ -static int ext4l_resolve_file(const char *path, struct dentry **dir_dentryp, +static int ext4l_resolve_file(struct ext4l_state *state, const char *path, + struct dentry **dir_dentryp, struct dentry **dentryp, char **path_copyp) { char *path_copy, *dir_path, *last_slash; @@ -892,14 +921,14 @@ static int ext4l_resolve_file(const char *path, struct dentry **dir_dentryp, const char *basename; int ret; - if (!efs.sb) + if (!state->sb) return -ENODEV; if (!path) return -EINVAL; /* Check if filesystem is mounted read-write */ - if (efs.sb->s_flags & SB_RDONLY) + if (state->sb->s_flags & SB_RDONLY) return -EROFS; /* Parse path to get parent directory and basename */ @@ -920,7 +949,7 @@ static int ext4l_resolve_file(const char *path, struct dentry **dir_dentryp, } /* Resolve parent directory */ - ret = ext4l_resolve_path(dir_path, &dir_inode); + ret = ext4l_resolve_path(state, dir_path, &dir_inode); if (ret) { free(path_copy); return ret; @@ -1119,8 +1148,8 @@ out_handle: return ret; } -int ext4l_write(const char *filename, void *buf, loff_t offset, loff_t len, - loff_t *actwrite) +int ext4l_write(struct ext4l_state *state, const char *filename, void *buf, + loff_t offset, loff_t len, loff_t *actwrite) { struct dentry *dir_dentry, *dentry; char *path_copy; @@ -1129,7 +1158,8 @@ int ext4l_write(const char *filename, void *buf, loff_t offset, loff_t len, if (!buf || !actwrite) return -EINVAL; - ret = ext4l_resolve_file(filename, &dir_dentry, &dentry, &path_copy); + ret = ext4l_resolve_file(state, filename, &dir_dentry, &dentry, + &path_copy); if (ret) return ret; @@ -1150,13 +1180,14 @@ int ext4l_write(const char *filename, void *buf, loff_t offset, loff_t len, return ret; } -int ext4l_unlink(const char *filename) +int ext4l_unlink(struct ext4l_state *state, const char *filename) { struct dentry *dentry, *dir_dentry; char *path_copy; int ret; - ret = ext4l_resolve_file(filename, &dir_dentry, &dentry, &path_copy); + ret = ext4l_resolve_file(state, filename, &dir_dentry, &dentry, + &path_copy); if (ret) return ret; @@ -1192,7 +1223,7 @@ int ext4l_unlink(const char *filename) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(efs.sb); + ext4_commit_super(state->sb); } out: @@ -1202,13 +1233,14 @@ out: return ret; } -int ext4l_mkdir(const char *dirname) +int ext4l_mkdir(struct ext4l_state *state, const char *dirname) { struct dentry *dentry, *dir_dentry, *result; char *path_copy; int ret; - ret = ext4l_resolve_file(dirname, &dir_dentry, &dentry, &path_copy); + ret = ext4l_resolve_file(state, dirname, &dir_dentry, &dentry, + &path_copy); if (ret) return ret; @@ -1235,7 +1267,7 @@ int ext4l_mkdir(const char *dirname) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(efs.sb); + ext4_commit_super(state->sb); } out: @@ -1245,7 +1277,8 @@ out: return ret; } -int ext4l_ln(const char *filename, const char *linkname) +int ext4l_ln(struct ext4l_state *state, const char *filename, + const char *linkname) { struct dentry *dentry, *dir_dentry; char *path_copy; @@ -1259,7 +1292,8 @@ int ext4l_ln(const char *filename, const char *linkname) if (!filename) return -EINVAL; - ret = ext4l_resolve_file(linkname, &dir_dentry, &dentry, &path_copy); + ret = ext4l_resolve_file(state, linkname, &dir_dentry, &dentry, + &path_copy); if (ret) return ret; @@ -1294,7 +1328,7 @@ int ext4l_ln(const char *filename, const char *linkname) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(efs.sb); + ext4_commit_super(state->sb); } out: @@ -1305,7 +1339,8 @@ out: return ret; } -int ext4l_rename(const char *old_path, const char *new_path) +int ext4l_rename(struct ext4l_state *state, const char *old_path, + const char *new_path) { struct dentry *old_dentry, *new_dentry; struct dentry *old_dir_dentry, *new_dir_dentry; @@ -1316,7 +1351,7 @@ int ext4l_rename(const char *old_path, const char *new_path) if (!new_path) return -EINVAL; - ret = ext4l_resolve_file(old_path, &old_dir_dentry, &old_dentry, + ret = ext4l_resolve_file(state, old_path, &old_dir_dentry, &old_dentry, &old_path_copy); if (ret) return ret; @@ -1327,7 +1362,7 @@ int ext4l_rename(const char *old_path, const char *new_path) goto out_old; } - ret = ext4l_resolve_file(new_path, &new_dir_dentry, &new_dentry, + ret = ext4l_resolve_file(state, new_path, &new_dir_dentry, &new_dentry, &new_path_copy); if (ret) goto out_old; @@ -1345,7 +1380,7 @@ int ext4l_rename(const char *old_path, const char *new_path) if (sync_ret) ret = sync_ret; /* Commit superblock with updated free counts */ - ext4_commit_super(efs.sb); + ext4_commit_super(state->sb); } out_new: @@ -1478,16 +1513,17 @@ static int ext4l_opendir_actor(struct dir_context *ctx, const char *name, return 1; } -int ext4l_opendir(const char *filename, struct fs_dir_stream **dirsp) +int ext4l_opendir(struct ext4l_state *state, const char *filename, + struct fs_dir_stream **dirsp) { struct ext4l_dir *dir; struct inode *inode; int ret; - if (!efs.mounted) + if (!state->mounted) return -ENODEV; - ret = ext4l_resolve_path(filename, &inode); + ret = ext4l_resolve_path(state, filename, &inode); if (ret) return ret; @@ -1512,20 +1548,21 @@ int ext4l_opendir(const char *filename, struct fs_dir_stream **dirsp) } /* Increment open dir count to prevent unmount */ - efs.open_dirs++; + state->open_dirs++; *dirsp = (struct fs_dir_stream *)dir; return 0; } -int ext4l_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) +int ext4l_readdir(struct ext4l_state *state, struct fs_dir_stream *dirs, + struct fs_dirent **dentp) { struct ext4l_dir *dir = (struct ext4l_dir *)dirs; struct ext4l_readdir_ctx ctx; int ret; - if (!efs.mounted) + if (!state->mounted) return -ENODEV; memset(&dir->dirent, '\0', sizeof(dir->dirent)); @@ -1557,7 +1594,7 @@ int ext4l_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp) return 0; } -void ext4l_closedir(struct fs_dir_stream *dirs) +void ext4l_closedir(struct ext4l_state *state, struct fs_dir_stream *dirs) { struct ext4l_dir *dir = (struct ext4l_dir *)dirs; @@ -1568,6 +1605,59 @@ void ext4l_closedir(struct fs_dir_stream *dirs) } /* Decrement open dir count */ - if (efs.open_dirs > 0) - efs.open_dirs--; + if (state->open_dirs > 0) + state->open_dirs--; +} + +/* Legacy wrappers for write, dir, uuid, and statfs functions */ + +int ext4l_get_uuid_legacy(u8 *uuid) +{ + return ext4l_get_uuid(&efs, uuid); +} + +int ext4l_statfs_legacy(struct fs_statfs *stats) +{ + return ext4l_statfs(&efs, stats); +} + +int ext4l_write_legacy(const char *filename, void *buf, loff_t offset, + loff_t len, loff_t *actwrite) +{ + return ext4l_write(&efs, filename, buf, offset, len, actwrite); +} + +int ext4l_unlink_legacy(const char *filename) +{ + return ext4l_unlink(&efs, filename); +} + +int ext4l_mkdir_legacy(const char *dirname) +{ + return ext4l_mkdir(&efs, dirname); +} + +int ext4l_ln_legacy(const char *filename, const char *linkname) +{ + return ext4l_ln(&efs, filename, linkname); +} + +int ext4l_rename_legacy(const char *old_path, const char *new_path) +{ + return ext4l_rename(&efs, old_path, new_path); +} + +int ext4l_opendir_legacy(const char *filename, struct fs_dir_stream **dirsp) +{ + return ext4l_opendir(&efs, filename, dirsp); +} + +int ext4l_readdir_legacy(struct fs_dir_stream *dirs, struct fs_dirent **dentp) +{ + return ext4l_readdir(&efs, dirs, dentp); +} + +void ext4l_closedir_legacy(struct fs_dir_stream *dirs) +{ + ext4l_closedir(&efs, dirs); } diff --git a/fs/fs_legacy.c b/fs/fs_legacy.c index 84292ad06c0..5286f07c659 100644 --- a/fs/fs_legacy.c +++ b/fs/fs_legacy.c @@ -279,20 +279,20 @@ static struct fstype_info fstypes[] = { .null_dev_desc_ok = false, .probe = ext4l_probe, .close = ext4l_close, - .ls = ext4l_ls, - .exists = ext4l_exists, - .size = ext4l_size, - .read = ext4l_read, - .write = ext4l_op_ptr(ext4l_write, fs_write_unsupported), + .ls = ext4l_ls_legacy, + .exists = ext4l_exists_legacy, + .size = ext4l_size_legacy, + .read = ext4l_read_legacy, + .write = ext4l_op_ptr(ext4l_write_legacy, fs_write_unsupported), .uuid = ext4l_uuid, - .opendir = ext4l_opendir, - .readdir = ext4l_readdir, - .closedir = ext4l_closedir, - .unlink = ext4l_op_ptr(ext4l_unlink, fs_unlink_unsupported), - .mkdir = ext4l_op_ptr(ext4l_mkdir, fs_mkdir_unsupported), - .ln = ext4l_op_ptr(ext4l_ln, fs_ln_unsupported), - .rename = ext4l_op_ptr(ext4l_rename, fs_rename_unsupported), - .statfs = ext4l_statfs, + .opendir = ext4l_opendir_legacy, + .readdir = ext4l_readdir_legacy, + .closedir = ext4l_closedir_legacy, + .unlink = ext4l_op_ptr(ext4l_unlink_legacy, fs_unlink_unsupported), + .mkdir = ext4l_op_ptr(ext4l_mkdir_legacy, fs_mkdir_unsupported), + .ln = ext4l_op_ptr(ext4l_ln_legacy, fs_ln_unsupported), + .rename = ext4l_op_ptr(ext4l_rename_legacy, fs_rename_unsupported), + .statfs = ext4l_statfs_legacy, }, #endif #if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_XPL_BUILD) diff --git a/include/ext4l.h b/include/ext4l.h index 5ef1cc0a30f..ee3942e47e9 100644 --- a/include/ext4l.h +++ b/include/ext4l.h @@ -76,46 +76,41 @@ void ext4l_umount(struct ext4l_state *state); */ void ext4l_close(void); -/** - * ext4l_ls() - List directory contents - * - * @dirname: Directory path to list - * Return: 0 on success, negative on error - */ -int ext4l_ls(const char *dirname); - -/** - * ext4l_exists() - Check if a file or directory exists - * - * @filename: Path to check - * Return: 1 if exists, 0 if not - */ -int ext4l_exists(const char *filename); - -/** - * ext4l_size() - Get the size of a file - * - * @filename: Path to file - * @sizep: Returns the file size - * Return: 0 on success, negative on error - */ -int ext4l_size(const char *filename, loff_t *sizep); - -/** - * ext4l_read() - Read data from a file - * - * @filename: Path to file - * @buf: Buffer to read data into - * @offset: Byte offset to start reading from - * @len: Number of bytes to read (0 = read entire file from offset) - * @actread: Returns actual bytes read - * Return: 0 on success, negative on error - */ -int ext4l_read(const char *filename, void *buf, loff_t offset, loff_t len, - loff_t *actread); - -/** - * ext4l_write() - Write data to a file +/* State-aware functions for VFS callers */ +int ext4l_ls(struct ext4l_state *state, const char *dirname); +int ext4l_exists(struct ext4l_state *state, const char *filename); +int ext4l_size(struct ext4l_state *state, const char *filename, + loff_t *sizep); +int ext4l_read(struct ext4l_state *state, const char *filename, + void *buf, loff_t offset, loff_t len, loff_t *actread); + +/* Legacy wrappers using the global state */ +int ext4l_ls_legacy(const char *dirname); +int ext4l_exists_legacy(const char *filename); +int ext4l_size_legacy(const char *filename, loff_t *sizep); +int ext4l_read_legacy(const char *filename, void *buf, loff_t offset, + loff_t len, loff_t *actread); + +/* State-aware functions for remaining operations */ +int ext4l_get_uuid(struct ext4l_state *state, u8 *uuid); +int ext4l_statfs(struct ext4l_state *state, struct fs_statfs *stats); +int ext4l_write(struct ext4l_state *state, const char *filename, + void *buf, loff_t offset, loff_t len, loff_t *actwrite); +int ext4l_unlink(struct ext4l_state *state, const char *filename); +int ext4l_mkdir(struct ext4l_state *state, const char *dirname); +int ext4l_ln(struct ext4l_state *state, const char *filename, + const char *linkname); +int ext4l_rename(struct ext4l_state *state, const char *old_path, + const char *new_path); +int ext4l_opendir(struct ext4l_state *state, const char *filename, + struct fs_dir_stream **dirsp); +int ext4l_readdir(struct ext4l_state *state, struct fs_dir_stream *dirs, + struct fs_dirent **dentp); +void ext4l_closedir(struct ext4l_state *state, + struct fs_dir_stream *dirs); + +/** + * ext4l_write_legacy() - Write data to a file * * Creates the file if it doesn't exist. Overwrites existing content. * @@ -127,30 +122,30 @@ int ext4l_read(const char *filename, void *buf, loff_t offset, loff_t len, * Return: 0 on success, -EROFS if read-only, -ENODEV if not mounted, * -ENOTDIR if parent is not a directory, negative on other errors */ -int ext4l_write(const char *filename, void *buf, loff_t offset, loff_t len, - loff_t *actwrite); +int ext4l_write_legacy(const char *filename, void *buf, loff_t offset, + loff_t len, loff_t *actwrite); /** - * ext4l_unlink() - Delete a file + * ext4l_unlink_legacy() - Delete a file * * @filename: Path to file to delete * Return: 0 on success, -ENOENT if file not found, -EISDIR if path is a * directory, -EROFS if read-only, negative on other errors */ -int ext4l_unlink(const char *filename); +int ext4l_unlink_legacy(const char *filename); /** - * ext4l_mkdir() - Create a directory + * ext4l_mkdir_legacy() - Create a directory * * @dirname: Path of directory to create * Return: 0 on success, -EEXIST if directory already exists, * -ENOTDIR if parent is not a directory, -EROFS if read-only, * negative on other errors */ -int ext4l_mkdir(const char *dirname); +int ext4l_mkdir_legacy(const char *dirname); /** - * ext4l_ln() - Create a symbolic link + * ext4l_ln_legacy() - Create a symbolic link * * Creates the symlink, replacing any existing file (like ln -sf). * Refuses to replace a directory. @@ -161,10 +156,10 @@ int ext4l_mkdir(const char *dirname); * -ENOTDIR if parent is not a directory, -EROFS if read-only, * negative on other errors */ -int ext4l_ln(const char *filename, const char *target); +int ext4l_ln_legacy(const char *filename, const char *target); /** - * ext4l_rename() - Rename a file or directory + * ext4l_rename_legacy() - Rename a file or directory * * @old_path: Current path of file or directory * @new_path: New path for file or directory @@ -172,15 +167,15 @@ int ext4l_ln(const char *filename, const char *target); * -ENOTDIR if parent is not a directory, -EROFS if read-only, * negative on other errors */ -int ext4l_rename(const char *old_path, const char *new_path); +int ext4l_rename_legacy(const char *old_path, const char *new_path); /** - * ext4l_get_uuid() - Get the filesystem UUID + * ext4l_get_uuid_legacy() - Get the filesystem UUID * * @uuid: Buffer to receive the 16-byte UUID * Return: 0 on success, -ENODEV if not mounted */ -int ext4l_get_uuid(u8 *uuid); +int ext4l_get_uuid_legacy(u8 *uuid); /** * ext4l_uuid() - Get the filesystem UUID as a string @@ -191,37 +186,37 @@ int ext4l_get_uuid(u8 *uuid); int ext4l_uuid(char *uuid_str); /** - * ext4l_statfs() - Get filesystem statistics + * ext4l_statfs_legacy() - Get filesystem statistics * * @stats: Pointer to fs_statfs structure to fill * Return: 0 on success, -ENODEV if not mounted */ -int ext4l_statfs(struct fs_statfs *stats); +int ext4l_statfs_legacy(struct fs_statfs *stats); /** - * ext4l_opendir() - Open a directory for iteration + * ext4l_opendir_legacy() - Open a directory for iteration * * @filename: Directory path * @dirsp: Returns directory stream pointer * Return: 0 on success, -ENODEV if not mounted, -ENOTDIR if not a directory, * -ENOMEM on allocation failure */ -int ext4l_opendir(const char *filename, struct fs_dir_stream **dirsp); +int ext4l_opendir_legacy(const char *filename, struct fs_dir_stream **dirsp); /** - * ext4l_readdir() - Read the next directory entry + * ext4l_readdir_legacy() - Read the next directory entry * - * @dirs: Directory stream from ext4l_opendir + * @dirs: Directory stream from ext4l_opendir_legacy * @dentp: Returns pointer to directory entry * Return: 0 on success, -ENODEV if not mounted, -ENOENT at end of directory */ -int ext4l_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp); +int ext4l_readdir_legacy(struct fs_dir_stream *dirs, struct fs_dirent **dentp); /** - * ext4l_closedir() - Close a directory stream + * ext4l_closedir_legacy() - Close a directory stream * * @dirs: Directory stream to close */ -void ext4l_closedir(struct fs_dir_stream *dirs); +void ext4l_closedir_legacy(struct fs_dir_stream *dirs); #endif /* __EXT4L_H__ */ diff --git a/test/fs/ext4l.c b/test/fs/ext4l.c index 0843ba1d5ba..7548c3049bb 100644 --- a/test/fs/ext4l.c +++ b/test/fs/ext4l.c @@ -63,7 +63,7 @@ static int fs_test_ext4l_msgs_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Get the UUID and clear the env var now we have the output */ - ut_assertok(ext4l_get_uuid(uuid)); + ut_assertok(ext4l_get_uuid_legacy(uuid)); uuid_bin_to_str(uuid, uuid_str, UUID_STR_FORMAT_STD); ut_assertok(env_set("ext4l_msgs", NULL)); @@ -142,11 +142,11 @@ static int fs_test_ext4l_opendir_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Open root directory */ - ut_assertok(ext4l_opendir("/", &dirs)); + ut_assertok(ext4l_opendir_legacy("/", &dirs)); ut_assertnonnull(dirs); /* Iterate through entries */ - while (!ext4l_readdir(dirs, &dent)) { + while (!ext4l_readdir_legacy(dirs, &dent)) { ut_assertnonnull(dent); count++; if (!strcmp(dent->name, "testfile.txt")) { @@ -162,7 +162,7 @@ static int fs_test_ext4l_opendir_norun(struct unit_test_state *uts) } } - ext4l_closedir(dirs); + ext4l_closedir_legacy(dirs); /* Verify we found expected entries */ ut_assert(found_testfile); @@ -173,11 +173,11 @@ static int fs_test_ext4l_opendir_norun(struct unit_test_state *uts) /* Now test reading the subdirectory */ ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); - ut_assertok(ext4l_opendir("/subdir", &dirs)); + ut_assertok(ext4l_opendir_legacy("/subdir", &dirs)); ut_assertnonnull(dirs); count = 0; - while (!ext4l_readdir(dirs, &dent)) { + while (!ext4l_readdir_legacy(dirs, &dent)) { ut_assertnonnull(dent); count++; if (!strcmp(dent->name, "nested.txt")) { @@ -187,7 +187,7 @@ static int fs_test_ext4l_opendir_norun(struct unit_test_state *uts) } } - ext4l_closedir(dirs); + ext4l_closedir_legacy(dirs); ut_assert(found_nested); /* At least ., .., nested.txt */ @@ -199,9 +199,9 @@ FS_TEST_ARGS(fs_test_ext4l_opendir_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_exists_norun() - Test ext4l_exists function + * fs_test_ext4l_exists_norun() - Test ext4l_exists_legacy function * - * Verifies that ext4l_exists correctly reports file existence. + * Verifies that ext4l_exists_legacy correctly reports file existence. * * Arguments: * fs_image: Path to the ext4 filesystem image @@ -215,10 +215,10 @@ static int fs_test_ext4l_exists_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Test existing directory */ - ut_asserteq(1, ext4l_exists("/")); + ut_asserteq(1, ext4l_exists_legacy("/")); /* Test non-existent paths */ - ut_asserteq(0, ext4l_exists("/no/such/path")); + ut_asserteq(0, ext4l_exists_legacy("/no/such/path")); return 0; } @@ -226,9 +226,9 @@ FS_TEST_ARGS(fs_test_ext4l_exists_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_size_norun() - Test ext4l_size function + * fs_test_ext4l_size_norun() - Test ext4l_size_legacy function * - * Verifies that ext4l_size correctly reports file size. + * Verifies that ext4l_size_legacy correctly reports file size. * * Arguments: * fs_image: Path to the ext4 filesystem image @@ -243,15 +243,15 @@ static int fs_test_ext4l_size_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Test root directory size - one block on a 4K block filesystem */ - ut_assertok(ext4l_size("/", &size)); + ut_assertok(ext4l_size_legacy("/", &size)); ut_asserteq(SZ_4K, size); /* Test file size - testfile.txt contains "hello world\n" */ - ut_assertok(ext4l_size("/testfile.txt", &size)); + ut_assertok(ext4l_size_legacy("/testfile.txt", &size)); ut_asserteq(12, size); /* Test non-existent path returns -ENOENT */ - ut_asserteq(-ENOENT, ext4l_size("/no/such/path", &size)); + ut_asserteq(-ENOENT, ext4l_size_legacy("/no/such/path", &size)); return 0; } @@ -259,7 +259,7 @@ FS_TEST_ARGS(fs_test_ext4l_size_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_read_norun() - Test ext4l_read function + * fs_test_ext4l_read_norun() - Test ext4l_read_legacy function * * Verifies that ext4l can read file contents. * @@ -278,18 +278,20 @@ static int fs_test_ext4l_read_norun(struct unit_test_state *uts) /* Read the test file - contains "hello world\n" (12 bytes) */ memset(buf, '\0', sizeof(buf)); - ut_assertok(ext4l_read("/testfile.txt", buf, 0, 0, &actread)); + ut_assertok(ext4l_read_legacy("/testfile.txt", buf, 0, 0, &actread)); ut_asserteq(12, actread); ut_asserteq_str("hello world\n", buf); /* Test partial read with offset */ memset(buf, '\0', sizeof(buf)); - ut_assertok(ext4l_read("/testfile.txt", buf, 6, 5, &actread)); + ut_assertok(ext4l_read_legacy("/testfile.txt", buf, 6, 5, &actread)); ut_asserteq(5, actread); ut_asserteq_str("world", buf); /* Verify read returns error for non-existent path */ - ut_asserteq(-ENOENT, ext4l_read("/no/such/file", buf, 0, 10, &actread)); + ut_asserteq(-ENOENT, + ext4l_read_legacy("/no/such/file", buf, 0, 10, + &actread)); return 0; } @@ -345,7 +347,7 @@ static int fs_test_ext4l_fsinfo_norun(struct unit_test_state *uts) ut_assertnonnull(fs_image); ut_assertok(run_commandf("host bind 0 %s", fs_image)); ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); - ut_assertok(ext4l_statfs(&stats)); + ut_assertok(ext4l_statfs_legacy(&stats)); used = stats.blocks - stats.bfree; console_record_reset_enable(); @@ -367,7 +369,7 @@ FS_TEST_ARGS(fs_test_ext4l_fsinfo_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_statfs_norun() - Test ext4l_statfs function + * fs_test_ext4l_statfs_norun() - Test ext4l_statfs_legacy function * * Verifies that ext4l can return filesystem statistics. * @@ -384,7 +386,7 @@ static int fs_test_ext4l_statfs_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Get filesystem statistics */ - ut_assertok(ext4l_statfs(&stats)); + ut_assertok(ext4l_statfs_legacy(&stats)); /* Verify reasonable values for a 64MB filesystem */ ut_asserteq(SZ_4K, stats.bsize); @@ -398,7 +400,7 @@ FS_TEST_ARGS(fs_test_ext4l_statfs_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_write_norun() - Test ext4l_write function + * fs_test_ext4l_write_norun() - Test ext4l_write_legacy function * * Verifies that ext4l can write file contents to the filesystem. * @@ -419,18 +421,19 @@ static int fs_test_ext4l_write_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Write a new file */ - ut_assertok(ext4l_write("/newfile.txt", (void *)test_data, 0, - test_len, &actwrite)); + ut_assertok(ext4l_write_legacy("/newfile.txt", (void *)test_data, + 0, test_len, &actwrite)); ut_asserteq(test_len, actwrite); /* Verify the file exists and has correct size */ - ut_asserteq(1, ext4l_exists("/newfile.txt")); - ut_assertok(ext4l_size("/newfile.txt", &size)); + ut_asserteq(1, ext4l_exists_legacy("/newfile.txt")); + ut_assertok(ext4l_size_legacy("/newfile.txt", &size)); ut_asserteq(test_len, size); /* Read back and verify contents */ memset(read_buf, '\0', sizeof(read_buf)); - ut_assertok(ext4l_read("/newfile.txt", read_buf, 0, 0, &actread)); + ut_assertok(ext4l_read_legacy("/newfile.txt", read_buf, 0, 0, + &actread)); ut_asserteq(test_len, actread); ut_asserteq_str(test_data, read_buf); @@ -440,7 +443,7 @@ FS_TEST_ARGS(fs_test_ext4l_write_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_unlink_norun() - Test ext4l_unlink function + * fs_test_ext4l_unlink_norun() - Test ext4l_unlink_legacy function * * Verifies that ext4l can delete files from the filesystem. * @@ -459,21 +462,21 @@ static int fs_test_ext4l_unlink_norun(struct unit_test_state *uts) ut_assertok(fs_set_blk_dev("host", "0", FS_TYPE_ANY)); /* Create a new file to unlink */ - ut_assertok(ext4l_write("/unlinkme.txt", (void *)test_data, 0, - test_len, &actwrite)); + ut_assertok(ext4l_write_legacy("/unlinkme.txt", (void *)test_data, + 0, test_len, &actwrite)); ut_asserteq(test_len, actwrite); /* Verify file exists (same mount) */ - ut_asserteq(1, ext4l_exists("/unlinkme.txt")); + ut_asserteq(1, ext4l_exists_legacy("/unlinkme.txt")); /* Unlink the file */ - ut_assertok(ext4l_unlink("/unlinkme.txt")); + ut_assertok(ext4l_unlink_legacy("/unlinkme.txt")); /* Verify file no longer exists */ - ut_asserteq(0, ext4l_exists("/unlinkme.txt")); + ut_asserteq(0, ext4l_exists_legacy("/unlinkme.txt")); /* Verify unlinking non-existent file returns -ENOENT */ - ut_asserteq(-ENOENT, ext4l_unlink("/nonexistent")); + ut_asserteq(-ENOENT, ext4l_unlink_legacy("/nonexistent")); return 0; } @@ -481,7 +484,7 @@ FS_TEST_ARGS(fs_test_ext4l_unlink_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_mkdir_norun() - Test ext4l_mkdir function + * fs_test_ext4l_mkdir_norun() - Test ext4l_mkdir_legacy function * * Verifies that ext4l can create directories on the filesystem. * @@ -506,21 +509,21 @@ static int fs_test_ext4l_mkdir_norun(struct unit_test_state *uts) test_counter++; /* Create a new directory */ - ret = ext4l_mkdir(dir_name); + ret = ext4l_mkdir_legacy(dir_name); ut_assertok(ret); /* Verify directory exists */ - ut_asserteq(1, ext4l_exists(dir_name)); + ut_asserteq(1, ext4l_exists_legacy(dir_name)); /* Verify creating duplicate returns -EEXIST */ - ut_asserteq(-EEXIST, ext4l_mkdir(dir_name)); + ut_asserteq(-EEXIST, ext4l_mkdir_legacy(dir_name)); /* Create nested directory */ - ut_assertok(ext4l_mkdir(subdir_name)); - ut_asserteq(1, ext4l_exists(subdir_name)); + ut_assertok(ext4l_mkdir_legacy(subdir_name)); + ut_asserteq(1, ext4l_exists_legacy(subdir_name)); /* Verify creating directory in non-existent parent returns -ENOENT */ - ut_asserteq(-ENOENT, ext4l_mkdir("/nonexistent/dir")); + ut_asserteq(-ENOENT, ext4l_mkdir_legacy("/nonexistent/dir")); return 0; } @@ -528,7 +531,7 @@ FS_TEST_ARGS(fs_test_ext4l_mkdir_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_ln_norun() - Test ext4l_ln function + * fs_test_ext4l_ln_norun() - Test ext4l_ln_legacy function * * Verifies that ext4l can create symbolic links on the filesystem. * @@ -554,33 +557,33 @@ static int fs_test_ext4l_ln_norun(struct unit_test_state *uts) test_counter++; /* - * Create a symbolic link. ext4l_ln follows U-Boot's ln command - * convention: ext4l_ln(target, linkname) creates linkname pointing - * to target. + * Create a symbolic link. ext4l_ln_legacy follows U-Boot's ln command + * convention: ext4l_ln_legacy(target, linkname) creates linkname + * pointing to target. */ - ut_assertok(ext4l_ln(target, link_name)); + ut_assertok(ext4l_ln_legacy(target, link_name)); /* Verify symlink exists */ - ut_asserteq(1, ext4l_exists(link_name)); + ut_asserteq(1, ext4l_exists_legacy(link_name)); /* * Size through symlink should be target file's size (12 bytes), * since ext4l_resolve_path follows symlinks (like stat, not lstat) */ - ut_assertok(ext4l_size(link_name, &size)); + ut_assertok(ext4l_size_legacy(link_name, &size)); ut_asserteq(12, size); /* Verify we can read through the symlink */ memset(buf, '\0', sizeof(buf)); - ut_assertok(ext4l_read(link_name, buf, 0, 0, &actread)); + ut_assertok(ext4l_read_legacy(link_name, buf, 0, 0, &actread)); ut_asserteq(12, actread); ut_asserteq_str("hello world\n", buf); /* Verify creating duplicate succeeds (like ln -sf) */ - ut_assertok(ext4l_ln(target, link_name)); + ut_assertok(ext4l_ln_legacy(target, link_name)); /* Verify creating symlink in non-existent parent returns -ENOENT */ - ut_asserteq(-ENOENT, ext4l_ln(target, "/nonexistent/link")); + ut_asserteq(-ENOENT, ext4l_ln_legacy(target, "/nonexistent/link")); return 0; } @@ -588,7 +591,7 @@ FS_TEST_ARGS(fs_test_ext4l_ln_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); /** - * fs_test_ext4l_rename_norun() - Test ext4l_rename function + * fs_test_ext4l_rename_norun() - Test ext4l_rename_legacy function * * Verifies that ext4l can rename files and directories on the filesystem. * @@ -616,32 +619,32 @@ static int fs_test_ext4l_rename_norun(struct unit_test_state *uts) test_counter++; /* Create a file to rename */ - ut_assertok(ext4l_write(old_name, (void *)test_data, 0, - test_len, &actwrite)); + ut_assertok(ext4l_write_legacy(old_name, (void *)test_data, + 0, test_len, &actwrite)); ut_asserteq(test_len, actwrite); /* Verify file exists */ - ut_asserteq(1, ext4l_exists(old_name)); + ut_asserteq(1, ext4l_exists_legacy(old_name)); /* Rename the file */ - ut_assertok(ext4l_rename(old_name, new_name)); + ut_assertok(ext4l_rename_legacy(old_name, new_name)); /* Verify old name no longer exists, new name does */ - ut_asserteq(0, ext4l_exists(old_name)); - ut_asserteq(1, ext4l_exists(new_name)); + ut_asserteq(0, ext4l_exists_legacy(old_name)); + ut_asserteq(1, ext4l_exists_legacy(new_name)); /* Verify file size is preserved */ - ut_assertok(ext4l_size(new_name, &size)); + ut_assertok(ext4l_size_legacy(new_name, &size)); ut_asserteq(test_len, size); /* Verify renaming non-existent file returns -ENOENT */ - ut_asserteq(-ENOENT, ext4l_rename("/nonexistent", "/newname")); + ut_asserteq(-ENOENT, ext4l_rename_legacy("/nonexistent", "/newname")); /* Test cross-directory rename */ - ut_assertok(ext4l_mkdir(subdir_name)); - ut_assertok(ext4l_rename(new_name, moved_name)); - ut_asserteq(0, ext4l_exists(new_name)); - ut_asserteq(1, ext4l_exists(moved_name)); + ut_assertok(ext4l_mkdir_legacy(subdir_name)); + ut_assertok(ext4l_rename_legacy(new_name, moved_name)); + ut_asserteq(0, ext4l_exists_legacy(new_name)); + ut_asserteq(1, ext4l_exists_legacy(moved_name)); return 0; } 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 */ From patchwork Sat Apr 11 00:36:40 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 2163 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=1775867838; bh=zCmsleLP/YuCYVsRLCm2CqlppZYFQI4BnNqO2ntC0MY=; 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=TLyfH4EOsMXYOffCn1vUzPEP/elY2w9W26/k7XG5La10FAUlGv3YpiOAs1uPSRatE ZUjdKNRhEWg7dC4TJAc2T6/PS/fU2HqhANjqsciKLn6Mmmx6OweIP4mDY5o1VSaq/L 6fcOFefE8vNiPUk7btmaDRL//SFOKjqI09TbW4k7Dv8TTTz9bFcZTKeSai982ydmaA iyTl3/HecCj2F76fXSmgnvNSy5emOPoRTuBSnr+wbJJ4c4/bxGDq9GA0aIWhrXzcMP xxonzH2Pi2DubTWiKPRtkDCm+NNDwgQ7eR3/O2wcSj8S5OSTeGYUAiMkBDwZToCcCF iA/DE5LrXuJxQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id E1F616A430 for ; Fri, 10 Apr 2026 18:37:18 -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 sdPqKtJNRJfo for ; Fri, 10 Apr 2026 18:37:18 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867838; bh=zCmsleLP/YuCYVsRLCm2CqlppZYFQI4BnNqO2ntC0MY=; 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=TLyfH4EOsMXYOffCn1vUzPEP/elY2w9W26/k7XG5La10FAUlGv3YpiOAs1uPSRatE ZUjdKNRhEWg7dC4TJAc2T6/PS/fU2HqhANjqsciKLn6Mmmx6OweIP4mDY5o1VSaq/L 6fcOFefE8vNiPUk7btmaDRL//SFOKjqI09TbW4k7Dv8TTTz9bFcZTKeSai982ydmaA iyTl3/HecCj2F76fXSmgnvNSy5emOPoRTuBSnr+wbJJ4c4/bxGDq9GA0aIWhrXzcMP xxonzH2Pi2DubTWiKPRtkDCm+NNDwgQ7eR3/O2wcSj8S5OSTeGYUAiMkBDwZToCcCF iA/DE5LrXuJxQ== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 04F666A434 for ; Fri, 10 Apr 2026 18:37:18 -0600 (MDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1775867834; bh=Yp5JjVzRkkJKQWKmdhGPnugNF64CmJSEtwUzh2JQpYU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EG0XcsJkyeTk+PdwL14w9YhwTU38RwAo1jcyqk8rxLMkYyqyl6UYipi3hEIqzvI8B lEo/O1VxXFyGe3PCTX5YB3Yxaj/kWv14w2c1Y5vtf6tOt5qd+lt0NJ1DlAaxLLeSQM Hrp5X9pBK7JrppQrnrS5fFbIC50/HM2/fdTvUBMBXj2UR5L7C3Ed9VTe9SH8dmkLMz ad+5v/R0QA+t3Y11P9OENutbZgQpCur0Fqwwq5HR0Y3X2WNzskzROVwvP+I+PGhP8/ +w50SN6nqJpLbynY5rEQpvho9vpRbigBpPUVyneOKvN3R4Ysg9jDv3lI5yHL4mfVtO CZ9sj92rRV+JQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id 6716C6A429; 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 EKE14LwlpHFj; 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=1775867831; bh=UAkPq1wLVvp8oavW4Q7dSBQdVQC5DsAPPa3qSFcHAR4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nE7B1bcLyYVYbo2619Ryd4eQ0dDnRVLHmdEc+ipKEfS0gO0T4qLWFGDY3/K0G+1rI 1NqFmekSpTQMK95AkquFKi1eHkGJwheV4dD0o5TmQAq548lWpjb+S2TAEjeuX01Gtr tk8gFL3YoeIDWF3WzibHyfaN6tokcpOAcnZjDaJRRkp81HcYLBVnDbx7ft298uie2y VgeZSceyigwclljwSEMLhs1p3wmSC40edIEBPTunXKzZUtwWLYIyjWPWEt4+Ijcznm c2Kxvxe9Pdl+ycKQXa+wNukkQkQ3623Nb7rZ2yCG53s8VyQdh/s2RjFkV1b0bSEPRn uxFUxak0xcA/Q== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 7D8D56A42B; Fri, 10 Apr 2026 18:37:11 -0600 (MDT) From: Simon Glass To: U-Boot Concept Date: Fri, 10 Apr 2026 18:36:40 -0600 Message-ID: <20260411003647.2592586-9-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: XPDXGV553EHQJZP6FKBBFT5ELNQZBAGB X-Message-ID-Hash: XPDXGV553EHQJZP6FKBBFT5ELNQZBAGB 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 8/8] ext4l: Add dual-mount test 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 a test that mounts two different ext4 images simultaneously via VFS and reads a file from each, verifying they return different content. Signed-off-by: Simon Glass --- test/fs/ext4l.c | 82 +++++++++++++++++++++++++++++ test/py/tests/test_fs/test_ext4l.py | 34 ++++++++++++ 2 files changed, 116 insertions(+) diff --git a/test/fs/ext4l.c b/test/fs/ext4l.c index 7548c3049bb..9e4c8823f2f 100644 --- a/test/fs/ext4l.c +++ b/test/fs/ext4l.c @@ -6,13 +6,19 @@ * Written by Simon Glass */ +#include #include +#include #include #include #include #include #include +#include +#include #include +#include +#include #include #include #include @@ -650,3 +656,79 @@ static int fs_test_ext4l_rename_norun(struct unit_test_state *uts) } FS_TEST_ARGS(fs_test_ext4l_rename_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, { "fs_image", UT_ARG_STR }); + +#define EXT4L_ARG_IMAGE_A 0 +#define EXT4L_ARG_IMAGE_B 1 +#define BUF_ADDR 0x10000 + +/** + * fs_test_ext4l_dual_mount_norun() - Test two ext4l mounts simultaneously + * + * Mount two different ext4 images at /mnt and /mnt2, read a file from + * each, and verify they return different content. + * + * Arguments: + * fs_image_a: Path to first ext4 filesystem image (contains "alpha\n") + * fs_image_b: Path to second ext4 filesystem image (contains "bravo\n") + */ +static int fs_test_ext4l_dual_mount_norun(struct unit_test_state *uts) +{ + const char *image_a = ut_str(EXT4L_ARG_IMAGE_A); + const char *image_b = ut_str(EXT4L_ARG_IMAGE_B); + struct udevice *dev_a, *dev_b, *blk; + struct blk_desc *desc; + char *buf; + + ut_assertok(vfs_init()); + + /* Mount first image at /mnt */ + ut_assertok(host_create_device("ext4a", true, DEFAULT_BLKSZ, &dev_a)); + ut_assertok(host_attach_file(dev_a, image_a)); + ut_assertok(blk_get_from_parent(dev_a, &blk)); + ut_assertok(device_probe(blk)); + desc = dev_get_uclass_plat(blk); + ut_assertok(run_commandf("mount host %x:0 /mnt", desc->devnum)); + ut_assert_console_end(); + + /* Mount second image at /mnt2 */ + ut_assertok(host_create_device("ext4b", true, DEFAULT_BLKSZ, &dev_b)); + ut_assertok(host_attach_file(dev_b, image_b)); + ut_assertok(blk_get_from_parent(dev_b, &blk)); + ut_assertok(device_probe(blk)); + desc = dev_get_uclass_plat(blk); + ut_assertok(run_commandf("mount host %x:0 /mnt2", desc->devnum)); + ut_assert_console_end(); + + /* Read from first mount */ + buf = map_sysmem(BUF_ADDR, 0x100); + memset(buf, '\0', 0x100); + ut_assertok(run_commandf("load %x /mnt/id.txt", BUF_ADDR)); + ut_assert_nextline("6 bytes read"); + ut_assert_console_end(); + ut_asserteq_str("alpha\n", buf); + + /* Read from second mount */ + memset(buf, '\0', 0x100); + ut_assertok(run_commandf("load %x /mnt2/id.txt", BUF_ADDR)); + ut_assert_nextline("6 bytes read"); + ut_assert_console_end(); + ut_asserteq_str("bravo\n", buf); + unmap_sysmem(buf); + + /* Unmount both */ + ut_assertok(run_command("umount /mnt2", 0)); + ut_assert_console_end(); + ut_assertok(run_command("umount /mnt", 0)); + ut_assert_console_end(); + + ut_assertok(host_detach_file(dev_b)); + ut_assertok(device_unbind(dev_b)); + ut_assertok(host_detach_file(dev_a)); + ut_assertok(device_unbind(dev_a)); + + return 0; +} +FS_TEST_ARGS(fs_test_ext4l_dual_mount_norun, + UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, + { "fs_image_a", UT_ARG_STR }, + { "fs_image_b", UT_ARG_STR }); diff --git a/test/py/tests/test_fs/test_ext4l.py b/test/py/tests/test_fs/test_ext4l.py index eb332d1b154..e029539572f 100644 --- a/test/py/tests/test_fs/test_ext4l.py +++ b/test/py/tests/test_fs/test_ext4l.py @@ -14,6 +14,8 @@ from tempfile import NamedTemporaryFile import pytest +from tests.fs_helper import FsHelper + @pytest.mark.buildconfigspec('sandbox') @pytest.mark.buildconfigspec('fs_ext4l') @@ -146,3 +148,35 @@ class TestExt4l: """Test that ext4l can rename files and directories.""" with ubman.log.section('Test ext4l rename'): ubman.run_ut('fs', 'fs_test_ext4l_rename', fs_image=ext4_image) + + @pytest.fixture(scope='class') + def dual_images(self, u_boot_config): + """Create two ext4 images with different content. + + Image A contains id.txt with "alpha\\n". + Image B contains id.txt with "bravo\\n". + + Yields: + tuple: (path_a, path_b) paths to the two images + """ + helpers = [] + for label, content in [('a', 'alpha'), ('b', 'bravo')]: + fsh = FsHelper(u_boot_config, 'ext4', 64, f'dual_{label}') + fsh.setup() + with open(os.path.join(fsh.srcdir, 'id.txt'), 'w') as f: + f.write(content + '\n') + fsh.mk_fs() + helpers.append(fsh) + + yield tuple(fsh.fs_img for fsh in helpers) + + for fsh in helpers: + fsh.cleanup() + + @pytest.mark.buildconfigspec('cmd_vfs') + def test_dual_mount(self, ubman, dual_images): + """Test that two ext4l filesystems can be mounted simultaneously.""" + image_a, image_b = dual_images + with ubman.log.section('Test ext4l dual mount'): + ubman.run_ut('fs', 'fs_test_ext4l_dual_mount', + fs_image_a=image_a, fs_image_b=image_b)