diff options
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 4 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 33 |
2 files changed, 28 insertions, 9 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 4b97f30bb7c6..c194348a46ed 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -2223,7 +2223,7 @@ static inline int __inc_ap_bio_cond(struct drbd_conf *mdev) | |||
2223 | /* I'd like to use wait_event_lock_irq, | 2223 | /* I'd like to use wait_event_lock_irq, |
2224 | * but I'm not sure when it got introduced, | 2224 | * but I'm not sure when it got introduced, |
2225 | * and not sure when it has 3 or 4 arguments */ | 2225 | * and not sure when it has 3 or 4 arguments */ |
2226 | static inline void inc_ap_bio(struct drbd_conf *mdev, int one_or_two) | 2226 | static inline void inc_ap_bio(struct drbd_conf *mdev, int count) |
2227 | { | 2227 | { |
2228 | /* compare with after_state_ch, | 2228 | /* compare with after_state_ch, |
2229 | * os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S */ | 2229 | * os.conn != C_WF_BITMAP_S && ns.conn == C_WF_BITMAP_S */ |
@@ -2245,7 +2245,7 @@ static inline void inc_ap_bio(struct drbd_conf *mdev, int one_or_two) | |||
2245 | finish_wait(&mdev->misc_wait, &wait); | 2245 | finish_wait(&mdev->misc_wait, &wait); |
2246 | spin_lock_irq(&mdev->req_lock); | 2246 | spin_lock_irq(&mdev->req_lock); |
2247 | } | 2247 | } |
2248 | atomic_add(one_or_two, &mdev->ap_bio_cnt); | 2248 | atomic_add(count, &mdev->ap_bio_cnt); |
2249 | spin_unlock_irq(&mdev->req_lock); | 2249 | spin_unlock_irq(&mdev->req_lock); |
2250 | } | 2250 | } |
2251 | 2251 | ||
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 343e0e6dd532..3397f11d0ba9 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -722,6 +722,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) | |||
722 | struct drbd_request *req; | 722 | struct drbd_request *req; |
723 | int local, remote; | 723 | int local, remote; |
724 | int err = -EIO; | 724 | int err = -EIO; |
725 | int ret = 0; | ||
725 | 726 | ||
726 | /* allocate outside of all locks; */ | 727 | /* allocate outside of all locks; */ |
727 | req = drbd_req_new(mdev, bio); | 728 | req = drbd_req_new(mdev, bio); |
@@ -784,7 +785,7 @@ static int drbd_make_request_common(struct drbd_conf *mdev, struct bio *bio) | |||
784 | (mdev->state.pdsk == D_INCONSISTENT && | 785 | (mdev->state.pdsk == D_INCONSISTENT && |
785 | mdev->state.conn >= C_CONNECTED)); | 786 | mdev->state.conn >= C_CONNECTED)); |
786 | 787 | ||
787 | if (!(local || remote)) { | 788 | if (!(local || remote) && !mdev->state.susp) { |
788 | dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); | 789 | dev_err(DEV, "IO ERROR: neither local nor remote disk\n"); |
789 | goto fail_free_complete; | 790 | goto fail_free_complete; |
790 | } | 791 | } |
@@ -810,6 +811,16 @@ allocate_barrier: | |||
810 | /* GOOD, everything prepared, grab the spin_lock */ | 811 | /* GOOD, everything prepared, grab the spin_lock */ |
811 | spin_lock_irq(&mdev->req_lock); | 812 | spin_lock_irq(&mdev->req_lock); |
812 | 813 | ||
814 | if (mdev->state.susp) { | ||
815 | /* If we got suspended, use the retry mechanism of | ||
816 | generic_make_request() to restart processing of this | ||
817 | bio. In the next call to drbd_make_request_26 | ||
818 | we sleep in inc_ap_bio() */ | ||
819 | ret = 1; | ||
820 | spin_unlock_irq(&mdev->req_lock); | ||
821 | goto fail_free_complete; | ||
822 | } | ||
823 | |||
813 | if (remote) { | 824 | if (remote) { |
814 | remote = (mdev->state.pdsk == D_UP_TO_DATE || | 825 | remote = (mdev->state.pdsk == D_UP_TO_DATE || |
815 | (mdev->state.pdsk == D_INCONSISTENT && | 826 | (mdev->state.pdsk == D_INCONSISTENT && |
@@ -947,12 +958,14 @@ fail_and_free_req: | |||
947 | req->private_bio = NULL; | 958 | req->private_bio = NULL; |
948 | put_ldev(mdev); | 959 | put_ldev(mdev); |
949 | } | 960 | } |
950 | bio_endio(bio, err); | 961 | if (!ret) |
962 | bio_endio(bio, err); | ||
963 | |||
951 | drbd_req_free(req); | 964 | drbd_req_free(req); |
952 | dec_ap_bio(mdev); | 965 | dec_ap_bio(mdev); |
953 | kfree(b); | 966 | kfree(b); |
954 | 967 | ||
955 | return 0; | 968 | return ret; |
956 | } | 969 | } |
957 | 970 | ||
958 | /* helper function for drbd_make_request | 971 | /* helper function for drbd_make_request |
@@ -1065,15 +1078,21 @@ int drbd_make_request_26(struct request_queue *q, struct bio *bio) | |||
1065 | 1078 | ||
1066 | /* we need to get a "reference count" (ap_bio_cnt) | 1079 | /* we need to get a "reference count" (ap_bio_cnt) |
1067 | * to avoid races with the disconnect/reconnect/suspend code. | 1080 | * to avoid races with the disconnect/reconnect/suspend code. |
1068 | * In case we need to split the bio here, we need to get two references | 1081 | * In case we need to split the bio here, we need to get three references |
1069 | * atomically, otherwise we might deadlock when trying to submit the | 1082 | * atomically, otherwise we might deadlock when trying to submit the |
1070 | * second one! */ | 1083 | * second one! */ |
1071 | inc_ap_bio(mdev, 2); | 1084 | inc_ap_bio(mdev, 3); |
1072 | 1085 | ||
1073 | D_ASSERT(e_enr == s_enr + 1); | 1086 | D_ASSERT(e_enr == s_enr + 1); |
1074 | 1087 | ||
1075 | drbd_make_request_common(mdev, &bp->bio1); | 1088 | while (drbd_make_request_common(mdev, &bp->bio1)) |
1076 | drbd_make_request_common(mdev, &bp->bio2); | 1089 | inc_ap_bio(mdev, 1); |
1090 | |||
1091 | while (drbd_make_request_common(mdev, &bp->bio2)) | ||
1092 | inc_ap_bio(mdev, 1); | ||
1093 | |||
1094 | dec_ap_bio(mdev); | ||
1095 | |||
1077 | bio_pair_release(bp); | 1096 | bio_pair_release(bp); |
1078 | } | 1097 | } |
1079 | return 0; | 1098 | return 0; |