Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe3f566c authored by Li Zefan's avatar Li Zefan Committed by Chris Mason
Browse files

Btrfs: Fix oops for defrag with compression turned on



When we defrag a file, whose size can be fit into an inline extent,
with compression enabled, the compress type is set to be
fs_info->compress_type, which is 0 if the btrfs filesystem is mounted
without compress option. This leads to oops.

Reported-by: default avatarDaniel Blueman <daniel.blueman@gmail.com>
Signed-off-by: default avatarLi Zefan <lizf@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 200da64e
Loading
Loading
Loading
Loading
+8 −9
Original line number Original line Diff line number Diff line
@@ -111,6 +111,7 @@ static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
				struct btrfs_root *root, struct inode *inode,
				struct btrfs_root *root, struct inode *inode,
				u64 start, size_t size, size_t compressed_size,
				u64 start, size_t size, size_t compressed_size,
				int compress_type,
				struct page **compressed_pages)
				struct page **compressed_pages)
{
{
	struct btrfs_key key;
	struct btrfs_key key;
@@ -125,12 +126,9 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
	size_t cur_size = size;
	size_t cur_size = size;
	size_t datasize;
	size_t datasize;
	unsigned long offset;
	unsigned long offset;
	int compress_type = BTRFS_COMPRESS_NONE;


	if (compressed_size && compressed_pages) {
	if (compressed_size && compressed_pages)
		compress_type = root->fs_info->compress_type;
		cur_size = compressed_size;
		cur_size = compressed_size;
	}


	path = btrfs_alloc_path();
	path = btrfs_alloc_path();
	if (!path)
	if (!path)
@@ -220,7 +218,7 @@ fail:
static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
				 struct btrfs_root *root,
				 struct btrfs_root *root,
				 struct inode *inode, u64 start, u64 end,
				 struct inode *inode, u64 start, u64 end,
				 size_t compressed_size,
				 size_t compressed_size, int compress_type,
				 struct page **compressed_pages)
				 struct page **compressed_pages)
{
{
	u64 isize = i_size_read(inode);
	u64 isize = i_size_read(inode);
@@ -253,7 +251,7 @@ static noinline int cow_file_range_inline(struct btrfs_trans_handle *trans,
		inline_len = min_t(u64, isize, actual_end);
		inline_len = min_t(u64, isize, actual_end);
	ret = insert_inline_extent(trans, root, inode, start,
	ret = insert_inline_extent(trans, root, inode, start,
				   inline_len, compressed_size,
				   inline_len, compressed_size,
				   compressed_pages);
				   compress_type, compressed_pages);
	BUG_ON(ret);
	BUG_ON(ret);
	btrfs_delalloc_release_metadata(inode, end + 1 - start);
	btrfs_delalloc_release_metadata(inode, end + 1 - start);
	btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
	btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
@@ -432,12 +430,13 @@ again:
			 * to make an uncompressed inline extent.
			 * to make an uncompressed inline extent.
			 */
			 */
			ret = cow_file_range_inline(trans, root, inode,
			ret = cow_file_range_inline(trans, root, inode,
						    start, end, 0, NULL);
						    start, end, 0, 0, NULL);
		} else {
		} else {
			/* try making a compressed inline extent */
			/* try making a compressed inline extent */
			ret = cow_file_range_inline(trans, root, inode,
			ret = cow_file_range_inline(trans, root, inode,
						    start, end,
						    start, end,
						    total_compressed, pages);
						    total_compressed,
						    compress_type, pages);
		}
		}
		if (ret == 0) {
		if (ret == 0) {
			/*
			/*
@@ -791,7 +790,7 @@ static noinline int cow_file_range(struct inode *inode,
	if (start == 0) {
	if (start == 0) {
		/* lets try to make an inline extent */
		/* lets try to make an inline extent */
		ret = cow_file_range_inline(trans, root, inode,
		ret = cow_file_range_inline(trans, root, inode,
					    start, end, 0, NULL);
					    start, end, 0, 0, NULL);
		if (ret == 0) {
		if (ret == 0) {
			extent_clear_unlock_delalloc(inode,
			extent_clear_unlock_delalloc(inode,
				     &BTRFS_I(inode)->io_tree,
				     &BTRFS_I(inode)->io_tree,