diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2012-08-21 20:34:07 +0200 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-11-09 14:08:20 +0100 |
commit | c1fd29a11f433ca8ae37723768016ffe6cdd487b (patch) | |
tree | d297c9ee730f292a2a789f9bbeceffde075afc26 /drivers/block/drbd/drbd_int.h | |
parent | drbd: temporarily suspend io in drbd_adm_disk_opts (diff) | |
download | linux-c1fd29a11f433ca8ae37723768016ffe6cdd487b.tar.xz linux-c1fd29a11f433ca8ae37723768016ffe6cdd487b.zip |
drbd: Fix a race condition that can lead to a BUG()
If the preconditions for a state change change after the wait_event() we
might hit the BUG() statement in conn_set_state().
With holding the spin_lock while evaluating the condition AND until the
actual state change we ensure the the preconditions can not change anymore.
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_int.h')
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 37ae87e468ae..1c1576b942b6 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h @@ -2301,3 +2301,30 @@ static inline void drbd_md_flush(struct drbd_conf *mdev) } #endif + +/* This is defined in drivers/md/md.h as well. Should go into wait.h */ +#define __wait_event_lock_irq(wq, condition, lock, cmd) \ +do { \ + wait_queue_t __wait; \ + init_waitqueue_entry(&__wait, current); \ + \ + add_wait_queue(&wq, &__wait); \ + for (;;) { \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + if (condition) \ + break; \ + spin_unlock_irq(&lock); \ + cmd; \ + schedule(); \ + spin_lock_irq(&lock); \ + } \ + current->state = TASK_RUNNING; \ + remove_wait_queue(&wq, &__wait); \ +} while (0) + +#define wait_event_lock_irq(wq, condition, lock, cmd) \ +do { \ + if (condition) \ + break; \ + __wait_event_lock_irq(wq, condition, lock, cmd); \ +} while (0) |