Merge patch series "fs: btrfs: report file sizes from readdir"
Cole Munz <Munzzyy1@proton.me> says: As agreed on the v1 thread, the fix and the cleanups are now separate patches: - patch 1 is the fix in the v1 shape - patch 2 makes btrfs_search_slot() release the path on error like the kernel version does. That is where the btrfs_size() leak came from. Suggested by Qu. - patch 3 is the dedup Alexey asked about. One helper shared by btrfs_readdir() and btrfs_size(). The pending btrfs test suite still passes on top of the readdir series: 5 passed. Link: https://lore.kernel.org/r/cover.1785660029.git.Munzzyy1@proton.me
This commit is contained in:
+54
-23
@@ -88,12 +88,43 @@ static unsigned int btrfs_dirent_type_to_fs_type(u8 dirent_type)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the size stored in an inode item. A missing item is -ENOENT and
|
||||
* leaves *size untouched.
|
||||
*/
|
||||
static int btrfs_get_inode_size(struct btrfs_root *root, u64 ino, u64 *size)
|
||||
{
|
||||
struct btrfs_inode_item *ii;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
int ret;
|
||||
|
||||
key.objectid = ino;
|
||||
key.type = BTRFS_INODE_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
|
||||
btrfs_init_path(&path);
|
||||
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0)
|
||||
ret = -ENOENT;
|
||||
if (!ret) {
|
||||
ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
|
||||
struct btrfs_inode_item);
|
||||
*size = btrfs_inode_size(path.nodes[0], ii);
|
||||
}
|
||||
btrfs_release_path(&path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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_root *root;
|
||||
struct btrfs_key location;
|
||||
struct btrfs_key key;
|
||||
u8 type;
|
||||
int ret;
|
||||
@@ -110,13 +141,29 @@ 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) {
|
||||
u64 size;
|
||||
|
||||
ret = btrfs_get_inode_size(root, location.objectid, &size);
|
||||
if (ret < 0 && ret != -ENOENT)
|
||||
return ret;
|
||||
if (!ret)
|
||||
dent->size = size;
|
||||
}
|
||||
|
||||
*dentp = dent;
|
||||
return 0;
|
||||
}
|
||||
@@ -151,10 +198,8 @@ int btrfs_exists(const char *file)
|
||||
int btrfs_size(const char *file, loff_t *size)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = current_fs_info;
|
||||
struct btrfs_inode_item *ii;
|
||||
struct btrfs_root *root;
|
||||
struct btrfs_path path;
|
||||
struct btrfs_key key;
|
||||
u64 isize;
|
||||
u64 ino;
|
||||
u8 type;
|
||||
int ret;
|
||||
@@ -169,27 +214,13 @@ int btrfs_size(const char *file, loff_t *size)
|
||||
printf("Not a regular file: %s\n", file);
|
||||
return -ENOENT;
|
||||
}
|
||||
btrfs_init_path(&path);
|
||||
key.objectid = ino;
|
||||
key.type = BTRFS_INODE_ITEM_KEY;
|
||||
key.offset = 0;
|
||||
|
||||
ret = btrfs_search_slot(NULL, root, &key, &path, 0, 0);
|
||||
if (ret < 0) {
|
||||
printf("Cannot lookup ino %llu\n", ino);
|
||||
ret = btrfs_get_inode_size(root, ino, &isize);
|
||||
if (ret) {
|
||||
printf("Cannot read size of ino %llu\n", ino);
|
||||
return ret;
|
||||
}
|
||||
if (ret > 0) {
|
||||
printf("Ino %llu does not exist\n", ino);
|
||||
ret = -ENOENT;
|
||||
goto out;
|
||||
}
|
||||
ii = btrfs_item_ptr(path.nodes[0], path.slots[0],
|
||||
struct btrfs_inode_item);
|
||||
*size = btrfs_inode_size(path.nodes[0], ii);
|
||||
out:
|
||||
btrfs_release_path(&path);
|
||||
return ret;
|
||||
*size = isize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_read(const char *file, void *buf, loff_t offset, loff_t len,
|
||||
|
||||
+12
-4
@@ -425,8 +425,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans,
|
||||
level = btrfs_header_level(b);
|
||||
p->nodes[level] = b;
|
||||
ret = check_block(fs_info, p, level);
|
||||
if (ret)
|
||||
return -1;
|
||||
if (ret) {
|
||||
ret = -1;
|
||||
goto err;
|
||||
}
|
||||
ret = btrfs_bin_search(b, key, &slot);
|
||||
if (level != 0) {
|
||||
if (ret && slot > 0)
|
||||
@@ -461,8 +463,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans,
|
||||
break;
|
||||
|
||||
b = read_node_slot(fs_info, b, slot);
|
||||
if (!extent_buffer_uptodate(b))
|
||||
return -EIO;
|
||||
if (!extent_buffer_uptodate(b)) {
|
||||
ret = -EIO;
|
||||
goto err;
|
||||
}
|
||||
} else {
|
||||
p->slots[level] = slot;
|
||||
/*
|
||||
@@ -479,6 +483,10 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans,
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
|
||||
err:
|
||||
btrfs_release_path(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+2
-1
@@ -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,
|
||||
|
||||
+6
-1
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user