summaryrefslogtreecommitdiffstats
path: root/drivers/block/drbd/drbd_req.h
diff options
context:
space:
mode:
authorLars Ellenberg2011-11-24 10:36:25 +0100
committerPhilipp Reisner2012-11-08 16:58:21 +0100
commit2312f0b3c5ab794fbac9e9bebe90c784c9d449c5 (patch)
tree0b4b74af502169d61e026855593b828fa202665a /drivers/block/drbd/drbd_req.h
parentdrbd: don't pretend that barrier_nr == 0 was special (diff)
downloadkernel-qcow2-linux-2312f0b3c5ab794fbac9e9bebe90c784c9d449c5.tar.gz
kernel-qcow2-linux-2312f0b3c5ab794fbac9e9bebe90c784c9d449c5.tar.xz
kernel-qcow2-linux-2312f0b3c5ab794fbac9e9bebe90c784c9d449c5.zip
drbd: fix potential deadlock during "restart" of conflicting writes
w_restart_write(), run from worker context, calls __drbd_make_request() and further drbd_al_begin_io(, delegate=true), which then potentially deadlocks. The previous patch moved a BUG_ON to expose such call paths, which would now be triggered. Also, if we call __drbd_make_request() from resource worker context, like w_restart_write() did, and that should block for whatever reason (!drbd_state_is_stable(), resource suspended, ...), we potentially deadlock the whole resource, as the worker is needed for state changes and other things. Create a dedicated retry workqueue for this instead. Also make sure that inc_ap_bio()/dec_ap_bio() are properly paired, even if do_retry() needs to retry itself, in case __drbd_make_request() returns != 0. 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_req.h')
-rw-r--r--drivers/block/drbd/drbd_req.h3
1 files changed, 3 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h
index 68f54050b7ca..492f81d3765a 100644
--- a/drivers/block/drbd/drbd_req.h
+++ b/drivers/block/drbd/drbd_req.h
@@ -268,6 +268,9 @@ extern void request_timer_fn(unsigned long data);
extern void tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what);
extern void _tl_restart(struct drbd_tconn *tconn, enum drbd_req_event what);
+/* this is in drbd_main.c */
+extern void drbd_restart_write(struct drbd_request *req);
+
/* use this if you don't want to deal with calling complete_master_bio()
* outside the spinlock, e.g. when walking some list on cleanup. */
static inline int _req_mod(struct drbd_request *req, enum drbd_req_event what)