aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2014-03-10 06:56:07 -0400
committerChris Mason <clm@fb.com>2014-03-21 20:35:18 -0400
commit00fdf13a2e9f313a044288aa59d3b8ec29ff904a (patch)
tree968425a22d4ccb20cdd2f9878083e0258d09d857 /fs/btrfs
parent73b802f44747e824f6efe273903149ede9ddf741 (diff)
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 <bo.li.liu@oracle.com> Signed-off-by: Chris Mason <clm@fb.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/file.c15
-rw-r--r--fs/btrfs/ioctl.c10
2 files changed, 18 insertions, 7 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index b2143b8c33c5..036f506cabd8 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -804,7 +804,10 @@ next_slot:
804 */ 804 */
805 if (start > key.offset && end < extent_end) { 805 if (start > key.offset && end < extent_end) {
806 BUG_ON(del_nr > 0); 806 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 }
808 811
809 memcpy(&new_key, &key, sizeof(new_key)); 812 memcpy(&new_key, &key, sizeof(new_key));
810 new_key.offset = start; 813 new_key.offset = start;
@@ -847,7 +850,10 @@ next_slot:
847 * | -------- extent -------- | 850 * | -------- extent -------- |
848 */ 851 */
849 if (start <= key.offset && end < extent_end) { 852 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 }
851 857
852 memcpy(&new_key, &key, sizeof(new_key)); 858 memcpy(&new_key, &key, sizeof(new_key));
853 new_key.offset = end; 859 new_key.offset = end;
@@ -870,7 +876,10 @@ next_slot:
870 */ 876 */
871 if (start > key.offset && end >= extent_end) { 877 if (start > key.offset && end >= extent_end) {
872 BUG_ON(del_nr > 0); 878 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 }
874 883
875 btrfs_set_file_extent_num_bytes(leaf, fi, 884 btrfs_set_file_extent_num_bytes(leaf, fi,
876 start - key.offset); 885 start - key.offset);
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 3ca313b138ca..6778fa3c6ed2 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -3087,8 +3087,9 @@ process_slot:
3087 new_key.offset + datal, 3087 new_key.offset + datal,
3088 1); 3088 1);
3089 if (ret) { 3089 if (ret) {
3090 btrfs_abort_transaction(trans, root, 3090 if (ret != -EINVAL)
3091 ret); 3091 btrfs_abort_transaction(trans,
3092 root, ret);
3092 btrfs_end_transaction(trans, root); 3093 btrfs_end_transaction(trans, root);
3093 goto out; 3094 goto out;
3094 } 3095 }
@@ -3246,8 +3247,9 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
3246 * decompress into destination's address_space (the file offset 3247 * decompress into destination's address_space (the file offset
3247 * may change, so source mapping won't do), then recompress (or 3248 * may change, so source mapping won't do), then recompress (or
3248 * otherwise reinsert) a subrange. 3249 * otherwise reinsert) a subrange.
3249 * - allow ranges within the same file to be cloned (provided 3250 *
3250 * they don't overlap)? 3251 * - split destination inode's inline extents. The inline extents can
3252 * be either compressed or non-compressed.
3251 */ 3253 */
3252 3254
3253 /* the destination must be opened for writing */ 3255 /* the destination must be opened for writing */