diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2011-03-01 05:08:28 -0500 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2011-03-10 05:48:16 -0500 |
commit | 7fde2be93080c028c20078a2d6abec8a95891192 (patch) | |
tree | 47993e3c52d550d22ab8035de94d526d226bc2e6 | |
parent | c5a91619793d444e5103ec5841045bf878718398 (diff) |
drbd: Implemented real timeout checking for request processing time
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 | 1 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 3 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 3 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.c | 39 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_req.h | 1 |
5 files changed, 47 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 267d9897ca8c..81030d8d654b 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -990,6 +990,7 @@ struct drbd_conf { | |||
990 | struct timer_list resync_timer; | 990 | struct timer_list resync_timer; |
991 | struct timer_list md_sync_timer; | 991 | struct timer_list md_sync_timer; |
992 | struct timer_list start_resync_timer; | 992 | struct timer_list start_resync_timer; |
993 | struct timer_list request_timer; | ||
993 | #ifdef DRBD_DEBUG_MD_SYNC | 994 | #ifdef DRBD_DEBUG_MD_SYNC |
994 | struct { | 995 | struct { |
995 | unsigned int line; | 996 | unsigned int line; |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 9043772de400..dfc85f32d317 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -3017,12 +3017,15 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) | |||
3017 | init_timer(&mdev->resync_timer); | 3017 | init_timer(&mdev->resync_timer); |
3018 | init_timer(&mdev->md_sync_timer); | 3018 | init_timer(&mdev->md_sync_timer); |
3019 | init_timer(&mdev->start_resync_timer); | 3019 | init_timer(&mdev->start_resync_timer); |
3020 | init_timer(&mdev->request_timer); | ||
3020 | mdev->resync_timer.function = resync_timer_fn; | 3021 | mdev->resync_timer.function = resync_timer_fn; |
3021 | mdev->resync_timer.data = (unsigned long) mdev; | 3022 | mdev->resync_timer.data = (unsigned long) mdev; |
3022 | mdev->md_sync_timer.function = md_sync_timer_fn; | 3023 | mdev->md_sync_timer.function = md_sync_timer_fn; |
3023 | mdev->md_sync_timer.data = (unsigned long) mdev; | 3024 | mdev->md_sync_timer.data = (unsigned long) mdev; |
3024 | mdev->start_resync_timer.function = start_resync_timer_fn; | 3025 | mdev->start_resync_timer.function = start_resync_timer_fn; |
3025 | mdev->start_resync_timer.data = (unsigned long) mdev; | 3026 | mdev->start_resync_timer.data = (unsigned long) mdev; |
3027 | mdev->request_timer.function = request_timer_fn; | ||
3028 | mdev->request_timer.data = (unsigned long) mdev; | ||
3026 | 3029 | ||
3027 | init_waitqueue_head(&mdev->misc_wait); | 3030 | init_waitqueue_head(&mdev->misc_wait); |
3028 | init_waitqueue_head(&mdev->state_wait); | 3031 | init_waitqueue_head(&mdev->state_wait); |
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index 3d62ac7cdc4a..fe1564c7d8b6 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -912,6 +912,7 @@ retry: | |||
912 | drbd_send_state(mdev); | 912 | drbd_send_state(mdev); |
913 | clear_bit(USE_DEGR_WFC_T, &mdev->flags); | 913 | clear_bit(USE_DEGR_WFC_T, &mdev->flags); |
914 | clear_bit(RESIZE_PENDING, &mdev->flags); | 914 | clear_bit(RESIZE_PENDING, &mdev->flags); |
915 | mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */ | ||
915 | 916 | ||
916 | return 1; | 917 | return 1; |
917 | 918 | ||
@@ -3822,6 +3823,8 @@ static void drbd_disconnect(struct drbd_conf *mdev) | |||
3822 | atomic_set(&mdev->rs_pending_cnt, 0); | 3823 | atomic_set(&mdev->rs_pending_cnt, 0); |
3823 | wake_up(&mdev->misc_wait); | 3824 | wake_up(&mdev->misc_wait); |
3824 | 3825 | ||
3826 | del_timer(&mdev->request_timer); | ||
3827 | |||
3825 | /* make sure syncer is stopped and w_resume_next_sg queued */ | 3828 | /* make sure syncer is stopped and w_resume_next_sg queued */ |
3826 | del_timer_sync(&mdev->resync_timer); | 3829 | del_timer_sync(&mdev->resync_timer); |
3827 | resync_timer_fn((unsigned long)mdev); | 3830 | resync_timer_fn((unsigned long)mdev); |
diff --git a/drivers/block/drbd/drbd_req.c b/drivers/block/drbd/drbd_req.c index 94fd5a2be559..c2cc28a55907 100644 --- a/drivers/block/drbd/drbd_req.c +++ b/drivers/block/drbd/drbd_req.c | |||
@@ -1194,3 +1194,42 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct | |||
1194 | } | 1194 | } |
1195 | return limit; | 1195 | return limit; |
1196 | } | 1196 | } |
1197 | |||
1198 | void request_timer_fn(unsigned long data) | ||
1199 | { | ||
1200 | struct drbd_conf *mdev = (struct drbd_conf *) data; | ||
1201 | struct drbd_request *req; /* oldest request */ | ||
1202 | struct list_head *le; | ||
1203 | unsigned long et = 0; /* effective timeout = ko_count * timeout */ | ||
1204 | |||
1205 | if (get_net_conf(mdev)) { | ||
1206 | et = mdev->net_conf->timeout*HZ/10 * mdev->net_conf->ko_count; | ||
1207 | put_net_conf(mdev); | ||
1208 | } | ||
1209 | if (!et || mdev->state.conn < C_WF_REPORT_PARAMS) | ||
1210 | return; /* Recurring timer stopped */ | ||
1211 | |||
1212 | spin_lock_irq(&mdev->req_lock); | ||
1213 | le = &mdev->oldest_tle->requests; | ||
1214 | if (list_empty(le)) { | ||
1215 | spin_unlock_irq(&mdev->req_lock); | ||
1216 | mod_timer(&mdev->request_timer, jiffies + et); | ||
1217 | return; | ||
1218 | } | ||
1219 | |||
1220 | le = le->prev; | ||
1221 | req = list_entry(le, struct drbd_request, tl_requests); | ||
1222 | if (time_is_before_eq_jiffies(req->start_time + et)) { | ||
1223 | if (req->rq_state & RQ_NET_PENDING) { | ||
1224 | dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n"); | ||
1225 | _drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE, NULL); | ||
1226 | } else { | ||
1227 | dev_warn(DEV, "Local backing block device frozen?\n"); | ||
1228 | mod_timer(&mdev->request_timer, jiffies + et); | ||
1229 | } | ||
1230 | } else { | ||
1231 | mod_timer(&mdev->request_timer, req->start_time + et); | ||
1232 | } | ||
1233 | |||
1234 | spin_unlock_irq(&mdev->req_lock); | ||
1235 | } | ||
diff --git a/drivers/block/drbd/drbd_req.h b/drivers/block/drbd/drbd_req.h index 32c1f2a31266..32e2c3e6a813 100644 --- a/drivers/block/drbd/drbd_req.h +++ b/drivers/block/drbd/drbd_req.h | |||
@@ -322,6 +322,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what, | |||
322 | struct bio_and_error *m); | 322 | struct bio_and_error *m); |
323 | extern void complete_master_bio(struct drbd_conf *mdev, | 323 | extern void complete_master_bio(struct drbd_conf *mdev, |
324 | struct bio_and_error *m); | 324 | struct bio_and_error *m); |
325 | extern void request_timer_fn(unsigned long data); | ||
325 | 326 | ||
326 | /* use this if you don't want to deal with calling complete_master_bio() | 327 | /* use this if you don't want to deal with calling complete_master_bio() |
327 | * outside the spinlock, e.g. when walking some list on cleanup. */ | 328 | * outside the spinlock, e.g. when walking some list on cleanup. */ |