diff options
| author | Philipp Reisner <philipp.reisner@linbit.com> | 2010-05-10 10:42:23 -0400 |
|---|---|---|
| committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-05-17 20:03:32 -0400 |
| commit | 9a25a04c8079725c1b1ab756694a8e0757844b40 (patch) | |
| tree | ed8fbbbbd7cb4db7d77531bcd2c046f5bd0170c1 | |
| parent | a1c88d0d7aa2ef427f78834c9a3b0a673a19dca6 (diff) | |
drbd: If we detect late that IO got frozen, retry after we thawed.
If we detect late (= after grabing mdev->req_lock) that IO got frozen, we
return 1 to generic_make_request(), which simply will retry to make a
request for that bio.
In the subsequent call of generic_make_request() into drbd_make_request_26()
we sleep in inc_ap_bio().
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_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; |
