From patchwork Sat Dec 27 20:43:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Simon Glass X-Patchwork-Id: 1093 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=1766868297; bh=0oL/31OAUv0u1mnTlRa/hjpMBldR56yw9EM3E8q5dIU=; 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=HCvjtfj+ucvsIYqlvs2m8zeLwmcNfcCatNnoD+Yhvso2gv/eM/X+ZMLV9iSmihCDB muOf+AfVJO4QYbxahQYJS0gzSYu68wyJzNbFAUrd2SB18dJKgj7VfFxalOv2y8ss3F 1b/byE8O5rjurB4TkkKSNBokqDgNKx9Rdgfv+gFBE+E5Q/q4pWLTMqQwUvPL5ERVDB cebgK1H1MNz37qXJIU2olNKnZ69joUUpJps/MKrkMTL7ez5V7/EwVMKNUsaBxB72T1 KAzHv1BGqHykSdN/NWc9ISj1YVVrD1DB5aE3fz4nJvYRh7e9GyAveHYVO8bIUPuxaW bgWCO1fHMlDKg== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id EF8F164E55 for ; Sat, 27 Dec 2025 13:44:57 -0700 (MST) 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 Wegu6b82TuEx for ; Sat, 27 Dec 2025 13:44:57 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1766868297; bh=0oL/31OAUv0u1mnTlRa/hjpMBldR56yw9EM3E8q5dIU=; 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=HCvjtfj+ucvsIYqlvs2m8zeLwmcNfcCatNnoD+Yhvso2gv/eM/X+ZMLV9iSmihCDB muOf+AfVJO4QYbxahQYJS0gzSYu68wyJzNbFAUrd2SB18dJKgj7VfFxalOv2y8ss3F 1b/byE8O5rjurB4TkkKSNBokqDgNKx9Rdgfv+gFBE+E5Q/q4pWLTMqQwUvPL5ERVDB cebgK1H1MNz37qXJIU2olNKnZ69joUUpJps/MKrkMTL7ez5V7/EwVMKNUsaBxB72T1 KAzHv1BGqHykSdN/NWc9ISj1YVVrD1DB5aE3fz4nJvYRh7e9GyAveHYVO8bIUPuxaW bgWCO1fHMlDKg== Received: from mail.u-boot.org (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id DF0BE64E4E for ; Sat, 27 Dec 2025 13:44:57 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1766868295; bh=Eh0J5vousLyzGrGAins1x2GOrHEIBBlm69y+wPZmz3U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aesRhqC3oSklfvg7A3ihy9OoiYYbOX6OYmcPLZgYtrJIZlR056mb3m921O9kfHzhk D1JogBcjNTKJID+gmUdpdJZv/qlSDjb2WNHTmOcgs9Mjw3JvTI6O2vnjVpMPfKUfBP NFvsUJITCkWo7Kt3RuHn1T7ixziBnmnaEpkxRcLxb8ICU2Ytzn3pMc3Ig4r6ZPuJXD T7Vj6kpn+B3ebQV6km85uIZkxAS7gc72pzAGdk2qaM8ovrrH0NQixDlheH8tOqao5S aqROqmH1e1GMU31w5w6TT/Y3v7sM11TvVxYZMIgGhICrbT4ZRhGexSJ8cviqGYVnyL PhkoA02fZOxOQ== Received: from localhost (localhost [127.0.0.1]) by mail.u-boot.org (Postfix) with ESMTP id C64EE64E1F; Sat, 27 Dec 2025 13:44:55 -0700 (MST) 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 ZM2qrDbChyN6; Sat, 27 Dec 2025 13:44:55 -0700 (MST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=u-boot.org; s=default; t=1766868291; bh=sPrYb+gZiN12gUu0VBHMC2gxGVIsqS9NNwxoc7aOSdE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ujFmhs48qGCuVYKvj+2mpFfod2wN321qxmroscryoBgkwE+6w6mae/pjZoHexrh78 kCGzCkY2N4Cd8JdYaIiKr3Oi8OZHmqeq1//3RE9J+f5odc3oeFfFv1lZePxt6TAE6P 7z6A5IfHfjyRbwK81Di3mcM26uY7YEfi8CPKNFc1K/rzrQ8rmFayzs6kLjoKZ/8CVq DjQ9KkBigR0vy6lwbPUwwqWeyRqRLfU9AFkhssu1FrEEXZacT0mh+T0WqHSxYE3w93 l4KrMzELwnucq1SRb8LJ5TZ6Asgefi3o3sS555pUhaDoXzrnWeEXSfIpGq2WIx9M01 abWky80YQPZqg== Received: from u-boot.org (unknown [73.34.74.121]) by mail.u-boot.org (Postfix) with ESMTPSA id 1B68564C0C; Sat, 27 Dec 2025 13:44:51 -0700 (MST) From: Simon Glass To: U-Boot Concept Date: Sat, 27 Dec 2025 13:43:11 -0700 Message-ID: <20251227204318.886983-17-sjg@u-boot.org> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20251227204318.886983-1-sjg@u-boot.org> References: <20251227204318.886983-1-sjg@u-boot.org> MIME-Version: 1.0 Message-ID-Hash: SHX7LPDBJDOZQCTSC4S3JG4WU4WMJNS7 X-Message-ID-Hash: SHX7LPDBJDOZQCTSC4S3JG4WU4WMJNS7 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: Heinrich Schuchardt , Simon Glass , "Claude Opus 4 . 5" X-Mailman-Version: 3.3.10 Precedence: list Subject: [Concept] [PATCH 16/16] fs: ext4l: Add statfs support 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 Implement ext4l_statfs() to return filesystem statistics using the ext4 superblock. The function returns block size, total block count, and free block count. Add unit test to verify the statfs implementation returns valid data. Co-developed-by: Claude Opus 4.5 Signed-off-by: Simon Glass --- fs/ext4l/interface.c | 22 ++++++++++++ fs/fs_legacy.c | 2 +- include/ext4l.h | 9 +++++ test/fs/ext4l.c | 52 ++++++++++++++++++++++++++--- test/py/tests/test_fs/test_ext4l.py | 7 ++++ 5 files changed, 86 insertions(+), 6 deletions(-) diff --git a/fs/ext4l/interface.c b/fs/ext4l/interface.c index f25664369e6..7c37c99488a 100644 --- a/fs/ext4l/interface.c +++ b/fs/ext4l/interface.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -100,6 +101,27 @@ int ext4l_uuid(char *uuid_str) return 0; } +/** + * ext4l_statfs() - 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) +{ + struct ext4_super_block *es; + + if (!ext4l_sb) + return -ENODEV; + + es = EXT4_SB(ext4l_sb)->s_es; + stats->bsize = ext4l_sb->s_blocksize; + stats->blocks = ext4_blocks_count(es); + stats->bfree = ext4_free_blocks_count(es); + + return 0; +} + /** * ext4l_set_blk_dev() - Set the block device for ext4l operations * diff --git a/fs/fs_legacy.c b/fs/fs_legacy.c index efb5ab669ff..155092519dd 100644 --- a/fs/fs_legacy.c +++ b/fs/fs_legacy.c @@ -292,7 +292,7 @@ static struct fstype_info fstypes[] = { .mkdir = fs_mkdir_unsupported, .ln = fs_ln_unsupported, .rename = fs_rename_unsupported, - .statfs = fs_statfs_unsupported, + .statfs = ext4l_statfs, }, #endif #if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_XPL_BUILD) diff --git a/include/ext4l.h b/include/ext4l.h index 9d9e79b7695..9cfe4867ffa 100644 --- a/include/ext4l.h +++ b/include/ext4l.h @@ -13,6 +13,7 @@ struct blk_desc; struct disk_partition; struct fs_dir_stream; struct fs_dirent; +struct fs_statfs; /** * ext4l_probe() - Probe a block device for an ext4 filesystem @@ -84,6 +85,14 @@ int ext4l_get_uuid(u8 *uuid); */ int ext4l_uuid(char *uuid_str); +/** + * ext4l_statfs() - 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); + /** * ext4l_opendir() - Open a directory for iteration * diff --git a/test/fs/ext4l.c b/test/fs/ext4l.c index 2641ac3678c..43801f252f7 100644 --- a/test/fs/ext4l.c +++ b/test/fs/ext4l.c @@ -331,7 +331,7 @@ FS_TEST_ARGS(fs_test_ext4l_uuid_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, /** * fs_test_ext4l_fsinfo_norun() - Test fsinfo command * - * This test verifies that the fsinfo command displays filesystem statistics. + * Verifies that the fsinfo command displays filesystem statistics. * * Arguments: * fs_image: Path to the ext4 filesystem image @@ -339,18 +339,60 @@ FS_TEST_ARGS(fs_test_ext4l_uuid_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, static int fs_test_ext4l_fsinfo_norun(struct unit_test_state *uts) { const char *fs_image = ut_str(EXT4L_ARG_IMAGE); + struct fs_statfs stats; + u64 used; 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)); + used = stats.blocks - stats.bfree; + console_record_reset_enable(); ut_assertok(run_commandf("fsinfo host 0")); - ut_assert_nextlinen("Block size:"); - ut_assert_nextlinen("Total blocks:"); - ut_assert_nextlinen("Used blocks:"); - ut_assert_nextlinen("Free blocks:"); + + /* Skip any EXT4-fs mount messages, check output format */ + ut_assert_skip_to_line("Block size: %lu bytes", stats.bsize); + ut_assert_nextlinen("Total blocks: %llu (%llu bytes,", + stats.blocks, stats.blocks * stats.bsize); + ut_assert_nextlinen("Used blocks: %llu (%llu bytes,", + used, used * stats.bsize); + ut_assert_nextlinen("Free blocks: %llu (%llu bytes,", + stats.bfree, stats.bfree * stats.bsize); ut_assert_console_end(); return 0; } 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 + * + * Verifies that ext4l can return filesystem statistics. + * + * Arguments: + * fs_image: Path to the ext4 filesystem image + */ +static int fs_test_ext4l_statfs_norun(struct unit_test_state *uts) +{ + const char *fs_image = ut_str(EXT4L_ARG_IMAGE); + struct fs_statfs stats; + + 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)); + + /* Get filesystem statistics */ + ut_assertok(ext4l_statfs(&stats)); + + /* Verify reasonable values for a 64MB filesystem */ + ut_asserteq(SZ_4K, stats.bsize); + ut_assert(stats.blocks > 0); + ut_assert(stats.bfree > 0); + ut_assert(stats.bfree <= stats.blocks); + + return 0; +} +FS_TEST_ARGS(fs_test_ext4l_statfs_norun, UTF_SCAN_FDT | UTF_CONSOLE | UTF_MANUAL, + { "fs_image", UT_ARG_STR }); diff --git a/test/py/tests/test_fs/test_ext4l.py b/test/py/tests/test_fs/test_ext4l.py index 0a9da40f358..754c2cc69c4 100644 --- a/test/py/tests/test_fs/test_ext4l.py +++ b/test/py/tests/test_fs/test_ext4l.py @@ -125,6 +125,13 @@ class TestExt4l: f'ut -f fs fs_test_ext4l_uuid_norun fs_image={ext4_image}') assert 'failures: 0' in output + def test_statfs(self, ubman, ext4_image): + """Test that ext4l can return filesystem statistics.""" + with ubman.log.section('Test ext4l statfs'): + output = ubman.run_command( + f'ut -f fs fs_test_ext4l_statfs_norun fs_image={ext4_image}') + assert 'failures: 0' in output + def test_fsinfo(self, ubman, ext4_image): """Test that fsinfo command displays filesystem statistics.""" with ubman.log.section('Test ext4l fsinfo'):