20
20
#include "subvolume.h"
21
21
#include "trace.h"
22
22
23
+ static void bkey_put_dev_refs (struct bch_fs * c , struct bkey_s_c k )
24
+ {
25
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c (k );
26
+
27
+ bkey_for_each_ptr (ptrs , ptr )
28
+ bch2_dev_put (bch2_dev_have_ref (c , ptr -> dev ));
29
+ }
30
+
31
+ static bool bkey_get_dev_refs (struct bch_fs * c , struct bkey_s_c k )
32
+ {
33
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c (k );
34
+
35
+ bkey_for_each_ptr (ptrs , ptr ) {
36
+ if (!bch2_dev_tryget (c , ptr -> dev )) {
37
+ bkey_for_each_ptr (ptrs , ptr2 ) {
38
+ if (ptr2 == ptr )
39
+ break ;
40
+ bch2_dev_put (bch2_dev_have_ref (c , ptr2 -> dev ));
41
+ }
42
+ return false;
43
+ }
44
+ }
45
+ return true;
46
+ }
47
+
48
+ static void bkey_nocow_unlock (struct bch_fs * c , struct bkey_s_c k )
49
+ {
50
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c (k );
51
+
52
+ bkey_for_each_ptr (ptrs , ptr ) {
53
+ struct bch_dev * ca = bch2_dev_have_ref (c , ptr -> dev );
54
+ struct bpos bucket = PTR_BUCKET_POS (ca , ptr );
55
+
56
+ bch2_bucket_nocow_unlock (& c -> nocow_locks , bucket , 0 );
57
+ }
58
+ }
59
+
60
+ static bool bkey_nocow_lock (struct bch_fs * c , struct moving_context * ctxt , struct bkey_s_c k )
61
+ {
62
+ struct bkey_ptrs_c ptrs = bch2_bkey_ptrs_c (k );
63
+
64
+ bkey_for_each_ptr (ptrs , ptr ) {
65
+ struct bch_dev * ca = bch2_dev_have_ref (c , ptr -> dev );
66
+ struct bpos bucket = PTR_BUCKET_POS (ca , ptr );
67
+
68
+ if (ctxt ) {
69
+ bool locked ;
70
+
71
+ move_ctxt_wait_event (ctxt ,
72
+ (locked = bch2_bucket_nocow_trylock (& c -> nocow_locks , bucket , 0 )) ||
73
+ list_empty (& ctxt -> ios ));
74
+
75
+ if (!locked )
76
+ bch2_bucket_nocow_lock (& c -> nocow_locks , bucket , 0 );
77
+ } else {
78
+ if (!bch2_bucket_nocow_trylock (& c -> nocow_locks , bucket , 0 )) {
79
+ bkey_for_each_ptr (ptrs , ptr2 ) {
80
+ if (ptr2 == ptr )
81
+ break ;
82
+
83
+ bucket = PTR_BUCKET_POS (ca , ptr2 );
84
+ bch2_bucket_nocow_unlock (& c -> nocow_locks , bucket , 0 );
85
+ }
86
+ return false;
87
+ }
88
+ }
89
+ }
90
+ return true;
91
+ }
92
+
23
93
static void trace_move_extent_finish2 (struct bch_fs * c , struct bkey_s_c k )
24
94
{
25
95
if (trace_move_extent_finish_enabled ()) {
@@ -355,17 +425,11 @@ void bch2_data_update_read_done(struct data_update *m,
355
425
void bch2_data_update_exit (struct data_update * update )
356
426
{
357
427
struct bch_fs * c = update -> op .c ;
358
- struct bkey_ptrs_c ptrs =
359
- bch2_bkey_ptrs_c (bkey_i_to_s_c (update -> k .k ));
360
-
361
- bkey_for_each_ptr (ptrs , ptr ) {
362
- struct bch_dev * ca = bch2_dev_have_ref (c , ptr -> dev );
363
- if (c -> opts .nocow_enabled )
364
- bch2_bucket_nocow_unlock (& c -> nocow_locks ,
365
- PTR_BUCKET_POS (ca , ptr ), 0 );
366
- bch2_dev_put (ca );
367
- }
428
+ struct bkey_s_c k = bkey_i_to_s_c (update -> k .k );
368
429
430
+ if (c -> opts .nocow_enabled )
431
+ bkey_nocow_unlock (c , k );
432
+ bkey_put_dev_refs (c , k );
369
433
bch2_bkey_buf_exit (& update -> k , c );
370
434
bch2_disk_reservation_put (c , & update -> op .res );
371
435
bch2_bio_free_pages_pool (c , & update -> op .wbio .bio );
@@ -546,7 +610,6 @@ int bch2_data_update_init(struct btree_trans *trans,
546
610
const union bch_extent_entry * entry ;
547
611
struct extent_ptr_decoded p ;
548
612
unsigned i , reserve_sectors = k .k -> size * data_opts .extra_replicas ;
549
- unsigned ptrs_locked = 0 ;
550
613
int ret = 0 ;
551
614
552
615
/*
@@ -557,6 +620,15 @@ int bch2_data_update_init(struct btree_trans *trans,
557
620
if (unlikely (k .k -> p .snapshot && !bch2_snapshot_equiv (c , k .k -> p .snapshot )))
558
621
return - BCH_ERR_data_update_done ;
559
622
623
+ if (!bkey_get_dev_refs (c , k ))
624
+ return - BCH_ERR_data_update_done ;
625
+
626
+ if (c -> opts .nocow_enabled &&
627
+ !bkey_nocow_lock (c , ctxt , k )) {
628
+ bkey_put_dev_refs (c , k );
629
+ return - BCH_ERR_nocow_lock_blocked ;
630
+ }
631
+
560
632
bch2_bkey_buf_init (& m -> k );
561
633
bch2_bkey_buf_reassemble (& m -> k , c , k );
562
634
m -> btree_id = btree_id ;
@@ -578,40 +650,24 @@ int bch2_data_update_init(struct btree_trans *trans,
578
650
m -> op .compression_opt = background_compression (io_opts );
579
651
m -> op .watermark = m -> data_opts .btree_insert_flags & BCH_WATERMARK_MASK ;
580
652
581
- bkey_for_each_ptr (ptrs , ptr ) {
582
- if (!bch2_dev_tryget (c , ptr -> dev )) {
583
- bkey_for_each_ptr (ptrs , ptr2 ) {
584
- if (ptr2 == ptr )
585
- break ;
586
- bch2_dev_put (bch2_dev_have_ref (c , ptr2 -> dev ));
587
- }
588
- return - BCH_ERR_data_update_done ;
589
- }
590
- }
591
-
592
653
unsigned durability_have = 0 , durability_removing = 0 ;
593
654
594
655
i = 0 ;
595
656
bkey_for_each_ptr_decode (k .k , ptrs , p , entry ) {
596
- struct bch_dev * ca = bch2_dev_have_ref (c , p .ptr .dev );
597
- struct bpos bucket = PTR_BUCKET_POS (ca , & p .ptr );
598
- bool locked ;
599
-
600
- rcu_read_lock ();
601
- if (((1U << i ) & m -> data_opts .rewrite_ptrs )) {
602
- BUG_ON (p .ptr .cached );
603
-
604
- if (crc_is_compressed (p .crc ))
605
- reserve_sectors += k .k -> size ;
606
-
607
- m -> op .nr_replicas += bch2_extent_ptr_desired_durability (c , & p );
608
- durability_removing += bch2_extent_ptr_desired_durability (c , & p );
609
- } else if (!p .ptr .cached &&
610
- !((1U << i ) & m -> data_opts .kill_ptrs )) {
611
- bch2_dev_list_add_dev (& m -> op .devs_have , p .ptr .dev );
612
- durability_have += bch2_extent_ptr_durability (c , & p );
657
+ if (!p .ptr .cached ) {
658
+ rcu_read_lock ();
659
+ if (BIT (i ) & m -> data_opts .rewrite_ptrs ) {
660
+ if (crc_is_compressed (p .crc ))
661
+ reserve_sectors += k .k -> size ;
662
+
663
+ m -> op .nr_replicas += bch2_extent_ptr_desired_durability (c , & p );
664
+ durability_removing += bch2_extent_ptr_desired_durability (c , & p );
665
+ } else if (!(BIT (i ) & m -> data_opts .kill_ptrs )) {
666
+ bch2_dev_list_add_dev (& m -> op .devs_have , p .ptr .dev );
667
+ durability_have += bch2_extent_ptr_durability (c , & p );
668
+ }
669
+ rcu_read_unlock ();
613
670
}
614
- rcu_read_unlock ();
615
671
616
672
/*
617
673
* op->csum_type is normally initialized from the fs/file's
@@ -626,24 +682,6 @@ int bch2_data_update_init(struct btree_trans *trans,
626
682
if (p .crc .compression_type == BCH_COMPRESSION_TYPE_incompressible )
627
683
m -> op .incompressible = true;
628
684
629
- if (c -> opts .nocow_enabled ) {
630
- if (ctxt ) {
631
- move_ctxt_wait_event (ctxt ,
632
- (locked = bch2_bucket_nocow_trylock (& c -> nocow_locks ,
633
- bucket , 0 )) ||
634
- list_empty (& ctxt -> ios ));
635
-
636
- if (!locked )
637
- bch2_bucket_nocow_lock (& c -> nocow_locks , bucket , 0 );
638
- } else {
639
- if (!bch2_bucket_nocow_trylock (& c -> nocow_locks , bucket , 0 )) {
640
- ret = - BCH_ERR_nocow_lock_blocked ;
641
- goto err ;
642
- }
643
- }
644
- ptrs_locked |= (1U << i );
645
- }
646
-
647
685
i ++ ;
648
686
}
649
687
@@ -664,7 +702,7 @@ int bch2_data_update_init(struct btree_trans *trans,
664
702
/* if iter == NULL, it's just a promote */
665
703
if (iter )
666
704
ret = bch2_extent_drop_ptrs (trans , iter , k , m -> data_opts );
667
- goto done ;
705
+ goto out ;
668
706
}
669
707
670
708
m -> op .nr_replicas = min (durability_removing , durability_required ) +
@@ -684,8 +722,7 @@ int bch2_data_update_init(struct btree_trans *trans,
684
722
bch2_data_update_to_text (& buf , m );
685
723
WARN (1 , "trying to move an extent, but nr_replicas=0\n%s" , buf .buf );
686
724
printbuf_exit (& buf );
687
- ret = - BCH_ERR_data_update_done ;
688
- goto done ;
725
+ goto out ;
689
726
}
690
727
691
728
m -> op .nr_replicas_required = m -> op .nr_replicas ;
@@ -696,30 +733,16 @@ int bch2_data_update_init(struct btree_trans *trans,
696
733
? 0
697
734
: BCH_DISK_RESERVATION_NOFAIL );
698
735
if (ret )
699
- goto err ;
736
+ goto out ;
700
737
}
701
738
702
739
if (bkey_extent_is_unwritten (k )) {
703
740
bch2_update_unwritten_extent (trans , m );
704
- goto done ;
741
+ goto out ;
705
742
}
706
743
707
744
return 0 ;
708
- err :
709
- i = 0 ;
710
- bkey_for_each_ptr_decode (k .k , ptrs , p , entry ) {
711
- struct bch_dev * ca = bch2_dev_have_ref (c , p .ptr .dev );
712
- struct bpos bucket = PTR_BUCKET_POS (ca , & p .ptr );
713
- if ((1U << i ) & ptrs_locked )
714
- bch2_bucket_nocow_unlock (& c -> nocow_locks , bucket , 0 );
715
- bch2_dev_put (ca );
716
- i ++ ;
717
- }
718
-
719
- bch2_bkey_buf_exit (& m -> k , c );
720
- bch2_bio_free_pages_pool (c , & m -> op .wbio .bio );
721
- return ret ;
722
- done :
745
+ out :
723
746
bch2_data_update_exit (m );
724
747
return ret ?: - BCH_ERR_data_update_done ;
725
748
}
0 commit comments