Commit 00fdf13a authored by Liu Bo's avatar Liu Bo Committed by Chris Mason

Btrfs: fix a crash of clone with inline extents's split

xfstests's btrfs/035 triggers a BUG_ON, which we use to detect the split
of inline extents in __btrfs_drop_extents().

For inline extents, we cannot duplicate another EXTENT_DATA item, because
it breaks the rule of inline extents, that is, 'start offset' needs to be 0.

We have set limitations for the source inode's compressed inline extents,
because it needs to decompress and recompress.  Now the destination inode's
inline extents also need similar limitations.

With this, xfstests btrfs/035 doesn't run into panic.
Signed-off-by: default avatarLiu Bo <bo.li.liu@oracle.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 73b802f4
...@@ -804,7 +804,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -804,7 +804,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
*/ */
if (start > key.offset && end < extent_end) { if (start > key.offset && end < extent_end) {
BUG_ON(del_nr > 0); BUG_ON(del_nr > 0);
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = -EINVAL;
break;
}
memcpy(&new_key, &key, sizeof(new_key)); memcpy(&new_key, &key, sizeof(new_key));
new_key.offset = start; new_key.offset = start;
...@@ -847,7 +850,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -847,7 +850,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
* | -------- extent -------- | * | -------- extent -------- |
*/ */
if (start <= key.offset && end < extent_end) { if (start <= key.offset && end < extent_end) {
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = -EINVAL;
break;
}
memcpy(&new_key, &key, sizeof(new_key)); memcpy(&new_key, &key, sizeof(new_key));
new_key.offset = end; new_key.offset = end;
...@@ -870,7 +876,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans, ...@@ -870,7 +876,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
*/ */
if (start > key.offset && end >= extent_end) { if (start > key.offset && end >= extent_end) {
BUG_ON(del_nr > 0); BUG_ON(del_nr > 0);
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE); if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
ret = -EINVAL;
break;
}
btrfs_set_file_extent_num_bytes(leaf, fi, btrfs_set_file_extent_num_bytes(leaf, fi,
start - key.offset); start - key.offset);
......
...@@ -3087,8 +3087,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode, ...@@ -3087,8 +3087,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
new_key.offset + datal, new_key.offset + datal,
1); 1);
if (ret) { if (ret) {
btrfs_abort_transaction(trans, root, if (ret != -EINVAL)
ret); btrfs_abort_transaction(trans,
root, ret);
btrfs_end_transaction(trans, root); btrfs_end_transaction(trans, root);
goto out; goto out;
} }
...@@ -3246,8 +3247,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd, ...@@ -3246,8 +3247,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
* decompress into destination's address_space (the file offset * decompress into destination's address_space (the file offset
* may change, so source mapping won't do), then recompress (or * may change, so source mapping won't do), then recompress (or
* otherwise reinsert) a subrange. * otherwise reinsert) a subrange.
* - allow ranges within the same file to be cloned (provided *
* they don't overlap)? * - split destination inode's inline extents. The inline extents can
* be either compressed or non-compressed.
*/ */
/* the destination must be opened for writing */ /* the destination must be opened for writing */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment