]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
aoe: avoid potential deadlock at set_capacity
authorMaksim Kiselev <bigunclemax@gmail.com>
Wed, 24 Jan 2024 07:24:36 +0000 (10:24 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Jul 2025 16:30:48 +0000 (18:30 +0200)
commit e169bd4fb2b36c4b2bee63c35c740c85daeb2e86 upstream.

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: Maksim Kiselev <bigunclemax@gmail.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20240124072436.3745720-2-bigunclemax@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
[ Larry: backport to 5.15.y. Minor conflict resolved due to missing commit d9c2bd252a457
  aoe: add error handling support for add_disk() ]
Signed-off-by: Larry Bassel <larry.bassel@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/block/aoe/aoeblk.c

index 06b360f7123af59cfef1aab57489e2257e633b8f..4bbb540f26b941792296cd51ef3febbf9c573d78 100644 (file)
@@ -346,6 +346,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;
@@ -408,7 +409,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);
 
@@ -417,6 +418,8 @@ aoeblk_gdalloc(void *vp)
 
        spin_unlock_irqrestore(&d->lock, flags);
 
+       set_capacity(gd, ssize);
+
        device_add_disk(NULL, gd, aoe_attr_groups);
        aoedisk_add_debugfs(d);