On Tue, Dec 11, 2018 at 10:19:45AM +0000, fdman...@kernel.org wrote: > From: Filipe Manana <fdman...@suse.com> > > If we create a snapshot of a snapshot currently being used by a send > operation, we can end up with send failing unexpectedly (returning > -ENOENT error to user space for example). The following diagram shows > how this happens. > > CPU 1 CPU2 > CPU3 > > btrfs_ioctl_send() > (...) > create_snapshot() > -> creates snapshot of a > root used by the send > task > btrfs_commit_transaction() > create_pending_snapshot() > __get_inode_info() > btrfs_search_slot() > btrfs_search_slot_get_root() > down_read commit_root_sem > > get reference on eb of the > commit root > -> eb with bytenr == X > > up_read commit_root_sem > > btrfs_cow_block(root node) > btrfs_free_tree_block() > -> creates delayed ref to > free the extent > > btrfs_run_delayed_refs() > -> runs the delayed ref, > adds extent to > fs_info->pinned_extents > > btrfs_finish_extent_commit() > unpin_extent_range() > -> marks extent as free > in the free space cache > > transaction commit finishes > > > btrfs_start_transaction() > (...) > > btrfs_cow_block() > > btrfs_alloc_tree_block() > > btrfs_reserve_extent() > -> > allocates extent at > > bytenr == X > > btrfs_init_new_buffer(bytenr X) > > btrfs_find_create_tree_block() > > alloc_extent_buffer(bytenr X) > > find_extent_buffer(bytenr X) > > -> returns existing eb, > > which the send task got > > (...) > -> > modifies content of the > > eb with bytenr == X > > -> uses an eb that now > belongs to some other > tree and no more matches > the commit root of the > snapshot, resuts will be > unpredictable > > The consequences of this race can be various, and can lead to searches in > the commit root performed by the send task failing unexpectedly (unable to > find inode items, returning -ENOENT to user space, for example) or not > failing because an inode item with the same number was added to the tree > that reused the metadata extent, in which case send can behave incorrectly > in the worst case or just fail later for some reason. > > Fix this by performing a copy of the commit root's extent buffer when doing > a search in the context of a send operation. > > Signed-off-by: Filipe Manana <fdman...@suse.com>
Nice catch, patch added to misc-next, thanks.