diff options
| -rw-r--r-- | fs/btrfs/btrfs.c | 24 | ||||
| -rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
| -rw-r--r-- | 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 e663dda12e8..b2856be0662 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 3fa9a8c9c02..cd3fd669f9a 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 c7b87d60d98..6edda34818b 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: |
