|
Hannes Reinecke |
57427b |
From ebd780ac233884d6ad298e29ba13d002da2ee5be Mon Sep 17 00:00:00 2001
|
|
Hannes Reinecke |
57427b |
From: Hannes Reinecke <hare@suse.de>
|
|
Hannes Reinecke |
57427b |
Date: Fri, 14 May 2021 12:44:38 +0200
|
|
Hannes Reinecke |
57427b |
Subject: [PATCH] block/genhd: use atomic_t for disk_event->block
|
|
Hannes Reinecke |
57427b |
References: bsc#1185497
|
|
Hannes Reinecke |
57427b |
Patch-Mainline: submitted linux-block 2021/06/01
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
__disk_unblock_events() will call queue_delayed_work() with a '0' argument
|
|
Hannes Reinecke |
57427b |
under a spin lock. This might cause the queue_work item to be executed
|
|
Hannes Reinecke |
57427b |
immediately, and run into a deadlock in disk_check_events() waiting for
|
|
Hannes Reinecke |
57427b |
the lock to be released.
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
This patch converts the 'blocked' counter into an atomic variable, so we don't
|
|
Hannes Reinecke |
57427b |
need to hold a spinlock anymore when scheduling the workqueue function.
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
Signed-off-by: Hannes Reinecke <hare@suse.de>
|
|
Hannes Reinecke |
57427b |
---
|
|
Hannes Reinecke |
57427b |
block/genhd.c | 36 +++++++++++++-----------------------
|
|
Hannes Reinecke |
57427b |
1 file changed, 13 insertions(+), 23 deletions(-)
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
diff --git a/block/genhd.c b/block/genhd.c
|
|
Hannes Reinecke |
57427b |
index ab29d1a723b2..e1c3b9d2b5d6 100644
|
|
Hannes Reinecke |
57427b |
--- a/block/genhd.c
|
|
Hannes Reinecke |
57427b |
+++ b/block/genhd.c
|
|
Hannes Reinecke |
57427b |
@@ -1731,7 +1731,7 @@ struct disk_events {
|
|
Hannes Reinecke |
57427b |
spinlock_t lock;
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
struct mutex block_mutex; /* protects blocking */
|
|
Hannes Reinecke |
57427b |
- int block; /* event blocking depth */
|
|
Hannes Reinecke |
57427b |
+ atomic_t block; /* event blocking depth */
|
|
Hannes Reinecke |
57427b |
unsigned int pending; /* events already sent out */
|
|
Hannes Reinecke |
57427b |
unsigned int clearing; /* events being cleared */
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
@@ -1791,8 +1791,6 @@ static unsigned long disk_events_poll_jiffies(struct gendisk *disk)
|
|
Hannes Reinecke |
57427b |
void disk_block_events(struct gendisk *disk)
|
|
Hannes Reinecke |
57427b |
{
|
|
Hannes Reinecke |
57427b |
struct disk_events *ev = disk->ev;
|
|
Hannes Reinecke |
57427b |
- unsigned long flags;
|
|
Hannes Reinecke |
57427b |
- bool cancel;
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
if (!ev)
|
|
Hannes Reinecke |
57427b |
return;
|
|
Hannes Reinecke |
57427b |
@@ -1803,11 +1801,7 @@ void disk_block_events(struct gendisk *disk)
|
|
Hannes Reinecke |
57427b |
*/
|
|
Hannes Reinecke |
57427b |
mutex_lock(&ev->block_mutex);
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
- spin_lock_irqsave(&ev->lock, flags);
|
|
Hannes Reinecke |
57427b |
- cancel = !ev->block++;
|
|
Hannes Reinecke |
57427b |
- spin_unlock_irqrestore(&ev->lock, flags);
|
|
Hannes Reinecke |
57427b |
-
|
|
Hannes Reinecke |
57427b |
- if (cancel)
|
|
Hannes Reinecke |
57427b |
+ if (atomic_inc_return(&ev->block) == 1)
|
|
Hannes Reinecke |
57427b |
cancel_delayed_work_sync(&disk->ev->dwork);
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
mutex_unlock(&ev->block_mutex);
|
|
Hannes Reinecke |
57427b |
@@ -1819,23 +1813,19 @@ static void __disk_unblock_events(struct gendisk *disk, bool check_now)
|
|
Hannes Reinecke |
57427b |
unsigned long intv;
|
|
Hannes Reinecke |
57427b |
unsigned long flags;
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
+ if (atomic_dec_return(&ev->block) <= 0) {
|
|
Hannes Reinecke |
57427b |
+ mutex_unlock(&ev->block_mutex);
|
|
Hannes Reinecke |
57427b |
+ return;
|
|
Hannes Reinecke |
57427b |
+ }
|
|
Hannes Reinecke |
57427b |
spin_lock_irqsave(&ev->lock, flags);
|
|
Hannes Reinecke |
57427b |
-
|
|
Hannes Reinecke |
57427b |
- if (WARN_ON_ONCE(ev->block <= 0))
|
|
Hannes Reinecke |
57427b |
- goto out_unlock;
|
|
Hannes Reinecke |
57427b |
-
|
|
Hannes Reinecke |
57427b |
- if (--ev->block)
|
|
Hannes Reinecke |
57427b |
- goto out_unlock;
|
|
Hannes Reinecke |
57427b |
-
|
|
Hannes Reinecke |
57427b |
intv = disk_events_poll_jiffies(disk);
|
|
Hannes Reinecke |
57427b |
+ spin_unlock_irqrestore(&ev->lock, flags);
|
|
Hannes Reinecke |
57427b |
if (check_now)
|
|
Hannes Reinecke |
57427b |
queue_delayed_work(system_freezable_power_efficient_wq,
|
|
Hannes Reinecke |
57427b |
&ev->dwork, 0);
|
|
Hannes Reinecke |
57427b |
else if (intv)
|
|
Hannes Reinecke |
57427b |
queue_delayed_work(system_freezable_power_efficient_wq,
|
|
Hannes Reinecke |
57427b |
&ev->dwork, intv);
|
|
Hannes Reinecke |
57427b |
-out_unlock:
|
|
Hannes Reinecke |
57427b |
- spin_unlock_irqrestore(&ev->lock, flags);
|
|
Hannes Reinecke |
57427b |
}
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
/**
|
|
Hannes Reinecke |
57427b |
@@ -1875,10 +1865,10 @@ void disk_flush_events(struct gendisk *disk, unsigned int mask)
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
spin_lock_irq(&ev->lock);
|
|
Hannes Reinecke |
57427b |
ev->clearing |= mask;
|
|
Hannes Reinecke |
57427b |
- if (!ev->block)
|
|
Hannes Reinecke |
57427b |
+ spin_unlock_irq(&ev->lock);
|
|
Hannes Reinecke |
57427b |
+ if (!atomic_read(&ev->block))
|
|
Hannes Reinecke |
57427b |
mod_delayed_work(system_freezable_power_efficient_wq,
|
|
Hannes Reinecke |
57427b |
&ev->dwork, 0);
|
|
Hannes Reinecke |
57427b |
- spin_unlock_irq(&ev->lock);
|
|
Hannes Reinecke |
57427b |
}
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
/**
|
|
Hannes Reinecke |
57427b |
@@ -1969,11 +1959,11 @@ static void disk_check_events(struct disk_events *ev,
|
|
Hannes Reinecke |
57427b |
*clearing_ptr &= ~clearing;
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
intv = disk_events_poll_jiffies(disk);
|
|
Hannes Reinecke |
57427b |
- if (!ev->block && intv)
|
|
Hannes Reinecke |
57427b |
+ spin_unlock_irq(&ev->lock);
|
|
Hannes Reinecke |
57427b |
+ if (!atomic_read(&ev->block) && intv)
|
|
Hannes Reinecke |
57427b |
queue_delayed_work(system_freezable_power_efficient_wq,
|
|
Hannes Reinecke |
57427b |
&ev->dwork, intv);
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
- spin_unlock_irq(&ev->lock);
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
/*
|
|
Hannes Reinecke |
57427b |
* Tell userland about new events. Only the events listed in
|
|
Hannes Reinecke |
57427b |
@@ -2138,7 +2128,7 @@ static void disk_alloc_events(struct gendisk *disk)
|
|
Hannes Reinecke |
57427b |
ev->disk = disk;
|
|
Hannes Reinecke |
57427b |
spin_lock_init(&ev->lock);
|
|
Hannes Reinecke |
57427b |
mutex_init(&ev->block_mutex);
|
|
Hannes Reinecke |
57427b |
- ev->block = 1;
|
|
Hannes Reinecke |
57427b |
+ atomic_set(&ev->block, 1);
|
|
Hannes Reinecke |
57427b |
ev->poll_msecs = -1;
|
|
Hannes Reinecke |
57427b |
INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn);
|
|
Hannes Reinecke |
57427b |
|
|
Hannes Reinecke |
57427b |
@@ -2182,6 +2172,6 @@ static void disk_del_events(struct gendisk *disk)
|
|
Hannes Reinecke |
57427b |
static void disk_release_events(struct gendisk *disk)
|
|
Hannes Reinecke |
57427b |
{
|
|
Hannes Reinecke |
57427b |
/* the block count should be 1 from disk_del_events() */
|
|
Hannes Reinecke |
57427b |
- WARN_ON_ONCE(disk->ev && disk->ev->block != 1);
|
|
Hannes Reinecke |
57427b |
+ WARN_ON_ONCE(disk->ev && atomic_read(&disk->ev->block) != 1);
|
|
Hannes Reinecke |
57427b |
kfree(disk->ev);
|
|
Hannes Reinecke |
57427b |
}
|
|
Hannes Reinecke |
57427b |
--
|
|
Hannes Reinecke |
57427b |
2.29.2
|
|
Hannes Reinecke |
57427b |
|