summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2012-07-30 07:06:26 (GMT)
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-11-08 15:58:38 (GMT)
commit3b9ef85e05f123f535d4ee1c5041b80f80648e50 (patch)
tree48ef1eeef5aa653171f68d7c4f0e57e138d3d74a
parent27012382bc221a8cf6ca67ced19df699b0ba8e78 (diff)
downloadlinux-3b9ef85e05f123f535d4ee1c5041b80f80648e50.tar.xz
drbd: fix null pointer dereference with on-congestion policy when diskless
We must not look at mdev->actlog, unless we have a get_ldev() reference. It also does not make much sense to try to disconnect or pull-ahead of the peer, if we don't have good local data. Only even consider congestion policies, if our local disk is D_UP_TO_DATE. Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com> Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
-rw-r--r--drivers/block/drbd/drbd_req.c16
1 files changed, 11 insertions, 5 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c
index c45479a..891c3d4 100644
--- a/drivers/block/drbd/drbd_req.c
+++ b/drivers/block/drbd/drbd_req.c
@@ -823,7 +823,7 @@ static void complete_conflicting_writes(struct drbd_request *req)
}
/* called within req_lock and rcu_read_lock() */
-static bool conn_check_congested(struct drbd_conf *mdev)
+static void maybe_pull_ahead(struct drbd_conf *mdev)
{
struct drbd_tconn *tconn = mdev->tconn;
struct net_conf *nc;
@@ -834,7 +834,14 @@ static bool conn_check_congested(struct drbd_conf *mdev)
on_congestion = nc ? nc->on_congestion : OC_BLOCK;
if (on_congestion == OC_BLOCK ||
tconn->agreed_pro_version < 96)
- return false;
+ return;
+
+ /* If I don't even have good local storage, we can not reasonably try
+ * to pull ahead of the peer. We also need the local reference to make
+ * sure mdev->act_log is there.
+ */
+ if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
+ return;
if (nc->cong_fill &&
atomic_read(&mdev->ap_in_flight) >= nc->cong_fill) {
@@ -857,8 +864,7 @@ static bool conn_check_congested(struct drbd_conf *mdev)
else /*nc->on_congestion == OC_DISCONNECT */
_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
}
-
- return congested;
+ put_ldev(mdev);
}
/* If this returns false, and req->private_bio is still set,
@@ -923,7 +929,7 @@ static int drbd_process_write_request(struct drbd_request *req)
rcu_read_lock();
remote = drbd_should_do_remote(mdev->state);
if (remote) {
- conn_check_congested(mdev);
+ maybe_pull_ahead(mdev);
remote = drbd_should_do_remote(mdev->state);
}
send_oos = drbd_should_send_out_of_sync(mdev->state);