[Concept,14/16] fs: Add statfs method to the filesystem interface

Message ID 20251227204318.886983-15-sjg@u-boot.org
State New
Headers
Series fs: ext4l: Complete read-only filesystem support (Part I) |

Commit Message

Simon Glass Dec. 27, 2025, 8:43 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add infrastructure for obtaining filesystem statistics. This includes:

- struct fs_statfs to hold block size, total blocks, and free blocks
- statfs method in struct fstype_info
- fs_statfs() wrapper function
- fs_statfs_unsupported() stub for filesystems without support

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

 fs/fs_legacy.c      | 37 +++++++++++++++++++++++++++++++++++++
 include/fs_legacy.h | 21 +++++++++++++++++++++
 2 files changed, 58 insertions(+)
  

Patch

diff --git a/fs/fs_legacy.c b/fs/fs_legacy.c
index 71f8e56715f..e8a5f8d9672 100644
--- a/fs/fs_legacy.c
+++ b/fs/fs_legacy.c
@@ -154,6 +154,11 @@  static inline int fs_rename_unsupported(const char *old_path,
 	return -1;
 }
 
+static inline int fs_statfs_unsupported(struct fs_statfs *stats)
+{
+	return -1;
+}
+
 struct fstype_info {
 	int fstype;
 	char *name;
@@ -195,6 +200,13 @@  struct fstype_info {
 	int (*mkdir)(const char *dirname);
 	int (*ln)(const char *filename, const char *target);
 	int (*rename)(const char *old_path, const char *new_path);
+
+	/*
+	 * Get filesystem statistics. On success return 0 and fill stats
+	 * with block size, total blocks, and free blocks. On error
+	 * return -errno. See fs_statfs().
+	 */
+	int (*statfs)(struct fs_statfs *stats);
 };
 
 static struct fstype_info fstypes[] = {
@@ -228,6 +240,7 @@  static struct fstype_info fstypes[] = {
 #else
 		.rename = fs_rename_unsupported,
 #endif
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 
@@ -256,6 +269,7 @@  static struct fstype_info fstypes[] = {
 		.unlink = fs_unlink_unsupported,
 		.mkdir = fs_mkdir_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #if CONFIG_IS_ENABLED(FS_EXT4L)
@@ -278,6 +292,7 @@  static struct fstype_info fstypes[] = {
 		.mkdir = fs_mkdir_unsupported,
 		.ln = fs_ln_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #if IS_ENABLED(CONFIG_SANDBOX) && !IS_ENABLED(CONFIG_XPL_BUILD)
@@ -298,6 +313,7 @@  static struct fstype_info fstypes[] = {
 		.mkdir = fs_mkdir_unsupported,
 		.ln = fs_ln_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #if CONFIG_IS_ENABLED(SEMIHOSTING)
@@ -318,6 +334,7 @@  static struct fstype_info fstypes[] = {
 		.mkdir = fs_mkdir_unsupported,
 		.ln = fs_ln_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #ifndef CONFIG_XPL_BUILD
@@ -339,6 +356,7 @@  static struct fstype_info fstypes[] = {
 		.mkdir = fs_mkdir_unsupported,
 		.ln = fs_ln_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #endif
@@ -361,6 +379,7 @@  static struct fstype_info fstypes[] = {
 		.mkdir = fs_mkdir_unsupported,
 		.ln = fs_ln_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #endif
@@ -384,6 +403,7 @@  static struct fstype_info fstypes[] = {
 		.unlink = fs_unlink_unsupported,
 		.mkdir = fs_mkdir_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #if IS_ENABLED(CONFIG_FS_EROFS)
@@ -406,6 +426,7 @@  static struct fstype_info fstypes[] = {
 		.unlink = fs_unlink_unsupported,
 		.mkdir = fs_mkdir_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #if IS_ENABLED(CONFIG_FS_EXFAT)
@@ -428,6 +449,7 @@  static struct fstype_info fstypes[] = {
 		.unlink = exfat_fs_unlink,
 		.mkdir = exfat_fs_mkdir,
 		.rename = exfat_fs_rename,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 #if CONFIG_IS_ENABLED(VIRTIO_FS)
@@ -450,6 +472,7 @@  static struct fstype_info fstypes[] = {
 		.unlink = fs_unlink_unsupported,
 		.mkdir = fs_mkdir_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 #endif
 	{
@@ -469,6 +492,7 @@  static struct fstype_info fstypes[] = {
 		.mkdir = fs_mkdir_unsupported,
 		.ln = fs_ln_unsupported,
 		.rename = fs_rename_unsupported,
+		.statfs = fs_statfs_unsupported,
 	},
 };
 
@@ -624,6 +648,19 @@  int fs_size(const char *filename, loff_t *size)
 	return ret;
 }
 
+int fs_statfs(struct fs_statfs *stats)
+{
+	int ret;
+
+	struct fstype_info *info = fs_get_info(fs_type);
+
+	ret = info->statfs(stats);
+
+	fs_close();
+
+	return ret;
+}
+
 #if CONFIG_IS_ENABLED(LMB)
 /* Check if a file may be read to the given address */
 static int fs_read_lmb_check(const char *filename, ulong addr, loff_t offset,
diff --git a/include/fs_legacy.h b/include/fs_legacy.h
index f1be6fbdc13..331a15cf7bd 100644
--- a/include/fs_legacy.h
+++ b/include/fs_legacy.h
@@ -172,6 +172,27 @@  struct fs_dirent *fs_readdir(struct fs_dir_stream *dirs);
  */
 void fs_closedir(struct fs_dir_stream *dirs);
 
+/**
+ * struct fs_statfs - filesystem statistics
+ *
+ * @bsize: block size
+ * @blocks: total blocks
+ * @bfree: free blocks
+ */
+struct fs_statfs {
+	ulong bsize;
+	u64 blocks;
+	u64 bfree;
+};
+
+/**
+ * fs_statfs - Get filesystem statistics
+ *
+ * @stats: pointer to struct fs_statfs to fill
+ * Return: 0 on success, -1 on error
+ */
+int fs_statfs(struct fs_statfs *stats);
+
 /**
  * fs_unlink - delete a file or directory
  *