Btrfs: make sure not to return overlapping extents to fiemap

The btrfs fiemap code was incorrectly returning duplicate or overlapping
extents in some cases. cp was blindly trusting this result and we would
end up with a destination file that was bigger than the original because
some bytes were copied twice.

The fix here adjusts our offsets to make sure we're always moving
forward in the fiemap results.

Signed-off-by: Chris Mason <chris.mason@oracle.com>

+27 -6
+27 -6
fs/btrfs/extent_io.c
··· 3046 } 3047 3048 while (!end) { 3049 - off = extent_map_end(em); 3050 - if (off >= max) 3051 - end = 1; 3052 3053 - em_start = em->start; 3054 - em_len = em->len; 3055 em_end = extent_map_end(em); 3056 emflags = em->flags; 3057 disko = 0; 3058 flags = 0; 3059 3060 if (em->block_start == EXTENT_MAP_LAST_BYTE) { 3061 end = 1; ··· 3088 flags |= (FIEMAP_EXTENT_DELALLOC | 3089 FIEMAP_EXTENT_UNKNOWN); 3090 } else { 3091 - disko = em->block_start; 3092 } 3093 if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) 3094 flags |= FIEMAP_EXTENT_ENCODED;
··· 3046 } 3047 3048 while (!end) { 3049 + u64 offset_in_extent; 3050 3051 + /* break if the extent we found is outside the range */ 3052 + if (em->start >= max || extent_map_end(em) < off) 3053 + break; 3054 + 3055 + /* 3056 + * get_extent may return an extent that starts before our 3057 + * requested range. We have to make sure the ranges 3058 + * we return to fiemap always move forward and don't 3059 + * overlap, so adjust the offsets here 3060 + */ 3061 + em_start = max(em->start, off); 3062 + 3063 + /* 3064 + * record the offset from the start of the extent 3065 + * for adjusting the disk offset below 3066 + */ 3067 + offset_in_extent = em_start - em->start; 3068 em_end = extent_map_end(em); 3069 + em_len = em_end - em_start; 3070 emflags = em->flags; 3071 disko = 0; 3072 flags = 0; 3073 + 3074 + /* 3075 + * bump off for our next call to get_extent 3076 + */ 3077 + off = extent_map_end(em); 3078 + if (off >= max) 3079 + end = 1; 3080 3081 if (em->block_start == EXTENT_MAP_LAST_BYTE) { 3082 end = 1; ··· 3067 flags |= (FIEMAP_EXTENT_DELALLOC | 3068 FIEMAP_EXTENT_UNKNOWN); 3069 } else { 3070 + disko = em->block_start + offset_in_extent; 3071 } 3072 if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) 3073 flags |= FIEMAP_EXTENT_ENCODED;