From: Qu Wenruo wqu@suse.com
[ Upstream commit 23019d3e6617a8ec99a8d2f5947aa3dd8a74a1b8 ]
Btrfs utilizes inline data extent for the following cases:
- Regular small files - Symlinks
And "btrfs check" detects any file extents that are too large as an error.
It's not a problem for 4K block size, but for the incoming smaller block sizes (2K), it can cause problems due to bad limits:
- Non-compressed inline data extents We do not allow a non-compressed inline data extent to be as large as block size.
- Symlinks Currently the only real limit on symlinks are 4K, which can be larger than 2K block size.
These will result btrfs-check to report too large file extents.
Fix it by adding proper size checks for the above cases.
Signed-off-by: Qu Wenruo wqu@suse.com Reviewed-by: David Sterba dsterba@suse.com Signed-off-by: David Sterba dsterba@suse.com Signed-off-by: Sasha Levin sashal@kernel.org --- fs/btrfs/inode.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 5b842276573e8..3dee0565ad21a 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -623,6 +623,10 @@ static bool can_cow_file_range_inline(struct btrfs_inode *inode, if (size > fs_info->sectorsize) return false;
+ /* We do not allow a non-compressed extent to be as large as block size. */ + if (data_len >= fs_info->sectorsize) + return false; + /* We cannot exceed the maximum inline data size. */ if (data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info)) return false; @@ -8683,7 +8687,12 @@ static int btrfs_symlink(struct mnt_idmap *idmap, struct inode *dir, struct extent_buffer *leaf;
name_len = strlen(symname); - if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info)) + /* + * Symlinks utilize uncompressed inline extent data, which should not + * reach block size. + */ + if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info) || + name_len >= fs_info->sectorsize) return -ENAMETOOLONG;
inode = new_inode(dir->i_sb);