@@ -347,33 +347,10 @@ static int add_prelim_ref(const struct btrfs_fs_info *fs_info,
347347 return - ENOMEM ;
348348
349349 ref -> root_id = root_id ;
350- if (key ) {
350+ if (key )
351351 ref -> key_for_search = * key ;
352- /*
353- * We can often find data backrefs with an offset that is too
354- * large (>= LLONG_MAX, maximum allowed file offset) due to
355- * underflows when subtracting a file's offset with the data
356- * offset of its corresponding extent data item. This can
357- * happen for example in the clone ioctl.
358- * So if we detect such case we set the search key's offset to
359- * zero to make sure we will find the matching file extent item
360- * at add_all_parents(), otherwise we will miss it because the
361- * offset taken form the backref is much larger then the offset
362- * of the file extent item. This can make us scan a very large
363- * number of file extent items, but at least it will not make
364- * us miss any.
365- * This is an ugly workaround for a behaviour that should have
366- * never existed, but it does and a fix for the clone ioctl
367- * would touch a lot of places, cause backwards incompatibility
368- * and would not fix the problem for extents cloned with older
369- * kernels.
370- */
371- if (ref -> key_for_search .type == BTRFS_EXTENT_DATA_KEY &&
372- ref -> key_for_search .offset >= LLONG_MAX )
373- ref -> key_for_search .offset = 0 ;
374- } else {
352+ else
375353 memset (& ref -> key_for_search , 0 , sizeof (ref -> key_for_search ));
376- }
377354
378355 ref -> inode_list = NULL ;
379356 ref -> level = level ;
@@ -424,6 +401,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
424401 u64 disk_byte ;
425402 u64 wanted_disk_byte = ref -> wanted_disk_byte ;
426403 u64 count = 0 ;
404+ u64 data_offset ;
427405
428406 if (level != 0 ) {
429407 eb = path -> nodes [level ];
@@ -457,11 +435,15 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
457435
458436 fi = btrfs_item_ptr (eb , slot , struct btrfs_file_extent_item );
459437 disk_byte = btrfs_file_extent_disk_bytenr (eb , fi );
438+ data_offset = btrfs_file_extent_offset (eb , fi );
460439
461440 if (disk_byte == wanted_disk_byte ) {
462441 eie = NULL ;
463442 old = NULL ;
464- count ++ ;
443+ if (ref -> key_for_search .offset == key .offset - data_offset )
444+ count ++ ;
445+ else
446+ goto next ;
465447 if (extent_item_pos ) {
466448 ret = check_extent_in_eb (& key , eb , fi ,
467449 * extent_item_pos ,
@@ -513,6 +495,7 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
513495 int root_level ;
514496 int level = ref -> level ;
515497 int index ;
498+ struct btrfs_key search_key = ref -> key_for_search ;
516499
517500 root_key .objectid = ref -> root_id ;
518501 root_key .type = BTRFS_ROOT_ITEM_KEY ;
@@ -545,13 +528,33 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
545528 goto out ;
546529 }
547530
531+ /*
532+ * We can often find data backrefs with an offset that is too large
533+ * (>= LLONG_MAX, maximum allowed file offset) due to underflows when
534+ * subtracting a file's offset with the data offset of its
535+ * corresponding extent data item. This can happen for example in the
536+ * clone ioctl.
537+ *
538+ * So if we detect such case we set the search key's offset to zero to
539+ * make sure we will find the matching file extent item at
540+ * add_all_parents(), otherwise we will miss it because the offset
541+ * taken form the backref is much larger then the offset of the file
542+ * extent item. This can make us scan a very large number of file
543+ * extent items, but at least it will not make us miss any.
544+ *
545+ * This is an ugly workaround for a behaviour that should have never
546+ * existed, but it does and a fix for the clone ioctl would touch a lot
547+ * of places, cause backwards incompatibility and would not fix the
548+ * problem for extents cloned with older kernels.
549+ */
550+ if (search_key .type == BTRFS_EXTENT_DATA_KEY &&
551+ search_key .offset >= LLONG_MAX )
552+ search_key .offset = 0 ;
548553 path -> lowest_level = level ;
549554 if (time_seq == SEQ_LAST )
550- ret = btrfs_search_slot (NULL , root , & ref -> key_for_search , path ,
551- 0 , 0 );
555+ ret = btrfs_search_slot (NULL , root , & search_key , path , 0 , 0 );
552556 else
553- ret = btrfs_search_old_slot (root , & ref -> key_for_search , path ,
554- time_seq );
557+ ret = btrfs_search_old_slot (root , & search_key , path , time_seq );
555558
556559 /* root node has been locked, we can release @subvol_srcu safely here */
557560 srcu_read_unlock (& fs_info -> subvol_srcu , index );
0 commit comments