Commit e169bd4f authored by Maksim Kiselev's avatar Maksim Kiselev Committed by Jens Axboe
Browse files

aoe: avoid potential deadlock at set_capacity



Move set_capacity() outside of the section procected by (&d->lock).
To avoid possible interrupt unsafe locking scenario:

        CPU0                    CPU1
        ----                    ----
[1] lock(&bdev->bd_size_lock);
                                local_irq_disable();
                            [2] lock(&d->lock);
                            [3] lock(&bdev->bd_size_lock);
   <Interrupt>
[4]  lock(&d->lock);

  *** DEADLOCK ***

Where [1](&bdev->bd_size_lock) hold by zram_add()->set_capacity().
[2]lock(&d->lock) hold by aoeblk_gdalloc(). And aoeblk_gdalloc()
is trying to acquire [3](&bdev->bd_size_lock) at set_capacity() call.
In this situation an attempt to acquire [4]lock(&d->lock) from
aoecmd_cfg_rsp() will lead to deadlock.

So the simplest solution is breaking lock dependency
[2](&d->lock) -> [3](&bdev->bd_size_lock) by moving set_capacity()
outside.

Signed-off-by: default avatarMaksim Kiselev <bigunclemax@gmail.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20240124072436.3745720-2-bigunclemax@gmail.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 13f3956e
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -333,6 +333,7 @@ aoeblk_gdalloc(void *vp)
	struct gendisk *gd;
	mempool_t *mp;
	struct blk_mq_tag_set *set;
	sector_t ssize;
	ulong flags;
	int late = 0;
	int err;
@@ -396,7 +397,7 @@ aoeblk_gdalloc(void *vp)
	gd->minors = AOE_PARTITIONS;
	gd->fops = &aoe_bdops;
	gd->private_data = d;
	set_capacity(gd, d->ssize);
	ssize = d->ssize;
	snprintf(gd->disk_name, sizeof gd->disk_name, "etherd/e%ld.%d",
		d->aoemajor, d->aoeminor);

@@ -405,6 +406,8 @@ aoeblk_gdalloc(void *vp)

	spin_unlock_irqrestore(&d->lock, flags);

	set_capacity(gd, ssize);

	err = device_add_disk(NULL, gd, aoe_attr_groups);
	if (err)
		goto out_disk_cleanup;