Skip to content

Commit

Permalink
dm zoned: Fix zone reclaim trigger
Browse files Browse the repository at this point in the history
Only triggering reclaim based on the percentage of unmapped cache
zones can fail to detect cases where reclaim is needed, e.g. if the
target has only 2 or 3 cache zones and only one unmapped cache zone,
the percentage of free cache zones is higher than
DMZ_RECLAIM_LOW_UNMAP_ZONES (30%) and reclaim does not trigger.

This problem, combined with the fact that dmz_schedule_reclaim() is
called from dmz_handle_bio() without the map lock held, leads to a
race between zone allocation and dmz_should_reclaim() result.
Depending on the workload applied, this race can lead to the write
path waiting forever for a free zone without reclaim being triggered.

Fix this by moving dmz_schedule_reclaim() inside dmz_alloc_zone()
under the map lock. This results in checking the need for zone reclaim
whenever a new data or buffer zone needs to be allocated.

Also fix dmz_reclaim_percentage() to always return 0 if the number of
unmapped cache (or random) zones is less than or equal to 1.

Suggested-by: Shin'ichiro Kawasaki <[email protected]>
Signed-off-by: Damien Le Moal <[email protected]>
Reviewed-by: Hannes Reinecke <[email protected]>
Signed-off-by: Mike Snitzer <[email protected]>
  • Loading branch information
damien-lemoal authored and snitm committed Jul 8, 2020
1 parent ce34c9b commit 174364f
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 10 deletions.
9 changes: 8 additions & 1 deletion drivers/md/dm-zoned-metadata.c
Original file line number Diff line number Diff line change
Expand Up @@ -2217,8 +2217,15 @@ struct dm_zone *dmz_alloc_zone(struct dmz_metadata *zmd, unsigned int dev_idx,
{
struct list_head *list;
struct dm_zone *zone;
int i = 0;
int i;

/* Schedule reclaim to ensure free zones are available */
if (!(flags & DMZ_ALLOC_RECLAIM)) {
for (i = 0; i < zmd->nr_devs; i++)
dmz_schedule_reclaim(zmd->dev[i].reclaim);
}

i = 0;
again:
if (flags & DMZ_ALLOC_CACHE)
list = &zmd->unmap_cache_list;
Expand Down
2 changes: 2 additions & 0 deletions drivers/md/dm-zoned-reclaim.c
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,8 @@ static unsigned int dmz_reclaim_percentage(struct dmz_reclaim *zrc)
nr_zones = dmz_nr_rnd_zones(zmd, zrc->dev_idx);
nr_unmap = dmz_nr_unmap_rnd_zones(zmd, zrc->dev_idx);
}
if (nr_unmap <= 1)
return 0;
return nr_unmap * 100 / nr_zones;
}

Expand Down
10 changes: 1 addition & 9 deletions drivers/md/dm-zoned-target.c
Original file line number Diff line number Diff line change
Expand Up @@ -400,15 +400,7 @@ static void dmz_handle_bio(struct dmz_target *dmz, struct dm_chunk_work *cw,
dm_per_bio_data(bio, sizeof(struct dmz_bioctx));
struct dmz_metadata *zmd = dmz->metadata;
struct dm_zone *zone;
int i, ret;

/*
* Write may trigger a zone allocation. So make sure the
* allocation can succeed.
*/
if (bio_op(bio) == REQ_OP_WRITE)
for (i = 0; i < dmz->nr_ddevs; i++)
dmz_schedule_reclaim(dmz->dev[i].reclaim);
int ret;

dmz_lock_metadata(zmd);

Expand Down

0 comments on commit 174364f

Please sign in to comment.