diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/genhd.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/block/genhd.c b/block/genhd.c index ab0731d8976d..3608289c8ecd 100644 --- a/block/genhd.c +++ b/block/genhd.c | |||
@@ -1371,6 +1371,7 @@ struct disk_events { | |||
1371 | struct gendisk *disk; /* the associated disk */ | 1371 | struct gendisk *disk; /* the associated disk */ |
1372 | spinlock_t lock; | 1372 | spinlock_t lock; |
1373 | 1373 | ||
1374 | struct mutex block_mutex; /* protects blocking */ | ||
1374 | int block; /* event blocking depth */ | 1375 | int block; /* event blocking depth */ |
1375 | unsigned int pending; /* events already sent out */ | 1376 | unsigned int pending; /* events already sent out */ |
1376 | unsigned int clearing; /* events being cleared */ | 1377 | unsigned int clearing; /* events being cleared */ |
@@ -1438,12 +1439,20 @@ void disk_block_events(struct gendisk *disk) | |||
1438 | if (!ev) | 1439 | if (!ev) |
1439 | return; | 1440 | return; |
1440 | 1441 | ||
1442 | /* | ||
1443 | * Outer mutex ensures that the first blocker completes canceling | ||
1444 | * the event work before further blockers are allowed to finish. | ||
1445 | */ | ||
1446 | mutex_lock(&ev->block_mutex); | ||
1447 | |||
1441 | spin_lock_irqsave(&ev->lock, flags); | 1448 | spin_lock_irqsave(&ev->lock, flags); |
1442 | cancel = !ev->block++; | 1449 | cancel = !ev->block++; |
1443 | spin_unlock_irqrestore(&ev->lock, flags); | 1450 | spin_unlock_irqrestore(&ev->lock, flags); |
1444 | 1451 | ||
1445 | if (cancel) | 1452 | if (cancel) |
1446 | cancel_delayed_work_sync(&disk->ev->dwork); | 1453 | cancel_delayed_work_sync(&disk->ev->dwork); |
1454 | |||
1455 | mutex_unlock(&ev->block_mutex); | ||
1447 | } | 1456 | } |
1448 | 1457 | ||
1449 | static void __disk_unblock_events(struct gendisk *disk, bool check_now) | 1458 | static void __disk_unblock_events(struct gendisk *disk, bool check_now) |
@@ -1751,6 +1760,7 @@ static void disk_add_events(struct gendisk *disk) | |||
1751 | INIT_LIST_HEAD(&ev->node); | 1760 | INIT_LIST_HEAD(&ev->node); |
1752 | ev->disk = disk; | 1761 | ev->disk = disk; |
1753 | spin_lock_init(&ev->lock); | 1762 | spin_lock_init(&ev->lock); |
1763 | mutex_init(&ev->block_mutex); | ||
1754 | ev->block = 1; | 1764 | ev->block = 1; |
1755 | ev->poll_msecs = -1; | 1765 | ev->poll_msecs = -1; |
1756 | INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn); | 1766 | INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn); |