linux/fs/btrfs
Filipe Manana fe9c798dbf Btrfs: incremental send, do not delay rename when parent inode is new
When we are checking if we need to delay the rename operation for an
inode we not checking if a parent inode that exists in the send and
parent snapshots is really the same inode or not, that is, we are not
comparing the generation number of the parent inode in the send and
parent snapshots. Not only this results in unnecessarily delaying a
rename operation but also can later on make us generate an incorrect
name for a new inode in the send snapshot that has the same number
as another inode in the parent snapshot but a different generation.

Here follows an example where this happens.

Parent snapshot:

 .                                                  (ino 256, gen 3)
 |--- dir258/                                       (ino 258, gen 7)
 |       |--- dir257/                               (ino 257, gen 7)
 |
 |--- dir259/                                       (ino 259, gen 7)

Send snapshot:

 .                                                  (ino 256, gen 3)
 |--- file258                                       (ino 258, gen 10)
 |
 |--- new_dir259/                                   (ino 259, gen 10)
          |--- dir257/                              (ino 257, gen 7)

The following steps happen when computing the incremental send stream:

1) When processing inode 257, its new parent is created using its orphan
   name (o257-21-0), and the rename operation for inode 257 is delayed
   because its new parent (inode 259) was not yet processed - this
   decision to delay the rename operation does not make much sense
   because the inode 259 in the send snapshot is a new inode, it's not
   the same as inode 259 in the parent snapshot.

2) When processing inode 258 we end up delaying its rmdir operation,
   because inode 257 was not yet renamed (moved away from the directory
   inode 258 represents). We also create the new inode 258 using its
   orphan name "o258-10-0", then rename it to its final name of "file258"
   and then issue a truncate operation for it. However this truncate
   operation contains an incorrect name, which corresponds to the orphan
   name and not to the final name, which makes the receiver fail. This
   happens because when we attempt to compute the inode's current name
   we verify that there's another inode with the same number (258) that
   has its rmdir operation pending and because of that we generate an
   orphan name for the new inode 258 (we do this in the function
   get_cur_path()).

Fix this by not delayed the rename operation of an inode if it has parents
with the same number but different generations in both snapshots.

The following steps reproduce this example scenario.

 $ mkfs.btrfs -f /dev/sdb
 $ mount /dev/sdb /mnt
 $ mkdir /mnt/dir257
 $ mkdir /mnt/dir258
 $ mkdir /mnt/dir259
 $ mv /mnt/dir257 /mnt/dir258/dir257
 $ btrfs subvolume snapshot -r /mnt /mnt/snap1

 $ mv /mnt/dir258/dir257 /mnt/dir257
 $ rmdir /mnt/dir258
 $ rmdir /mnt/dir259

 # Remount the filesystem so that the next created inodes will have the
 # numbers 258 and 259. This is because when a filesystem is mounted,
 # btrfs sets the subvolume's inode counter to a value corresponding to
 # the highest inode number in the subvolume plus 1. This inode counter
 # is used to assign a unique number to each new inode and it's
 # incremented by 1 after very inode creation.
 # Note: we unmount and then mount instead of doing a mount with
 # "-o remount" because otherwise the inode counter remains at value 260.
 $ umount /mnt
 $ mount /dev/sdb /mnt
 $ touch /mnt/file258
 $ mkdir /mnt/new_dir259
 $ mv /mnt/dir257 /mnt/new_dir259/dir257
 $ btrfs subvolume snapshot -r /mnt /mnt/snap2

 $ btrfs send /mnt/snap1 -f /tmp/1.snap
 $ btrfs send -p /mnt/snap1 /mnt/snap2 -f /tmp/2.snap

 $ umount /mnt
 $ mkfs.btrfs -f /dev/sdc
 $ mount /dev/sdc /mnt
 $ btrfs receive /mnt -f /tmo/1.snap
 $ btrfs receive /mnt -f /tmo/2.snap -vv
 receiving snapshot mysnap2 uuid=e059b6d1-7f55-f140-8d7c-9a3039d23c97, ctransid=10 parent_uuid=77e98cb6-8762-814f-9e05-e8ba877fc0b0, parent_ctransid=7
 utimes
 mkdir o259-10-0
 rename dir258 -> o258-7-0
 utimes
 mkfile o258-10-0
 rename o258-10-0 -> file258
 utimes
 truncate o258-10-0 size=0
 ERROR: truncate o258-10-0 failed: No such file or directory

Reported-by: Robbie Ko <robbieko@synology.com>
Signed-off-by: Filipe Manana <fdmanana@suse.com>
2017-02-24 00:36:33 +00:00
..
tests Merge branch 'for-linus-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs 2016-12-16 10:53:01 -08:00
acl.c posix_acl: Clear SGID bit when setting file permissions 2016-09-22 10:55:32 +02:00
async-thread.c btrfs: fix crash when tracepoint arguments are freed by wq callbacks 2017-01-09 11:24:50 +01:00
async-thread.h btrfs: limit async_work allocation and worker func duration 2016-12-13 11:01:30 -08:00
backref.c btrfs: remove unused parameter from __add_inline_refs 2017-02-17 12:03:54 +01:00
backref.h
btrfs_inode.h btrfs: Better csum error message for data csum mismatch 2017-02-17 12:03:48 +01:00
check-integrity.c btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
check-integrity.h btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
compression.c btrfs: Better csum error message for data csum mismatch 2017-02-17 12:03:48 +01:00
compression.h btrfs: use bio iterators for the decompression handlers 2016-11-30 13:45:19 +01:00
ctree.c btrfs: remove unused parameter from tree_move_next_or_upnext 2017-02-17 12:03:52 +01:00
ctree.h btrfs: use btrfs_debug instead of pr_debug in transaction abort 2017-02-17 12:03:56 +01:00
dedupe.h btrfs: expand cow_file_range() to support in-band dedup and subpage-blocksize 2016-07-26 13:52:25 +02:00
delayed-inode.c btrfs: fix over-80 lines introduced by previous cleanups 2017-02-14 15:50:57 +01:00
delayed-inode.h btrfs: Make btrfs_inode_delayed_dir_index_count take btrfs_inode 2017-02-14 15:50:53 +01:00
delayed-ref.c btrfs: qgroup: Move half of the qgroup accounting time out of commit trans 2017-02-17 12:03:55 +01:00
delayed-ref.h Btrfs: pass delayed_refs directly to btrfs_find_delayed_ref_head 2017-02-14 15:50:59 +01:00
dev-replace.c btrfs: remove root parameter from transaction commit/end routines 2016-12-06 16:07:00 +01:00
dev-replace.h btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
dir-item.c btrfs: fix over-80 lines introduced by previous cleanups 2017-02-14 15:50:57 +01:00
disk-io.c btrfs: remove unused parameter from btrfs_check_super_valid 2017-02-17 12:03:52 +01:00
disk-io.h btrfs: merge two superblock writing helpers 2017-02-17 12:03:51 +01:00
export.c btrfs: Make btrfs_ino take a struct btrfs_inode 2017-02-14 15:50:51 +01:00
export.h
extent_io.c btrfs: remove unused parameter from extent_write_cache_pages 2017-02-17 12:03:53 +01:00
extent_io.h btrfs: embed extent_changeset::range_changed to the structure 2017-02-17 12:03:49 +01:00
extent_map.c btrfs: Fix slab accounting flags 2016-07-26 13:52:25 +02:00
extent_map.h btrfs: cleanup, stop casting for extent_map->lookup everywhere 2016-01-15 19:22:28 +01:00
extent-tree.c btrfs: free-space-cache, clean up unnecessary root arguments 2017-02-17 12:03:56 +01:00
file-item.c btrfs: Make btrfs_ino take a struct btrfs_inode 2017-02-14 15:50:51 +01:00
file.c btrfs: fix over-80 lines introduced by previous cleanups 2017-02-14 15:50:57 +01:00
free-space-cache.c btrfs: btrfs_truncate_free_space_cache always allocates path 2017-02-17 12:03:56 +01:00
free-space-cache.h btrfs: free-space-cache, clean up unnecessary root arguments 2017-02-17 12:03:56 +01:00
free-space-tree.c btrfs: remove unused parameter from clean_tree_block 2017-02-17 12:03:51 +01:00
free-space-tree.h Btrfs: implement the free space B-tree 2015-12-17 12:16:47 -08:00
hash.c btrfs: advertise which crc32c implementation is being used at module load 2016-06-06 14:08:28 +02:00
hash.h btrfs: advertise which crc32c implementation is being used at module load 2016-06-06 14:08:28 +02:00
inode-item.c btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
inode-map.c btrfs: free-space-cache, clean up unnecessary root arguments 2017-02-17 12:03:56 +01:00
inode-map.h Btrfs: Initialize btrfs_root->highest_objectid when loading tree root and subvolume roots 2016-01-15 19:25:02 +01:00
inode.c Btrfs: use the correct type when creating cow dio extent 2017-02-22 15:55:03 -08:00
ioctl.c Btrfs: fix deadlock between dedup on same file and starting writeback 2017-02-22 15:55:02 -08:00
Kconfig
locking.c btrfs: cleanup, remove stray return statements 2016-01-07 14:30:52 +01:00
locking.h
lzo.c btrfs: use bio iterators for the decompression handlers 2016-11-30 13:45:19 +01:00
Makefile Btrfs: add free space tree sanity tests 2015-12-17 12:16:47 -08:00
math.h
ordered-data.c Btrfs: clean up btrfs_ordered_update_i_size 2017-02-14 15:50:58 +01:00
ordered-data.h Btrfs: specify a new ordered extent type for create_io_em 2017-02-17 12:03:48 +01:00
orphan.c
print-tree.c btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
print-tree.h btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
props.c btrfs: Make btrfs_ino take a struct btrfs_inode 2017-02-14 15:50:51 +01:00
props.h
qgroup.c btrfs: qgroup: Move half of the qgroup accounting time out of commit trans 2017-02-17 12:03:55 +01:00
qgroup.h btrfs: qgroup: Move half of the qgroup accounting time out of commit trans 2017-02-17 12:03:55 +01:00
raid56.c btrfs: raid56: Remove unused variable in lock_stripe_add 2017-02-14 15:50:59 +01:00
raid56.h btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
rcu-string.h
reada.c btrfs: take an fs_info directly when the root is not used otherwise 2016-12-06 16:06:59 +01:00
relocation.c btrfs: free-space-cache, clean up unnecessary root arguments 2017-02-17 12:03:56 +01:00
root-tree.c Btrfs: constify struct btrfs_{,disk_}key wherever possible 2017-02-14 15:50:58 +01:00
scrub.c btrfs: convert btrfs_inc_block_group_ro to accept fs_info 2017-02-17 12:03:56 +01:00
send.c Btrfs: incremental send, do not delay rename when parent inode is new 2017-02-24 00:36:33 +00:00
send.h Btrfs: use linux/sizes.h to represent constants 2016-01-07 14:38:02 +01:00
struct-funcs.c btrfs: fix string and comment grammatical issues and typos 2016-05-25 22:35:14 +02:00
super.c btrfs: remove unused parameter from btrfs_fill_super 2017-02-17 12:03:53 +01:00
sysfs.c btrfs: convert printk(KERN_* to use pr_* calls 2016-09-26 18:08:44 +02:00
sysfs.h btrfs: sysfs: introduce helper for syncing bits with sysfs files 2016-01-21 18:50:40 +01:00
transaction.c btrfs: remove unused parameter from btrfs_prepare_extent_commit 2017-02-17 12:03:52 +01:00
transaction.h btrfs: remove root parameter from transaction commit/end routines 2016-12-06 16:07:00 +01:00
tree-defrag.c Btrfs: fix locking bugs when defragging leaves 2015-12-18 02:51:32 +00:00
tree-log.c btrfs: remove unused parameter from __add_inode_ref 2017-02-17 12:03:54 +01:00
tree-log.h btrfs: Make btrfs_del_inode_ref take btrfs_inode 2017-02-14 15:50:54 +01:00
ulist.c btrfs: ulist: rename ulist_fini to ulist_release 2017-02-17 12:03:50 +01:00
ulist.h btrfs: ulist: rename ulist_fini to ulist_release 2017-02-17 12:03:50 +01:00
uuid-tree.c btrfs: return the actual error value from from btrfs_uuid_tree_iterate 2016-12-19 18:08:15 +01:00
volumes.c btrfs: remove unused parameter from init_first_rw_device 2017-02-17 12:03:54 +01:00
volumes.h Merge branch 'for-linus-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux-btrfs 2016-12-16 10:53:01 -08:00
xattr.c btrfs: fix over-80 lines introduced by previous cleanups 2017-02-14 15:50:57 +01:00
xattr.h btrfs: Switch to generic xattr handlers 2016-05-17 19:17:09 -04:00
zlib.c btrfs: use bio iterators for the decompression handlers 2016-11-30 13:45:19 +01:00