Hi Cole,

On Sun, Aug 2, 2026 at 9:42 AM Cole Munz <[email protected]> wrote:
>
> 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 <[email protected]>
> ---
> The Fixes: commit is in Tom's tree, applied 2026-07-10 (b4-ty
> [email protected]); 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);

The above repeats much of the calls that have just been done for this
exact entry several lines above inside btrfs_read_next_dir_enrty()

Can you perhaps refactor to avoid this repetition?

Best regards,
Alexey

Reply via email to