summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_int.h
diff options
context:
space:
mode:
authorPhilipp Reisner <philipp.reisner@linbit.com>2012-08-21 20:34:07 +0200
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-09 14:08:20 +0100
commitc1fd29a11f433ca8ae37723768016ffe6cdd487b (patch)
treed297c9ee730f292a2a789f9bbeceffde075afc26 /drivers/block/drbd/drbd_int.h
parentdrbd: temporarily suspend io in drbd_adm_disk_opts (diff)
downloadlinux-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.h27
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)