Skip to content

Commit 00fdf13

Browse files
Liu Bomasoncl
authored andcommitted
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: Liu Bo <[email protected]> Signed-off-by: Chris Mason <[email protected]>
1 parent 73b802f commit 00fdf13

File tree

2 files changed

+18
-7
lines changed

2 files changed

+18
-7
lines changed

fs/btrfs/file.c

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -804,7 +804,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
804804
*/
805805
if (start > key.offset && end < extent_end) {
806806
BUG_ON(del_nr > 0);
807-
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
807+
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
808+
ret = -EINVAL;
809+
break;
810+
}
808811

809812
memcpy(&new_key, &key, sizeof(new_key));
810813
new_key.offset = start;
@@ -847,7 +850,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
847850
* | -------- extent -------- |
848851
*/
849852
if (start <= key.offset && end < extent_end) {
850-
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
853+
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
854+
ret = -EINVAL;
855+
break;
856+
}
851857

852858
memcpy(&new_key, &key, sizeof(new_key));
853859
new_key.offset = end;
@@ -870,7 +876,10 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
870876
*/
871877
if (start > key.offset && end >= extent_end) {
872878
BUG_ON(del_nr > 0);
873-
BUG_ON(extent_type == BTRFS_FILE_EXTENT_INLINE);
879+
if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
880+
ret = -EINVAL;
881+
break;
882+
}
874883

875884
btrfs_set_file_extent_num_bytes(leaf, fi,
876885
start - key.offset);

fs/btrfs/ioctl.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3087,8 +3087,9 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
30873087
new_key.offset + datal,
30883088
1);
30893089
if (ret) {
3090-
btrfs_abort_transaction(trans, root,
3091-
ret);
3090+
if (ret != -EINVAL)
3091+
btrfs_abort_transaction(trans,
3092+
root, ret);
30923093
btrfs_end_transaction(trans, root);
30933094
goto out;
30943095
}
@@ -3246,8 +3247,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
32463247
* decompress into destination's address_space (the file offset
32473248
* may change, so source mapping won't do), then recompress (or
32483249
* otherwise reinsert) a subrange.
3249-
* - allow ranges within the same file to be cloned (provided
3250-
* they don't overlap)?
3250+
*
3251+
* - split destination inode's inline extents. The inline extents can
3252+
* be either compressed or non-compressed.
32513253
*/
32523254

32533255
/* the destination must be opened for writing */

0 commit comments

Comments
 (0)