All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] fs: btrfs: report file sizes from readdir
@ 2026-08-02  5:42 Cole Munz
  2026-08-02  6:02 ` Alexey Charkov
  0 siblings, 1 reply; 12+ messages in thread
From: Cole Munz @ 2026-08-02  5:42 UTC (permalink / raw)
  To: u-boot; +Cc: Alexey Charkov, Qu Wenruo, Marek Behun, Tom Rini

btrfs_readdir() zeroes the dirent and fills in only the name and the
type, so dent->size stays 0 and every file is listed as zero bytes:

  => ls host 0 /
          0   f_192k.bin
          0   small_3k.bin

Reads themselves are fine, since btrfs_read() takes the size from
btrfs_size(), which does its own inode item lookup. It affects EFI
too: dir_read() in lib/efi_loader/efi_file.c copies dent->size into
both file_size and physical_size, so an EFI application enumerating a
directory on btrfs sees every file as empty, which is the generic-code
path Alexey's readdir series moves btrfs onto.

The custom listing that fs_ls_generic() replaced looked the inode item
up and printed the real size, and every other filesystem in the tree
fills dent->size in its own readdir: ext4fs.c:327, exfat io.c:805,
erofs fs.c:186, squashfs sqfs.c:1095 and fat.c:1555.

btrfs_next_dir_entry() already has the dir item mapped, so read the
key it points at while we are there and hand it back to the caller,
and use that to reach the inode item. A subvolume entry points at a
root item instead and has no size of its own, so leave that one at 0.

  => ls host 0 /
     196608   f_192k.bin
       3000   small_3k.bin

Fixes: 31cf3f177823 ("fs: btrfs: use fs_ls_generic() and drop custom implementation")
Signed-off-by: Cole Munz <Munzzyy1@proton.me>
---
The Fixes: commit is in Tom's tree, applied 2026-07-10 (b4-ty
178372904690.2905849.8798963092987519032.b4-ty@konsulko.com); it has not
reached master yet, so that SHA will not resolve on a public clone today.

Found by a btrfs test suite I am preparing for test/py; I will send that
separately once the pending zstd inline extent fix is applied, since it
depends on it.
 fs/btrfs/btrfs.c    | 24 +++++++++++++++++++++++-
 fs/btrfs/ctree.h    |  3 ++-
 fs/btrfs/dir-item.c |  7 ++++++-
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/btrfs.c b/fs/btrfs/btrfs.c
index e663dda12e80..b2856be0662f 100644
--- a/fs/btrfs/btrfs.c
+++ b/fs/btrfs/btrfs.c
@@ -93,7 +93,10 @@ int btrfs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
 	struct btrfs_dir_stream *dirs = container_of(fs_dirs, struct btrfs_dir_stream, parent);
 	struct btrfs_fs_info *fs_info = current_fs_info;
 	struct fs_dirent *dent = &dirs->dirent;
+	struct btrfs_inode_item *ii;
 	struct btrfs_root *root;
+	struct btrfs_path path;
+	struct btrfs_key location;
 	struct btrfs_key key;
 	u8 type;
 	int ret;
@@ -110,13 +113,32 @@ int btrfs_readdir(struct fs_dir_stream *fs_dirs, struct fs_dirent **dentp)
 
 	memset(dent, 0, sizeof(*dent));
 	ret = btrfs_next_dir_entry(root, dirs->ino, &dirs->offset, dent->name,
-				   sizeof(dent->name), &type);
+				   sizeof(dent->name), &type, &location);
 	if (ret < 0)
 		return ret;
 	if (ret > 0)
 		return -ENOENT;
 
 	dent->type = btrfs_dirent_type_to_fs_type(type);
+
+	/*
+	 * A subvolume entry points at a root item rather than an inode, and
+	 * has no size of its own.  Everything else carries one, and the fs
+	 * layer prints it, so look it up.
+	 */
+	if (location.type == BTRFS_INODE_ITEM_KEY) {
+		btrfs_init_path(&path);
+		ret = btrfs_search_slot(NULL, root, &location, &path, 0, 0);
+		if (ret == 0) {
+			ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
+					    struct btrfs_inode_item);
+			dent->size = btrfs_inode_size(path.nodes[0], ii);
+		}
+		btrfs_release_path(&path);
+		if (ret < 0)
+			return ret;
+	}
+
 	*dentp = dent;
 	return 0;
 }
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 3fa9a8c9c020..cd3fd669f9ae 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1221,7 +1221,8 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
 					     const char *name, int name_len,
 					     int mod);
 int btrfs_next_dir_entry(struct btrfs_root *root, u64 ino, u64 *offset,
-			 char *namebuf, int namebuf_len, u8 *ftype);
+			 char *namebuf, int namebuf_len, u8 *ftype,
+			 struct btrfs_key *location);
 /* inode.c */
 int btrfs_lookup_path(struct btrfs_root *root, u64 ino, const char *filename,
 			struct btrfs_root **root_ret, u64 *ino_ret,
diff --git a/fs/btrfs/dir-item.c b/fs/btrfs/dir-item.c
index c7b87d60d986..6edda34818b8 100644
--- a/fs/btrfs/dir-item.c
+++ b/fs/btrfs/dir-item.c
@@ -126,12 +126,16 @@ struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans,
  * @namebuf:		caller buffer that receives the NUL-terminated name
  * @namebuf_len:	size of @namebuf in bytes
  * @ftype:		receives the BTRFS_FT_* type of the entry
+ * @location:		receives the key the entry points at, so the caller can
+ *			reach the inode item without searching for the name
+ *			again
  *
  * Return: 0 if an entry was returned, 1 when the directory is exhausted,
  *	   -ve on error.
  */
 int btrfs_next_dir_entry(struct btrfs_root *root, u64 ino, u64 *offset,
-			 char *namebuf, int namebuf_len, u8 *ftype)
+			 char *namebuf, int namebuf_len, u8 *ftype,
+			 struct btrfs_key *location)
 {
 	struct btrfs_path path;
 	struct btrfs_key key;
@@ -180,6 +184,7 @@ int btrfs_next_dir_entry(struct btrfs_root *root, u64 ino, u64 *offset,
 			   (unsigned long)(di + 1), name_len);
 	namebuf[name_len] = '\0';
 	*ftype = btrfs_dir_type(path.nodes[0], di);
+	btrfs_dir_item_key_to_cpu(path.nodes[0], di, location);
 	ret = 0;
 
 out:
-- 
2.55.0



^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-08-10 20:53 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-02  5:42 [PATCH] fs: btrfs: report file sizes from readdir Cole Munz
2026-08-02  6:02 ` Alexey Charkov
2026-08-02  6:44   ` [PATCH v2] " Cole Munz
2026-08-02  6:47   ` [PATCH] " Qu Wenruo
2026-08-02  7:37     ` Cole Munz
2026-08-02  7:55       ` Qu Wenruo
2026-08-02  9:35         ` [PATCH v3 0/3] " Cole Munz
2026-08-02  9:35           ` [PATCH v3 1/3] " Cole Munz
2026-08-02  9:35           ` [PATCH v3 2/3] fs: btrfs: release the path when btrfs_search_slot() fails Cole Munz
2026-08-02  9:35           ` [PATCH v3 3/3] fs: btrfs: deduplicate the inode size lookup Cole Munz
2026-08-02 22:08           ` [PATCH v3 0/3] fs: btrfs: report file sizes from readdir Qu Wenruo
2026-08-10 20:53           ` Tom Rini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.