@@ -1681,6 +1681,9 @@ static int is_inode_existent(struct send_ctx *sctx, u64 ino, u64 gen)
16811681{
16821682 int ret ;
16831683
1684+ if (ino == BTRFS_FIRST_FREE_OBJECTID )
1685+ return 1 ;
1686+
16841687 ret = get_cur_inode_state (sctx , ino , gen );
16851688 if (ret < 0 )
16861689 goto out ;
@@ -1866,7 +1869,7 @@ static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen,
18661869 * not deleted and then re-created, if it was then we have no overwrite
18671870 * and we can just unlink this entry.
18681871 */
1869- if (sctx -> parent_root ) {
1872+ if (sctx -> parent_root && dir != BTRFS_FIRST_FREE_OBJECTID ) {
18701873 ret = get_inode_info (sctx -> parent_root , dir , NULL , & gen , NULL ,
18711874 NULL , NULL , NULL );
18721875 if (ret < 0 && ret != - ENOENT )
@@ -1934,6 +1937,19 @@ static int did_overwrite_ref(struct send_ctx *sctx,
19341937 if (ret <= 0 )
19351938 goto out ;
19361939
1940+ if (dir != BTRFS_FIRST_FREE_OBJECTID ) {
1941+ ret = get_inode_info (sctx -> send_root , dir , NULL , & gen , NULL ,
1942+ NULL , NULL , NULL );
1943+ if (ret < 0 && ret != - ENOENT )
1944+ goto out ;
1945+ if (ret ) {
1946+ ret = 0 ;
1947+ goto out ;
1948+ }
1949+ if (gen != dir_gen )
1950+ goto out ;
1951+ }
1952+
19371953 /* check if the ref was overwritten by another ref */
19381954 ret = lookup_dir_item_inode (sctx -> send_root , dir , name , name_len ,
19391955 & ow_inode , & other_type );
@@ -3556,6 +3572,7 @@ static int wait_for_parent_move(struct send_ctx *sctx,
35563572{
35573573 int ret = 0 ;
35583574 u64 ino = parent_ref -> dir ;
3575+ u64 ino_gen = parent_ref -> dir_gen ;
35593576 u64 parent_ino_before , parent_ino_after ;
35603577 struct fs_path * path_before = NULL ;
35613578 struct fs_path * path_after = NULL ;
@@ -3576,6 +3593,8 @@ static int wait_for_parent_move(struct send_ctx *sctx,
35763593 * at get_cur_path()).
35773594 */
35783595 while (ino > BTRFS_FIRST_FREE_OBJECTID ) {
3596+ u64 parent_ino_after_gen ;
3597+
35793598 if (is_waiting_for_move (sctx , ino )) {
35803599 /*
35813600 * If the current inode is an ancestor of ino in the
@@ -3598,7 +3617,7 @@ static int wait_for_parent_move(struct send_ctx *sctx,
35983617 fs_path_reset (path_after );
35993618
36003619 ret = get_first_ref (sctx -> send_root , ino , & parent_ino_after ,
3601- NULL , path_after );
3620+ & parent_ino_after_gen , path_after );
36023621 if (ret < 0 )
36033622 goto out ;
36043623 ret = get_first_ref (sctx -> parent_root , ino , & parent_ino_before ,
@@ -3615,10 +3634,20 @@ static int wait_for_parent_move(struct send_ctx *sctx,
36153634 if (ino > sctx -> cur_ino &&
36163635 (parent_ino_before != parent_ino_after || len1 != len2 ||
36173636 memcmp (path_before -> start , path_after -> start , len1 ))) {
3618- ret = 1 ;
3619- break ;
3637+ u64 parent_ino_gen ;
3638+
3639+ ret = get_inode_info (sctx -> parent_root , ino , NULL ,
3640+ & parent_ino_gen , NULL , NULL , NULL ,
3641+ NULL );
3642+ if (ret < 0 )
3643+ goto out ;
3644+ if (ino_gen == parent_ino_gen ) {
3645+ ret = 1 ;
3646+ break ;
3647+ }
36203648 }
36213649 ino = parent_ino_after ;
3650+ ino_gen = parent_ino_after_gen ;
36223651 }
36233652
36243653out :
@@ -5277,6 +5306,81 @@ static int get_last_extent(struct send_ctx *sctx, u64 offset)
52775306 return ret ;
52785307}
52795308
5309+ static int range_is_hole_in_parent (struct send_ctx * sctx ,
5310+ const u64 start ,
5311+ const u64 end )
5312+ {
5313+ struct btrfs_path * path ;
5314+ struct btrfs_key key ;
5315+ struct btrfs_root * root = sctx -> parent_root ;
5316+ u64 search_start = start ;
5317+ int ret ;
5318+
5319+ path = alloc_path_for_send ();
5320+ if (!path )
5321+ return - ENOMEM ;
5322+
5323+ key .objectid = sctx -> cur_ino ;
5324+ key .type = BTRFS_EXTENT_DATA_KEY ;
5325+ key .offset = search_start ;
5326+ ret = btrfs_search_slot (NULL , root , & key , path , 0 , 0 );
5327+ if (ret < 0 )
5328+ goto out ;
5329+ if (ret > 0 && path -> slots [0 ] > 0 )
5330+ path -> slots [0 ]-- ;
5331+
5332+ while (search_start < end ) {
5333+ struct extent_buffer * leaf = path -> nodes [0 ];
5334+ int slot = path -> slots [0 ];
5335+ struct btrfs_file_extent_item * fi ;
5336+ u64 extent_end ;
5337+
5338+ if (slot >= btrfs_header_nritems (leaf )) {
5339+ ret = btrfs_next_leaf (root , path );
5340+ if (ret < 0 )
5341+ goto out ;
5342+ else if (ret > 0 )
5343+ break ;
5344+ continue ;
5345+ }
5346+
5347+ btrfs_item_key_to_cpu (leaf , & key , slot );
5348+ if (key .objectid < sctx -> cur_ino ||
5349+ key .type < BTRFS_EXTENT_DATA_KEY )
5350+ goto next ;
5351+ if (key .objectid > sctx -> cur_ino ||
5352+ key .type > BTRFS_EXTENT_DATA_KEY ||
5353+ key .offset >= end )
5354+ break ;
5355+
5356+ fi = btrfs_item_ptr (leaf , slot , struct btrfs_file_extent_item );
5357+ if (btrfs_file_extent_type (leaf , fi ) ==
5358+ BTRFS_FILE_EXTENT_INLINE ) {
5359+ u64 size = btrfs_file_extent_inline_len (leaf , slot , fi );
5360+
5361+ extent_end = ALIGN (key .offset + size ,
5362+ root -> fs_info -> sectorsize );
5363+ } else {
5364+ extent_end = key .offset +
5365+ btrfs_file_extent_num_bytes (leaf , fi );
5366+ }
5367+ if (extent_end <= start )
5368+ goto next ;
5369+ if (btrfs_file_extent_disk_bytenr (leaf , fi ) == 0 ) {
5370+ search_start = extent_end ;
5371+ goto next ;
5372+ }
5373+ ret = 0 ;
5374+ goto out ;
5375+ next :
5376+ path -> slots [0 ]++ ;
5377+ }
5378+ ret = 1 ;
5379+ out :
5380+ btrfs_free_path (path );
5381+ return ret ;
5382+ }
5383+
52805384static int maybe_send_hole (struct send_ctx * sctx , struct btrfs_path * path ,
52815385 struct btrfs_key * key )
52825386{
@@ -5321,8 +5425,17 @@ static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
53215425 return ret ;
53225426 }
53235427
5324- if (sctx -> cur_inode_last_extent < key -> offset )
5325- ret = send_hole (sctx , key -> offset );
5428+ if (sctx -> cur_inode_last_extent < key -> offset ) {
5429+ ret = range_is_hole_in_parent (sctx ,
5430+ sctx -> cur_inode_last_extent ,
5431+ key -> offset );
5432+ if (ret < 0 )
5433+ return ret ;
5434+ else if (ret == 0 )
5435+ ret = send_hole (sctx , key -> offset );
5436+ else
5437+ ret = 0 ;
5438+ }
53265439 sctx -> cur_inode_last_extent = extent_end ;
53275440 return ret ;
53285441}
0 commit comments