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>
This commit is contained in:
parent
1ed25b269e
commit
0d5934e3c2
|
@ -770,6 +770,40 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s
|
||||||
return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
|
return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void maybe_pull_ahead(struct drbd_conf *mdev)
|
||||||
|
{
|
||||||
|
int congested = 0;
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
* Note: caller has to make sure that net_conf is there.
|
||||||
|
*/
|
||||||
|
if (!get_ldev_if_state(mdev, D_UP_TO_DATE))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (mdev->net_conf->cong_fill &&
|
||||||
|
atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
|
||||||
|
dev_info(DEV, "Congestion-fill threshold reached\n");
|
||||||
|
congested = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
|
||||||
|
dev_info(DEV, "Congestion-extents threshold reached\n");
|
||||||
|
congested = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (congested) {
|
||||||
|
queue_barrier(mdev); /* last barrier, after mirrored writes */
|
||||||
|
|
||||||
|
if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
|
||||||
|
_drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
|
||||||
|
else /*mdev->net_conf->on_congestion == OC_DISCONNECT */
|
||||||
|
_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
|
||||||
|
}
|
||||||
|
put_ldev(mdev);
|
||||||
|
}
|
||||||
|
|
||||||
static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
|
static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time)
|
||||||
{
|
{
|
||||||
const int rw = bio_rw(bio);
|
const int rw = bio_rw(bio);
|
||||||
|
@ -977,29 +1011,8 @@ allocate_barrier:
|
||||||
_req_mod(req, queue_for_send_oos);
|
_req_mod(req, queue_for_send_oos);
|
||||||
|
|
||||||
if (remote &&
|
if (remote &&
|
||||||
mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) {
|
mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96)
|
||||||
int congested = 0;
|
maybe_pull_ahead(mdev);
|
||||||
|
|
||||||
if (mdev->net_conf->cong_fill &&
|
|
||||||
atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) {
|
|
||||||
dev_info(DEV, "Congestion-fill threshold reached\n");
|
|
||||||
congested = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mdev->act_log->used >= mdev->net_conf->cong_extents) {
|
|
||||||
dev_info(DEV, "Congestion-extents threshold reached\n");
|
|
||||||
congested = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (congested) {
|
|
||||||
queue_barrier(mdev); /* last barrier, after mirrored writes */
|
|
||||||
|
|
||||||
if (mdev->net_conf->on_congestion == OC_PULL_AHEAD)
|
|
||||||
_drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL);
|
|
||||||
else /*mdev->net_conf->on_congestion == OC_DISCONNECT */
|
|
||||||
_drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
spin_unlock_irq(&mdev->req_lock);
|
spin_unlock_irq(&mdev->req_lock);
|
||||||
kfree(b); /* if someone else has beaten us to it... */
|
kfree(b); /* if someone else has beaten us to it... */
|
||||||
|
|
Reference in New Issue