Skip to content

Commit

Permalink
block: don't use non-syncing event blocking in disk_check_events()
Browse files Browse the repository at this point in the history
This patch is part of fix for triggering of WARN_ON_ONCE() in
disk_clear_events() reported in bug#34662.

  https://bugzilla.kernel.org/show_bug.cgi?id=34662

disk_clear_events() blocks events, schedules and flushes the event
work.  It expects the work to have started execution on schedule and
finished on return from flush.  WARN_ON_ONCE() triggers if the event
work hasn't executed as expected.  This problem happens because
__disk_block_events() fails to guarantee that the event work item is
not in flight on return from the function in race-free manner.  The
problem is two-fold and this patch addresses one of them.

When __disk_block_events() is called with @sync == %false, it bumps
event block count, calls cancel_delayed_work() and return.  This makes
it impossible to guarantee that event polling is not in flight on
return from syncing __disk_block_events() - if the first blocker was
non-syncing, polling could still be in progress and later syncing ones
would assume that the first blocker already canceled it.

Making __disk_block_events() cancel_sync regardless of block count
isn't feasible either as it may race with forced event checking in
disk_clear_events().

As disk_check_events() is the only user of non-syncing
__disk_block_events(), updating it to directly cancel and schedule
event work is the easiest way to solve the issue.

Note that there's another bug in __disk_block_events() and this patch
doesn't fix the issue completely.  Later patch will fix the other bug.

Signed-off-by: Tejun Heo <[email protected]>
Tested-by: Sitsofe Wheeler <[email protected]>
Reported-by: Sitsofe Wheeler <[email protected]>
Reported-by: Borislav Petkov <[email protected]>
Reported-by: Meelis Roos <[email protected]>
Reported-by: Linus Torvalds <[email protected]>
Cc: Andrew Morton <[email protected]>
Cc: Jens Axboe <[email protected]>
Cc: Kay Sievers <[email protected]>
Signed-off-by: Jens Axboe <[email protected]>
  • Loading branch information
htejun authored and Jens Axboe committed Jun 9, 2011
1 parent ab4bd22 commit a9dce2a
Showing 1 changed file with 11 additions and 3 deletions.
14 changes: 11 additions & 3 deletions block/genhd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1508,10 +1508,18 @@ void disk_unblock_events(struct gendisk *disk)
*/
void disk_check_events(struct gendisk *disk)
{
if (disk->ev) {
__disk_block_events(disk, false);
__disk_unblock_events(disk, true);
struct disk_events *ev = disk->ev;
unsigned long flags;

if (!ev)
return;

spin_lock_irqsave(&ev->lock, flags);
if (!ev->block) {
cancel_delayed_work(&ev->dwork);
queue_delayed_work(system_nrt_wq, &ev->dwork, 0);
}
spin_unlock_irqrestore(&ev->lock, flags);
}
EXPORT_SYMBOL_GPL(disk_check_events);

Expand Down

0 comments on commit a9dce2a

Please sign in to comment.