@@ -6768,7 +6768,9 @@ static struct extent_map *prev_extent_map(struct extent_map *em)
static int merge_extent_mapping(struct extent_map_tree *em_tree,
struct extent_map *existing,
struct extent_map *em,
- u64 map_start)
+ u64 map_start,
+ struct extent_map *prev_ret,
+ struct extent_map *next_ret)
{
struct extent_map *prev;
struct extent_map *next;
@@ -6786,6 +6788,16 @@ static int merge_extent_mapping(struct extent_map_tree *em_tree,
next = next_extent_map(prev);
}
+ if (prev)
+ *prev_ret = *prev;
+ else
+ *prev_ret = (struct extent_map){ 0 };
+
+ if (next)
+ *next_ret = *next;
+ else
+ *next_ret = (struct extent_map){ 0 };
+
start = prev ? extent_map_end(prev) : em->start;
start = max_t(u64, start, em->start);
end = next ? next->start : extent_map_end(em);
@@ -6857,7 +6869,7 @@ static noinline int uncompress_inline(struct btrfs_path *path,
*/
struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
struct page *page,
- size_t pg_offset, u64 start, u64 len,
+ size_t pg_offset, const u64 start, const u64 len,
int create)
{
struct btrfs_fs_info *fs_info = btrfs_sb(inode->vfs_inode.i_sb);
@@ -7111,14 +7123,34 @@ struct extent_map *btrfs_get_extent(struct btrfs_inode *inode,
} else if (start >= extent_map_end(existing) ||
start <= existing->start) {
+ const u64 em_start = em->start;
+ const u64 em_end = extent_map_end(em);
+ const u64 existing_start = existing->start;
+ const u64 existing_end = extent_map_end(existing);
+ struct extent_map prev, next;
+
/*
* The existing extent map is the one nearest to
* the [start, start + len) range which overlaps
*/
err = merge_extent_mapping(em_tree, existing,
- em, start);
+ em, start, &prev, &next);
free_extent_map(existing);
if (err) {
+ if (err == -EEXIST) {
+ pr_warn("merge_extent_mapping() returned -EEXIST!\n"
+ "given a request to find the extent map for [%llu, %llu)\n"
+ "found and tried to insert [%llu, %llu), but it overlapped\n"
+ "existing extent [%llu, %llu), then was adjusted to\n"
+ "[%llu, %llu) but still overlapped\n"
+ "prev=[%llu, %llu) or next=[%llu, %llu)\n",
+ start, start + len,
+ em_start, em_end,
+ existing_start, existing_end,
+ em->start, extent_map_end(em),
+ prev.start, extent_map_end(&prev),
+ next.start, extent_map_end(&next));
+ }
free_extent_map(em);
em = NULL;
}