@@ -114,6 +114,8 @@ struct xfs_gc_bio {
114114 /* Open Zone being written to */
115115 struct xfs_open_zone * oz ;
116116
117+ struct xfs_rtgroup * victim_rtg ;
118+
117119 /* Bio used for reads and writes, including the bvec used by it */
118120 struct bio_vec bv ;
119121 struct bio bio ; /* must be last */
@@ -264,6 +266,7 @@ xfs_zone_gc_iter_init(
264266 iter -> rec_count = 0 ;
265267 iter -> rec_idx = 0 ;
266268 iter -> victim_rtg = victim_rtg ;
269+ atomic_inc (& victim_rtg -> rtg_gccount );
267270}
268271
269272/*
@@ -362,6 +365,7 @@ xfs_zone_gc_query(
362365
363366 return 0 ;
364367done :
368+ atomic_dec (& iter -> victim_rtg -> rtg_gccount );
365369 xfs_rtgroup_rele (iter -> victim_rtg );
366370 iter -> victim_rtg = NULL ;
367371 return 0 ;
@@ -451,6 +455,20 @@ xfs_zone_gc_pick_victim_from(
451455 if (!rtg )
452456 continue ;
453457
458+ /*
459+ * If the zone is already undergoing GC, don't pick it again.
460+ *
461+ * This prevents us from picking one of the zones for which we
462+ * already submitted GC I/O, but for which the remapping hasn't
463+ * concluded yet. This won't cause data corruption, but
464+ * increases write amplification and slows down GC, so this is
465+ * a bad thing.
466+ */
467+ if (atomic_read (& rtg -> rtg_gccount )) {
468+ xfs_rtgroup_rele (rtg );
469+ continue ;
470+ }
471+
454472 /* skip zones that are just waiting for a reset */
455473 if (rtg_rmap (rtg )-> i_used_blocks == 0 ||
456474 rtg_rmap (rtg )-> i_used_blocks >= victim_used ) {
@@ -688,6 +706,9 @@ xfs_zone_gc_start_chunk(
688706 chunk -> scratch = & data -> scratch [data -> scratch_idx ];
689707 chunk -> data = data ;
690708 chunk -> oz = oz ;
709+ chunk -> victim_rtg = iter -> victim_rtg ;
710+ atomic_inc (& chunk -> victim_rtg -> rtg_group .xg_active_ref );
711+ atomic_inc (& chunk -> victim_rtg -> rtg_gccount );
691712
692713 bio -> bi_iter .bi_sector = xfs_rtb_to_daddr (mp , chunk -> old_startblock );
693714 bio -> bi_end_io = xfs_zone_gc_end_io ;
@@ -710,6 +731,8 @@ static void
710731xfs_zone_gc_free_chunk (
711732 struct xfs_gc_bio * chunk )
712733{
734+ atomic_dec (& chunk -> victim_rtg -> rtg_gccount );
735+ xfs_rtgroup_rele (chunk -> victim_rtg );
713736 list_del (& chunk -> entry );
714737 xfs_open_zone_put (chunk -> oz );
715738 xfs_irele (chunk -> ip );
@@ -770,6 +793,10 @@ xfs_zone_gc_split_write(
770793 split_chunk -> oz = chunk -> oz ;
771794 atomic_inc (& chunk -> oz -> oz_ref );
772795
796+ split_chunk -> victim_rtg = chunk -> victim_rtg ;
797+ atomic_inc (& chunk -> victim_rtg -> rtg_group .xg_active_ref );
798+ atomic_inc (& chunk -> victim_rtg -> rtg_gccount );
799+
773800 chunk -> offset += split_len ;
774801 chunk -> len -= split_len ;
775802 chunk -> old_startblock += XFS_B_TO_FSB (data -> mp , split_len );
0 commit comments