aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLars Ellenberg <lars.ellenberg@linbit.com>2012-06-08 08:17:36 -0400
committerPhilipp Reisner <philipp.reisner@linbit.com>2012-06-12 08:35:19 -0400
commit0d5934e3c258fc5decc4103600c597086fd95a52 (patch)
tree1e9810b23c495ffed5f9d1814ea74535b6013ea5 /drivers
parent1ed25b269e3dd5ecc64f17beef9ea21745c39ca6 (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.c59
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
773static 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
773static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio, unsigned long start_time) 807static 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... */