]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
aoe: defer rexmit timer downdev work to workqueue
authorJustin Sanders <jsanders.devel@gmail.com>
Tue, 10 Jun 2025 17:06:00 +0000 (17:06 +0000)
committerJens Axboe <axboe@kernel.dk>
Tue, 17 Jun 2025 12:12:35 +0000 (06:12 -0600)
When aoe's rexmit_timer() notices that an aoe target fails to respond to
commands for more than aoe_deadsecs, it calls aoedev_downdev() which
cleans the outstanding aoe and block queues. This can involve sleeping,
such as in blk_mq_freeze_queue(), which should not occur in irq context.

This patch defers that aoedev_downdev() call to the aoe device's
workqueue.

Link: https://bugzilla.kernel.org/show_bug.cgi?id=212665
Signed-off-by: Justin Sanders <jsanders.devel@gmail.com>
Link: https://lore.kernel.org/r/20250610170600.869-2-jsanders.devel@gmail.com
Tested-By: Valentin Kleibel <valentin@vrvis.at>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
drivers/block/aoe/aoe.h
drivers/block/aoe/aoecmd.c
drivers/block/aoe/aoedev.c

index 749ae1246f4cf894f8544248c1461d0d06720db0..d35caa3c69e15e70dcb33decb18973f472b71865 100644 (file)
@@ -80,6 +80,7 @@ enum {
        DEVFL_NEWSIZE = (1<<6), /* need to update dev size in block layer */
        DEVFL_FREEING = (1<<7), /* set when device is being cleaned up */
        DEVFL_FREED = (1<<8),   /* device has been cleaned up */
+       DEVFL_DEAD = (1<<9),    /* device has timed out of aoe_deadsecs */
 };
 
 enum {
index 92b06d1de4cc7b7c4ea6f5fad6aa6c4518c1001b..6c94cfd1c480ea2175f5cdfed2857c9075e20919 100644 (file)
@@ -754,7 +754,7 @@ rexmit_timer(struct timer_list *timer)
 
        utgts = count_targets(d, NULL);
 
-       if (d->flags & DEVFL_TKILL) {
+       if (d->flags & (DEVFL_TKILL | DEVFL_DEAD)) {
                spin_unlock_irqrestore(&d->lock, flags);
                return;
        }
@@ -786,7 +786,8 @@ rexmit_timer(struct timer_list *timer)
                         * to clean up.
                         */
                        list_splice(&flist, &d->factive[0]);
-                       aoedev_downdev(d);
+                       d->flags |= DEVFL_DEAD;
+                       queue_work(aoe_wq, &d->work);
                        goto out;
                }
 
@@ -898,6 +899,9 @@ aoecmd_sleepwork(struct work_struct *work)
 {
        struct aoedev *d = container_of(work, struct aoedev, work);
 
+       if (d->flags & DEVFL_DEAD)
+               aoedev_downdev(d);
+
        if (d->flags & DEVFL_GDALLOC)
                aoeblk_gdalloc(d);
 
index 8c18034cb3d69e85efcd20c6d902a4711b344bfe..9b66f8ebce50d003f234f4b7a79a4539ebeabe98 100644 (file)
@@ -200,8 +200,11 @@ aoedev_downdev(struct aoedev *d)
        struct list_head *head, *pos, *nx;
        struct request *rq, *rqnext;
        int i;
+       unsigned long flags;
 
-       d->flags &= ~DEVFL_UP;
+       spin_lock_irqsave(&d->lock, flags);
+       d->flags &= ~(DEVFL_UP | DEVFL_DEAD);
+       spin_unlock_irqrestore(&d->lock, flags);
 
        /* clean out active and to-be-retransmitted buffers */
        for (i = 0; i < NFACTIVE; i++) {