@@ -347,33 +347,10 @@ static int add_prelim_ref(const struct btrfs_fs_info *fs_info,
347
347
return - ENOMEM ;
348
348
349
349
ref -> root_id = root_id ;
350
- if (key ) {
350
+ if (key )
351
351
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
375
353
memset (& ref -> key_for_search , 0 , sizeof (ref -> key_for_search ));
376
- }
377
354
378
355
ref -> inode_list = NULL ;
379
356
ref -> level = level ;
@@ -409,10 +386,36 @@ static int add_indirect_ref(const struct btrfs_fs_info *fs_info,
409
386
wanted_disk_byte , count , sc , gfp_mask );
410
387
}
411
388
389
+ static int is_shared_data_backref (struct preftrees * preftrees , u64 bytenr )
390
+ {
391
+ struct rb_node * * p = & preftrees -> direct .root .rb_root .rb_node ;
392
+ struct rb_node * parent = NULL ;
393
+ struct prelim_ref * ref = NULL ;
394
+ struct prelim_ref target = {0 };
395
+ int result ;
396
+
397
+ target .parent = bytenr ;
398
+
399
+ while (* p ) {
400
+ parent = * p ;
401
+ ref = rb_entry (parent , struct prelim_ref , rbnode );
402
+ result = prelim_ref_compare (ref , & target );
403
+
404
+ if (result < 0 )
405
+ p = & (* p )-> rb_left ;
406
+ else if (result > 0 )
407
+ p = & (* p )-> rb_right ;
408
+ else
409
+ return 1 ;
410
+ }
411
+ return 0 ;
412
+ }
413
+
412
414
static int add_all_parents (struct btrfs_root * root , struct btrfs_path * path ,
413
- struct ulist * parents , struct prelim_ref * ref ,
415
+ struct ulist * parents ,
416
+ struct preftrees * preftrees , struct prelim_ref * ref ,
414
417
int level , u64 time_seq , const u64 * extent_item_pos ,
415
- u64 total_refs , bool ignore_offset )
418
+ bool ignore_offset )
416
419
{
417
420
int ret = 0 ;
418
421
int slot ;
@@ -424,6 +427,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
424
427
u64 disk_byte ;
425
428
u64 wanted_disk_byte = ref -> wanted_disk_byte ;
426
429
u64 count = 0 ;
430
+ u64 data_offset ;
427
431
428
432
if (level != 0 ) {
429
433
eb = path -> nodes [level ];
@@ -434,18 +438,26 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
434
438
}
435
439
436
440
/*
437
- * We normally enter this function with the path already pointing to
438
- * the first item to check. But sometimes, we may enter it with
439
- * slot==nritems. In that case, go to the next leaf before we continue.
441
+ * 1. We normally enter this function with the path already pointing to
442
+ * the first item to check. But sometimes, we may enter it with
443
+ * slot == nritems.
444
+ * 2. We are searching for normal backref but bytenr of this leaf
445
+ * matches shared data backref
446
+ * 3. The leaf owner is not equal to the root we are searching
447
+ *
448
+ * For these cases, go to the next leaf before we continue.
440
449
*/
441
- if (path -> slots [0 ] >= btrfs_header_nritems (path -> nodes [0 ])) {
450
+ eb = path -> nodes [0 ];
451
+ if (path -> slots [0 ] >= btrfs_header_nritems (eb ) ||
452
+ is_shared_data_backref (preftrees , eb -> start ) ||
453
+ ref -> root_id != btrfs_header_owner (eb )) {
442
454
if (time_seq == SEQ_LAST )
443
455
ret = btrfs_next_leaf (root , path );
444
456
else
445
457
ret = btrfs_next_old_leaf (root , path , time_seq );
446
458
}
447
459
448
- while (!ret && count < total_refs ) {
460
+ while (!ret && count < ref -> count ) {
449
461
eb = path -> nodes [0 ];
450
462
slot = path -> slots [0 ];
451
463
@@ -455,13 +467,31 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
455
467
key .type != BTRFS_EXTENT_DATA_KEY )
456
468
break ;
457
469
470
+ /*
471
+ * We are searching for normal backref but bytenr of this leaf
472
+ * matches shared data backref, OR
473
+ * the leaf owner is not equal to the root we are searching for
474
+ */
475
+ if (slot == 0 &&
476
+ (is_shared_data_backref (preftrees , eb -> start ) ||
477
+ ref -> root_id != btrfs_header_owner (eb ))) {
478
+ if (time_seq == SEQ_LAST )
479
+ ret = btrfs_next_leaf (root , path );
480
+ else
481
+ ret = btrfs_next_old_leaf (root , path , time_seq );
482
+ continue ;
483
+ }
458
484
fi = btrfs_item_ptr (eb , slot , struct btrfs_file_extent_item );
459
485
disk_byte = btrfs_file_extent_disk_bytenr (eb , fi );
486
+ data_offset = btrfs_file_extent_offset (eb , fi );
460
487
461
488
if (disk_byte == wanted_disk_byte ) {
462
489
eie = NULL ;
463
490
old = NULL ;
464
- count ++ ;
491
+ if (ref -> key_for_search .offset == key .offset - data_offset )
492
+ count ++ ;
493
+ else
494
+ goto next ;
465
495
if (extent_item_pos ) {
466
496
ret = check_extent_in_eb (& key , eb , fi ,
467
497
* extent_item_pos ,
@@ -502,33 +532,35 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
502
532
*/
503
533
static int resolve_indirect_ref (struct btrfs_fs_info * fs_info ,
504
534
struct btrfs_path * path , u64 time_seq ,
535
+ struct preftrees * preftrees ,
505
536
struct prelim_ref * ref , struct ulist * parents ,
506
- const u64 * extent_item_pos , u64 total_refs ,
507
- bool ignore_offset )
537
+ const u64 * extent_item_pos , bool ignore_offset )
508
538
{
509
539
struct btrfs_root * root ;
510
540
struct btrfs_key root_key ;
511
541
struct extent_buffer * eb ;
512
542
int ret = 0 ;
513
543
int root_level ;
514
544
int level = ref -> level ;
515
- int index ;
545
+ struct btrfs_key search_key = ref -> key_for_search ;
516
546
517
547
root_key .objectid = ref -> root_id ;
518
548
root_key .type = BTRFS_ROOT_ITEM_KEY ;
519
549
root_key .offset = (u64 )- 1 ;
520
550
521
- index = srcu_read_lock (& fs_info -> subvol_srcu );
522
-
523
551
root = btrfs_get_fs_root (fs_info , & root_key , false);
524
552
if (IS_ERR (root )) {
525
- srcu_read_unlock (& fs_info -> subvol_srcu , index );
526
553
ret = PTR_ERR (root );
554
+ goto out_free ;
555
+ }
556
+
557
+ if (!path -> search_commit_root &&
558
+ test_bit (BTRFS_ROOT_DELETING , & root -> state )) {
559
+ ret = - ENOENT ;
527
560
goto out ;
528
561
}
529
562
530
563
if (btrfs_is_testing (fs_info )) {
531
- srcu_read_unlock (& fs_info -> subvol_srcu , index );
532
564
ret = - ENOENT ;
533
565
goto out ;
534
566
}
@@ -540,21 +572,36 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
540
572
else
541
573
root_level = btrfs_old_root_level (root , time_seq );
542
574
543
- if (root_level + 1 == level ) {
544
- srcu_read_unlock (& fs_info -> subvol_srcu , index );
575
+ if (root_level + 1 == level )
545
576
goto out ;
546
- }
547
577
578
+ /*
579
+ * We can often find data backrefs with an offset that is too large
580
+ * (>= LLONG_MAX, maximum allowed file offset) due to underflows when
581
+ * subtracting a file's offset with the data offset of its
582
+ * corresponding extent data item. This can happen for example in the
583
+ * clone ioctl.
584
+ *
585
+ * So if we detect such case we set the search key's offset to zero to
586
+ * make sure we will find the matching file extent item at
587
+ * add_all_parents(), otherwise we will miss it because the offset
588
+ * taken form the backref is much larger then the offset of the file
589
+ * extent item. This can make us scan a very large number of file
590
+ * extent items, but at least it will not make us miss any.
591
+ *
592
+ * This is an ugly workaround for a behaviour that should have never
593
+ * existed, but it does and a fix for the clone ioctl would touch a lot
594
+ * of places, cause backwards incompatibility and would not fix the
595
+ * problem for extents cloned with older kernels.
596
+ */
597
+ if (search_key .type == BTRFS_EXTENT_DATA_KEY &&
598
+ search_key .offset >= LLONG_MAX )
599
+ search_key .offset = 0 ;
548
600
path -> lowest_level = level ;
549
601
if (time_seq == SEQ_LAST )
550
- ret = btrfs_search_slot (NULL , root , & ref -> key_for_search , path ,
551
- 0 , 0 );
602
+ ret = btrfs_search_slot (NULL , root , & search_key , path , 0 , 0 );
552
603
else
553
- ret = btrfs_search_old_slot (root , & ref -> key_for_search , path ,
554
- time_seq );
555
-
556
- /* root node has been locked, we can release @subvol_srcu safely here */
557
- srcu_read_unlock (& fs_info -> subvol_srcu , index );
604
+ ret = btrfs_search_old_slot (root , & search_key , path , time_seq );
558
605
559
606
btrfs_debug (fs_info ,
560
607
"search slot in root %llu (level %d, ref count %d) returned %d for key (%llu %u %llu)" ,
@@ -574,9 +621,11 @@ static int resolve_indirect_ref(struct btrfs_fs_info *fs_info,
574
621
eb = path -> nodes [level ];
575
622
}
576
623
577
- ret = add_all_parents (root , path , parents , ref , level , time_seq ,
578
- extent_item_pos , total_refs , ignore_offset );
624
+ ret = add_all_parents (root , path , parents , preftrees , ref , level ,
625
+ time_seq , extent_item_pos , ignore_offset );
579
626
out :
627
+ btrfs_put_root (root );
628
+ out_free :
580
629
path -> lowest_level = 0 ;
581
630
btrfs_release_path (path );
582
631
return ret ;
@@ -609,7 +658,7 @@ unode_aux_to_inode_list(struct ulist_node *node)
609
658
static int resolve_indirect_refs (struct btrfs_fs_info * fs_info ,
610
659
struct btrfs_path * path , u64 time_seq ,
611
660
struct preftrees * preftrees ,
612
- const u64 * extent_item_pos , u64 total_refs ,
661
+ const u64 * extent_item_pos ,
613
662
struct share_check * sc , bool ignore_offset )
614
663
{
615
664
int err ;
@@ -653,9 +702,9 @@ static int resolve_indirect_refs(struct btrfs_fs_info *fs_info,
653
702
ret = BACKREF_FOUND_SHARED ;
654
703
goto out ;
655
704
}
656
- err = resolve_indirect_ref (fs_info , path , time_seq , ref ,
657
- parents , extent_item_pos ,
658
- total_refs , ignore_offset );
705
+ err = resolve_indirect_ref (fs_info , path , time_seq , preftrees ,
706
+ ref , parents , extent_item_pos ,
707
+ ignore_offset );
659
708
/*
660
709
* we can only tolerate ENOENT,otherwise,we should catch error
661
710
* and return directly.
@@ -758,8 +807,7 @@ static int add_missing_keys(struct btrfs_fs_info *fs_info,
758
807
*/
759
808
static int add_delayed_refs (const struct btrfs_fs_info * fs_info ,
760
809
struct btrfs_delayed_ref_head * head , u64 seq ,
761
- struct preftrees * preftrees , u64 * total_refs ,
762
- struct share_check * sc )
810
+ struct preftrees * preftrees , struct share_check * sc )
763
811
{
764
812
struct btrfs_delayed_ref_node * node ;
765
813
struct btrfs_delayed_extent_op * extent_op = head -> extent_op ;
@@ -793,7 +841,6 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
793
841
default :
794
842
BUG ();
795
843
}
796
- * total_refs += count ;
797
844
switch (node -> type ) {
798
845
case BTRFS_TREE_BLOCK_REF_KEY : {
799
846
/* NORMAL INDIRECT METADATA backref */
@@ -876,7 +923,7 @@ static int add_delayed_refs(const struct btrfs_fs_info *fs_info,
876
923
static int add_inline_refs (const struct btrfs_fs_info * fs_info ,
877
924
struct btrfs_path * path , u64 bytenr ,
878
925
int * info_level , struct preftrees * preftrees ,
879
- u64 * total_refs , struct share_check * sc )
926
+ struct share_check * sc )
880
927
{
881
928
int ret = 0 ;
882
929
int slot ;
@@ -900,7 +947,6 @@ static int add_inline_refs(const struct btrfs_fs_info *fs_info,
900
947
901
948
ei = btrfs_item_ptr (leaf , slot , struct btrfs_extent_item );
902
949
flags = btrfs_extent_flags (leaf , ei );
903
- * total_refs += btrfs_extent_refs (leaf , ei );
904
950
btrfs_item_key_to_cpu (leaf , & found_key , slot );
905
951
906
952
ptr = (unsigned long )(ei + 1 );
@@ -1125,8 +1171,6 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
1125
1171
struct prelim_ref * ref ;
1126
1172
struct rb_node * node ;
1127
1173
struct extent_inode_elem * eie = NULL ;
1128
- /* total of both direct AND indirect refs! */
1129
- u64 total_refs = 0 ;
1130
1174
struct preftrees preftrees = {
1131
1175
.direct = PREFTREE_INIT ,
1132
1176
.indirect = PREFTREE_INIT ,
@@ -1195,7 +1239,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
1195
1239
}
1196
1240
spin_unlock (& delayed_refs -> lock );
1197
1241
ret = add_delayed_refs (fs_info , head , time_seq ,
1198
- & preftrees , & total_refs , sc );
1242
+ & preftrees , sc );
1199
1243
mutex_unlock (& head -> mutex );
1200
1244
if (ret )
1201
1245
goto out ;
@@ -1216,8 +1260,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
1216
1260
(key .type == BTRFS_EXTENT_ITEM_KEY ||
1217
1261
key .type == BTRFS_METADATA_ITEM_KEY )) {
1218
1262
ret = add_inline_refs (fs_info , path , bytenr ,
1219
- & info_level , & preftrees ,
1220
- & total_refs , sc );
1263
+ & info_level , & preftrees , sc );
1221
1264
if (ret )
1222
1265
goto out ;
1223
1266
ret = add_keyed_refs (fs_info , path , bytenr , info_level ,
@@ -1236,7 +1279,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
1236
1279
WARN_ON (!RB_EMPTY_ROOT (& preftrees .indirect_missing_keys .root .rb_root ));
1237
1280
1238
1281
ret = resolve_indirect_refs (fs_info , path , time_seq , & preftrees ,
1239
- extent_item_pos , total_refs , sc , ignore_offset );
1282
+ extent_item_pos , sc , ignore_offset );
1240
1283
if (ret )
1241
1284
goto out ;
1242
1285
@@ -1362,10 +1405,10 @@ static void free_leaf_list(struct ulist *blocks)
1362
1405
*
1363
1406
* returns 0 on success, <0 on error
1364
1407
*/
1365
- static int btrfs_find_all_leafs (struct btrfs_trans_handle * trans ,
1366
- struct btrfs_fs_info * fs_info , u64 bytenr ,
1367
- u64 time_seq , struct ulist * * leafs ,
1368
- const u64 * extent_item_pos , bool ignore_offset )
1408
+ int btrfs_find_all_leafs (struct btrfs_trans_handle * trans ,
1409
+ struct btrfs_fs_info * fs_info , u64 bytenr ,
1410
+ u64 time_seq , struct ulist * * leafs ,
1411
+ const u64 * extent_item_pos , bool ignore_offset )
1369
1412
{
1370
1413
int ret ;
1371
1414
0 commit comments