aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/extent_io.c14
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
3888static 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
3888static void copy_pages(struct page *dst_page, struct page *src_page, 3894static 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 }