diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 9a8dc16673b43387a60cb33bfc111b8d16a0471d..a14c02112141b7aec29f0e49cf9b7e56b752ca32 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -4415,22 +4415,27 @@ static int btrfs_log_prealloc_extents(struct btrfs_trans_handle *trans, path->slots[0]++; continue; } - if (!dropped_extents) { + if (!dropped_extents || key.offset < truncate_offset) { /* - * Avoid logging extent items logged in past fsync calls - * and leading to duplicate keys in the log tree. + * Avoid overlapping items in the log tree. The first time we + * get here, get rid of everything from a past fsync. After + * that, if the current extent starts before the end of the last + * extent we copied, truncate the last one. This can happen if + * an ordered extent completion modifies the subvolume tree + * while btrfs_next_leaf() has the tree unlocked. */ do { ret = btrfs_truncate_inode_items(trans, root->log_root, &inode->vfs_inode, - truncate_offset, + min(key.offset, truncate_offset), BTRFS_EXTENT_DATA_KEY); } while (ret == -EAGAIN); if (ret) goto out; dropped_extents = true; } + truncate_offset = btrfs_file_extent_end(path); if (ins_nr == 0) start_slot = slot; ins_nr++;