diff options
Diffstat (limited to 'fs/btrfs')
-rw-r--r-- | fs/btrfs/extent_io.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 77c65a0bea34..864e0496cc1c 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -3885,6 +3885,12 @@ static void move_pages(struct page *dst_page, struct page *src_page, | |||
3885 | kunmap_atomic(dst_kaddr, KM_USER0); | 3885 | kunmap_atomic(dst_kaddr, KM_USER0); |
3886 | } | 3886 | } |
3887 | 3887 | ||
3888 | static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len) | ||
3889 | { | ||
3890 | unsigned long distance = (src > dst) ? src - dst : dst - src; | ||
3891 | return distance < len; | ||
3892 | } | ||
3893 | |||
3888 | static void copy_pages(struct page *dst_page, struct page *src_page, | 3894 | static void copy_pages(struct page *dst_page, struct page *src_page, |
3889 | unsigned long dst_off, unsigned long src_off, | 3895 | unsigned long dst_off, unsigned long src_off, |
3890 | unsigned long len) | 3896 | unsigned long len) |
@@ -3892,10 +3898,12 @@ static void copy_pages(struct page *dst_page, struct page *src_page, | |||
3892 | char *dst_kaddr = kmap_atomic(dst_page, KM_USER0); | 3898 | char *dst_kaddr = kmap_atomic(dst_page, KM_USER0); |
3893 | char *src_kaddr; | 3899 | char *src_kaddr; |
3894 | 3900 | ||
3895 | if (dst_page != src_page) | 3901 | if (dst_page != src_page) { |
3896 | src_kaddr = kmap_atomic(src_page, KM_USER1); | 3902 | src_kaddr = kmap_atomic(src_page, KM_USER1); |
3897 | else | 3903 | } else { |
3898 | src_kaddr = dst_kaddr; | 3904 | src_kaddr = dst_kaddr; |
3905 | BUG_ON(areas_overlap(src_off, dst_off, len)); | ||
3906 | } | ||
3899 | 3907 | ||
3900 | memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); | 3908 | memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); |
3901 | kunmap_atomic(dst_kaddr, KM_USER0); | 3909 | kunmap_atomic(dst_kaddr, KM_USER0); |
@@ -3970,7 +3978,7 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, | |||
3970 | "len %lu len %lu\n", dst_offset, len, dst->len); | 3978 | "len %lu len %lu\n", dst_offset, len, dst->len); |
3971 | BUG_ON(1); | 3979 | BUG_ON(1); |
3972 | } | 3980 | } |
3973 | if (dst_offset < src_offset) { | 3981 | if (!areas_overlap(src_offset, dst_offset, len)) { |
3974 | memcpy_extent_buffer(dst, dst_offset, src_offset, len); | 3982 | memcpy_extent_buffer(dst, dst_offset, src_offset, len); |
3975 | return; | 3983 | return; |
3976 | } | 3984 | } |