2020#include "subvolume.h"
2121#include "trace.h"
2222
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+
2393static void trace_move_extent_finish2 (struct bch_fs * c , struct bkey_s_c k )
2494{
2595 if (trace_move_extent_finish_enabled ()) {
@@ -355,17 +425,11 @@ void bch2_data_update_read_done(struct data_update *m,
355425void bch2_data_update_exit (struct data_update * update )
356426{
357427 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 );
368429
430+ if (c -> opts .nocow_enabled )
431+ bkey_nocow_unlock (c , k );
432+ bkey_put_dev_refs (c , k );
369433 bch2_bkey_buf_exit (& update -> k , c );
370434 bch2_disk_reservation_put (c , & update -> op .res );
371435 bch2_bio_free_pages_pool (c , & update -> op .wbio .bio );
@@ -546,7 +610,6 @@ int bch2_data_update_init(struct btree_trans *trans,
546610 const union bch_extent_entry * entry ;
547611 struct extent_ptr_decoded p ;
548612 unsigned i , reserve_sectors = k .k -> size * data_opts .extra_replicas ;
549- unsigned ptrs_locked = 0 ;
550613 int ret = 0 ;
551614
552615 /*
@@ -557,6 +620,15 @@ int bch2_data_update_init(struct btree_trans *trans,
557620 if (unlikely (k .k -> p .snapshot && !bch2_snapshot_equiv (c , k .k -> p .snapshot )))
558621 return - BCH_ERR_data_update_done ;
559622
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+
560632 bch2_bkey_buf_init (& m -> k );
561633 bch2_bkey_buf_reassemble (& m -> k , c , k );
562634 m -> btree_id = btree_id ;
@@ -578,40 +650,24 @@ int bch2_data_update_init(struct btree_trans *trans,
578650 m -> op .compression_opt = background_compression (io_opts );
579651 m -> op .watermark = m -> data_opts .btree_insert_flags & BCH_WATERMARK_MASK ;
580652
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-
592653 unsigned durability_have = 0 , durability_removing = 0 ;
593654
594655 i = 0 ;
595656 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 ();
613670 }
614- rcu_read_unlock ();
615671
616672 /*
617673 * op->csum_type is normally initialized from the fs/file's
@@ -626,24 +682,6 @@ int bch2_data_update_init(struct btree_trans *trans,
626682 if (p .crc .compression_type == BCH_COMPRESSION_TYPE_incompressible )
627683 m -> op .incompressible = true;
628684
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-
647685 i ++ ;
648686 }
649687
@@ -664,7 +702,7 @@ int bch2_data_update_init(struct btree_trans *trans,
664702 /* if iter == NULL, it's just a promote */
665703 if (iter )
666704 ret = bch2_extent_drop_ptrs (trans , iter , k , m -> data_opts );
667- goto done ;
705+ goto out ;
668706 }
669707
670708 m -> op .nr_replicas = min (durability_removing , durability_required ) +
@@ -684,8 +722,7 @@ int bch2_data_update_init(struct btree_trans *trans,
684722 bch2_data_update_to_text (& buf , m );
685723 WARN (1 , "trying to move an extent, but nr_replicas=0\n%s" , buf .buf );
686724 printbuf_exit (& buf );
687- ret = - BCH_ERR_data_update_done ;
688- goto done ;
725+ goto out ;
689726 }
690727
691728 m -> op .nr_replicas_required = m -> op .nr_replicas ;
@@ -696,30 +733,16 @@ int bch2_data_update_init(struct btree_trans *trans,
696733 ? 0
697734 : BCH_DISK_RESERVATION_NOFAIL );
698735 if (ret )
699- goto err ;
736+ goto out ;
700737 }
701738
702739 if (bkey_extent_is_unwritten (k )) {
703740 bch2_update_unwritten_extent (trans , m );
704- goto done ;
741+ goto out ;
705742 }
706743
707744 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 :
723746 bch2_data_update_exit (m );
724747 return ret ?: - BCH_ERR_data_update_done ;
725748}
0 commit comments