]> git.ipfire.org Git - thirdparty/kernel/stable.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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 10 Jul 2025 14:05:07 +0000 (16:05 +0200)
[ Upstream commit cffc873d68ab09a0432b8212008c5613f8a70a2c ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
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 280679bde3a5067ee3bc9ebe1e749a9fc2188e6b..4240e11adfb7698c65e2b3b85a433d0cd22a52a5 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++) {