Skip to content

Commit 79ae35a

Browse files
damien-lemoalaxboe
authored andcommitted
block: Unhash a zone write plug only if needed
Fix disk_remove_zone_wplug() to ensure that a zone write plug already removed from a disk hash table of zone write plugs is not removed again. Do this by checking the BLK_ZONE_WPLUG_UNHASHED flag of the plug and calling hlist_del_init_rcu() only if the flag is not set. Furthermore, since BIO completions can happen at any time, that is, decrementing of the zone write plug reference count can happen at any time, make sure to use disk_put_zone_wplug() instead of atomic_dec() to ensure that the zone write plug is freed when its last reference is dropped. In order to do this, disk_remove_zone_wplug() is moved after the definition of disk_put_zone_wplug(). disk_should_remove_zone_wplug() is moved as well to keep it together with disk_remove_zone_wplug(). To be consistent with this change, add a check in disk_put_zone_wplug() to ensure that a zone write plug being freed was already removed from the disk hash table. Fixes: dd291d7 ("block: Introduce zone write plugging") Signed-off-by: Damien Le Moal <dlemoal@kernel.org> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com> Link: https://lore.kernel.org/r/20240501110907.96950-7-dlemoal@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 9e78c38 commit 79ae35a

File tree

1 file changed

+32
-23
lines changed

1 file changed

+32
-23
lines changed

block/blk-zoned.c

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -476,29 +476,6 @@ static bool disk_insert_zone_wplug(struct gendisk *disk,
476476
return true;
477477
}
478478

479-
static void disk_remove_zone_wplug(struct gendisk *disk,
480-
struct blk_zone_wplug *zwplug)
481-
{
482-
unsigned long flags;
483-
484-
spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
485-
zwplug->flags |= BLK_ZONE_WPLUG_UNHASHED;
486-
atomic_dec(&zwplug->ref);
487-
hlist_del_init_rcu(&zwplug->node);
488-
spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
489-
}
490-
491-
static inline bool disk_should_remove_zone_wplug(struct gendisk *disk,
492-
struct blk_zone_wplug *zwplug)
493-
{
494-
/* If the zone is still busy, the plug cannot be removed. */
495-
if (zwplug->flags & BLK_ZONE_WPLUG_BUSY)
496-
return false;
497-
498-
/* We can remove zone write plugs for zones that are empty or full. */
499-
return !zwplug->wp_offset || zwplug->wp_offset >= disk->zone_capacity;
500-
}
501-
502479
static struct blk_zone_wplug *disk_get_zone_wplug(struct gendisk *disk,
503480
sector_t sector)
504481
{
@@ -534,11 +511,43 @@ static inline void disk_put_zone_wplug(struct blk_zone_wplug *zwplug)
534511
if (atomic_dec_and_test(&zwplug->ref)) {
535512
WARN_ON_ONCE(!bio_list_empty(&zwplug->bio_list));
536513
WARN_ON_ONCE(!list_empty(&zwplug->link));
514+
WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_UNHASHED));
537515

538516
call_rcu(&zwplug->rcu_head, disk_free_zone_wplug_rcu);
539517
}
540518
}
541519

520+
static inline bool disk_should_remove_zone_wplug(struct gendisk *disk,
521+
struct blk_zone_wplug *zwplug)
522+
{
523+
/* If the zone is still busy, the plug cannot be removed. */
524+
if (zwplug->flags & BLK_ZONE_WPLUG_BUSY)
525+
return false;
526+
527+
/* We can remove zone write plugs for zones that are empty or full. */
528+
return !zwplug->wp_offset || zwplug->wp_offset >= disk->zone_capacity;
529+
}
530+
531+
static void disk_remove_zone_wplug(struct gendisk *disk,
532+
struct blk_zone_wplug *zwplug)
533+
{
534+
unsigned long flags;
535+
536+
/* If the zone write plug was already removed, we have nothing to do. */
537+
if (zwplug->flags & BLK_ZONE_WPLUG_UNHASHED)
538+
return;
539+
540+
/*
541+
* Mark the zone write plug as unhashed and drop the extra reference we
542+
* took when the plug was inserted in the hash table.
543+
*/
544+
zwplug->flags |= BLK_ZONE_WPLUG_UNHASHED;
545+
spin_lock_irqsave(&disk->zone_wplugs_lock, flags);
546+
hlist_del_init_rcu(&zwplug->node);
547+
spin_unlock_irqrestore(&disk->zone_wplugs_lock, flags);
548+
disk_put_zone_wplug(zwplug);
549+
}
550+
542551
static void blk_zone_wplug_bio_work(struct work_struct *work);
543552

544553
/*

0 commit comments

Comments
 (0)