diff options
author | Lars Ellenberg <lars.ellenberg@linbit.com> | 2012-06-08 08:17:36 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2012-06-12 08:35:19 -0400 |
commit | 0d5934e3c258fc5decc4103600c597086fd95a52 (patch) | |
tree | 1e9810b23c495ffed5f9d1814ea74535b6013ea5 /drivers | |
parent | 1ed25b269e3dd5ecc64f17beef9ea21745c39ca6 (diff) |
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>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 59 |
1 files changed, 36 insertions, 23 deletions
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 773f4e2d3c1b..8e93a6ac9bb6 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -770,6 +770,40 @@ static int drbd_may_do_local_read(struct drbd_conf *mdev, sector_t sector, int s | |||
770 | return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); | 770 | return 0 == drbd_bm_count_bits(mdev, sbnr, ebnr); |
771 | } | 771 | } |
772 | 772 | ||
773 | static void maybe_pull_ahead(struct drbd_conf *mdev) | ||
774 | { | ||
775 | int congested = 0; | ||
776 | |||
777 | /* If I don't even have good local storage, we can not reasonably try | ||
778 | * to pull ahead of the peer. We also need the local reference to make | ||
779 | * sure mdev->act_log is there. | ||
780 | * Note: caller has to make sure that net_conf is there. | ||
781 | */ | ||
782 | if (!get_ldev_if_state(mdev, D_UP_TO_DATE)) | ||
783 | return; | ||
784 | |||
785 | if (mdev->net_conf->cong_fill && | ||
786 | atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) { | ||
787 | dev_info(DEV, "Congestion-fill threshold reached\n"); | ||
788 | congested = 1; | ||
789 | } | ||
790 | |||
791 | if (mdev->act_log->used >= mdev->net_conf->cong_extents) { | ||
792 | dev_info(DEV, "Congestion-extents threshold reached\n"); | ||
793 | congested = 1; | ||
794 | } | ||
795 | |||
796 | if (congested) { | ||
797 | queue_barrier(mdev); /* last barrier, after mirrored writes */ | ||
798 | |||
799 | if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) | ||
800 | _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); | ||
801 | else /*mdev->net_conf->on_congestion == OC_DISCONNECT */ | ||
802 | _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL); | ||
803 | } | ||
804 | put_ldev(mdev); | ||
805 | } | ||
806 | |||
773 | static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) | 807 | static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) |
774 | { | 808 | { |
775 | const int rw = bio_rw(bio); | 809 | const int rw = bio_rw(bio); |
@@ -977,29 +1011,8 @@ allocate_barrier: | |||
977 | _req_mod(req, queue_for_send_oos); | 1011 | _req_mod(req, queue_for_send_oos); |
978 | 1012 | ||
979 | if (remote && | 1013 | if (remote && |
980 | mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) { | 1014 | mdev->net_conf->on_congestion != OC_BLOCK && mdev->agreed_pro_version >= 96) |
981 | int congested = 0; | 1015 | maybe_pull_ahead(mdev); |
982 | |||
983 | if (mdev->net_conf->cong_fill && | ||
984 | atomic_read(&mdev->ap_in_flight) >= mdev->net_conf->cong_fill) { | ||
985 | dev_info(DEV, "Congestion-fill threshold reached\n"); | ||
986 | congested = 1; | ||
987 | } | ||
988 | |||
989 | if (mdev->act_log->used >= mdev->net_conf->cong_extents) { | ||
990 | dev_info(DEV, "Congestion-extents threshold reached\n"); | ||
991 | congested = 1; | ||
992 | } | ||
993 | |||
994 | if (congested) { | ||
995 | queue_barrier(mdev); /* last barrier, after mirrored writes */ | ||
996 | |||
997 | if (mdev->net_conf->on_congestion == OC_PULL_AHEAD) | ||
998 | _drbd_set_state(_NS(mdev, conn, C_AHEAD), 0, NULL); | ||
999 | else /*mdev->net_conf->on_congestion == OC_DISCONNECT */ | ||
1000 | _drbd_set_state(_NS(mdev, conn, C_DISCONNECTING), 0, NULL); | ||
1001 | } | ||
1002 | } | ||
1003 | 1016 | ||
1004 | spin_unlock_irq(&mdev->req_lock); | 1017 | spin_unlock_irq(&mdev->req_lock); |
1005 | kfree(b); /* if someone else has beaten us to it... */ | 1018 | kfree(b); /* if someone else has beaten us to it... */ |