Skip to content

Commit 3b8cafd

Browse files
damien-lemoalsnitm
authored andcommitted
dm zoned: fix zone state management race
dm-zoned uses the zone flag DMZ_ACTIVE to indicate that a zone of the backend device is being actively read or written and so cannot be reclaimed. This flag is set as long as the zone atomic reference counter is not 0. When this atomic is decremented and reaches 0 (e.g. on BIO completion), the active flag is cleared and set again whenever the zone is reused and BIO issued with the atomic counter incremented. These 2 operations (atomic inc/dec and flag set/clear) are however not always executed atomically under the target metadata mutex lock and this causes the warning: WARN_ON(!test_bit(DMZ_ACTIVE, &zone->flags)); in dmz_deactivate_zone() to be displayed. This problem is regularly triggered with xfstests generic/209, generic/300, generic/451 and xfs/077 with XFS being used as the file system on the dm-zoned target device. Similarly, xfstests ext4/303, ext4/304, generic/209 and generic/300 trigger the warning with ext4 use. This problem can be easily fixed by simply removing the DMZ_ACTIVE flag and managing the "ACTIVE" state by directly looking at the reference counter value. To do so, the functions dmz_activate_zone() and dmz_deactivate_zone() are changed to inline functions respectively calling atomic_inc() and atomic_dec(), while the dmz_is_active() macro is changed to an inline function calling atomic_read(). Fixes: 3b1a94c ("dm zoned: drive-managed zoned block device target") Cc: [email protected] Reported-by: Masato Suzuki <[email protected]> Signed-off-by: Damien Le Moal <[email protected]> Signed-off-by: Mike Snitzer <[email protected]>
1 parent bd293d0 commit 3b8cafd

File tree

2 files changed

+24
-28
lines changed

2 files changed

+24
-28
lines changed

drivers/md/dm-zoned-metadata.c

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1593,30 +1593,6 @@ struct dm_zone *dmz_get_zone_for_reclaim(struct dmz_metadata *zmd)
15931593
return zone;
15941594
}
15951595

1596-
/*
1597-
* Activate a zone (increment its reference count).
1598-
*/
1599-
void dmz_activate_zone(struct dm_zone *zone)
1600-
{
1601-
set_bit(DMZ_ACTIVE, &zone->flags);
1602-
atomic_inc(&zone->refcount);
1603-
}
1604-
1605-
/*
1606-
* Deactivate a zone. This decrement the zone reference counter
1607-
* and clears the active state of the zone once the count reaches 0,
1608-
* indicating that all BIOs to the zone have completed. Returns
1609-
* true if the zone was deactivated.
1610-
*/
1611-
void dmz_deactivate_zone(struct dm_zone *zone)
1612-
{
1613-
if (atomic_dec_and_test(&zone->refcount)) {
1614-
WARN_ON(!test_bit(DMZ_ACTIVE, &zone->flags));
1615-
clear_bit_unlock(DMZ_ACTIVE, &zone->flags);
1616-
smp_mb__after_atomic();
1617-
}
1618-
}
1619-
16201596
/*
16211597
* Get the zone mapping a chunk, if the chunk is mapped already.
16221598
* If no mapping exist and the operation is WRITE, a zone is

drivers/md/dm-zoned.h

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ enum {
115115
DMZ_BUF,
116116

117117
/* Zone internal state */
118-
DMZ_ACTIVE,
119118
DMZ_RECLAIM,
120119
DMZ_SEQ_WRITE_ERR,
121120
};
@@ -128,7 +127,6 @@ enum {
128127
#define dmz_is_empty(z) ((z)->wp_block == 0)
129128
#define dmz_is_offline(z) test_bit(DMZ_OFFLINE, &(z)->flags)
130129
#define dmz_is_readonly(z) test_bit(DMZ_READ_ONLY, &(z)->flags)
131-
#define dmz_is_active(z) test_bit(DMZ_ACTIVE, &(z)->flags)
132130
#define dmz_in_reclaim(z) test_bit(DMZ_RECLAIM, &(z)->flags)
133131
#define dmz_seq_write_err(z) test_bit(DMZ_SEQ_WRITE_ERR, &(z)->flags)
134132

@@ -188,8 +186,30 @@ void dmz_unmap_zone(struct dmz_metadata *zmd, struct dm_zone *zone);
188186
unsigned int dmz_nr_rnd_zones(struct dmz_metadata *zmd);
189187
unsigned int dmz_nr_unmap_rnd_zones(struct dmz_metadata *zmd);
190188

191-
void dmz_activate_zone(struct dm_zone *zone);
192-
void dmz_deactivate_zone(struct dm_zone *zone);
189+
/*
190+
* Activate a zone (increment its reference count).
191+
*/
192+
static inline void dmz_activate_zone(struct dm_zone *zone)
193+
{
194+
atomic_inc(&zone->refcount);
195+
}
196+
197+
/*
198+
* Deactivate a zone. This decrement the zone reference counter
199+
* indicating that all BIOs to the zone have completed when the count is 0.
200+
*/
201+
static inline void dmz_deactivate_zone(struct dm_zone *zone)
202+
{
203+
atomic_dec(&zone->refcount);
204+
}
205+
206+
/*
207+
* Test if a zone is active, that is, has a refcount > 0.
208+
*/
209+
static inline bool dmz_is_active(struct dm_zone *zone)
210+
{
211+
return atomic_read(&zone->refcount);
212+
}
193213

194214
int dmz_lock_zone_reclaim(struct dm_zone *zone);
195215
void dmz_unlock_zone_reclaim(struct dm_zone *zone);

0 commit comments

Comments
 (0)