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>
This commit is contained in:
Philipp Reisner 2011-03-01 11:08:28 +01:00
parent c5a9161979
commit 7fde2be930
5 changed files with 47 additions and 0 deletions

View File

@ -990,6 +990,7 @@ struct drbd_conf {
struct timer_list resync_timer;
struct timer_list md_sync_timer;
struct timer_list start_resync_timer;
struct timer_list request_timer;
#ifdef DRBD_DEBUG_MD_SYNC
struct {
unsigned int line;

View File

@ -3017,12 +3017,15 @@ void drbd_init_set_defaults(struct drbd_conf *mdev)
init_timer(&mdev->resync_timer);
init_timer(&mdev->md_sync_timer);
init_timer(&mdev->start_resync_timer);
init_timer(&mdev->request_timer);
mdev->resync_timer.function = resync_timer_fn;
mdev->resync_timer.data = (unsigned long) mdev;
mdev->md_sync_timer.function = md_sync_timer_fn;
mdev->md_sync_timer.data = (unsigned long) mdev;
mdev->start_resync_timer.function = start_resync_timer_fn;
mdev->start_resync_timer.data = (unsigned long) mdev;
mdev->request_timer.function = request_timer_fn;
mdev->request_timer.data = (unsigned long) mdev;
init_waitqueue_head(&mdev->misc_wait);
init_waitqueue_head(&mdev->state_wait);

View File

@ -912,6 +912,7 @@ static int drbd_connect(struct drbd_conf *mdev)
drbd_send_state(mdev);
clear_bit(USE_DEGR_WFC_T, &mdev->flags);
clear_bit(RESIZE_PENDING, &mdev->flags);
mod_timer(&mdev->request_timer, jiffies + HZ); /* just start it here. */
return 1;
@ -3822,6 +3823,8 @@ static void drbd_disconnect(struct drbd_conf *mdev)
atomic_set(&mdev->rs_pending_cnt, 0);
wake_up(&mdev->misc_wait);
del_timer(&mdev->request_timer);
/* make sure syncer is stopped and w_resume_next_sg queued */
del_timer_sync(&mdev->resync_timer);
resync_timer_fn((unsigned long)mdev);

View File

@ -1194,3 +1194,42 @@ int drbd_merge_bvec(struct request_queue *q, struct bvec_merge_data *bvm, struct
}
return limit;
}
void request_timer_fn(unsigned long data)
{
struct drbd_conf *mdev = (struct drbd_conf *) data;
struct drbd_request *req; /* oldest request */
struct list_head *le;
unsigned long et = 0; /* effective timeout = ko_count * timeout */
if (get_net_conf(mdev)) {
et = mdev->net_conf->timeout*HZ/10 * mdev->net_conf->ko_count;
put_net_conf(mdev);
}
if (!et || mdev->state.conn < C_WF_REPORT_PARAMS)
return; /* Recurring timer stopped */
spin_lock_irq(&mdev->req_lock);
le = &mdev->oldest_tle->requests;
if (list_empty(le)) {
spin_unlock_irq(&mdev->req_lock);
mod_timer(&mdev->request_timer, jiffies + et);
return;
}
le = le->prev;
req = list_entry(le, struct drbd_request, tl_requests);
if (time_is_before_eq_jiffies(req->start_time + et)) {
if (req->rq_state & RQ_NET_PENDING) {
dev_warn(DEV, "Remote failed to finish a request within ko-count * timeout\n");
_drbd_set_state(_NS(mdev, conn, C_TIMEOUT), CS_VERBOSE, NULL);
} else {
dev_warn(DEV, "Local backing block device frozen?\n");
mod_timer(&mdev->request_timer, jiffies + et);
}
} else {
mod_timer(&mdev->request_timer, req->start_time + et);
}
spin_unlock_irq(&mdev->req_lock);
}

View File

@ -322,6 +322,7 @@ extern int __req_mod(struct drbd_request *req, enum drbd_req_event what,
struct bio_and_error *m);
extern void complete_master_bio(struct drbd_conf *mdev,
struct bio_and_error *m);
extern void request_timer_fn(unsigned long data);
/* use this if you don't want to deal with calling complete_master_bio()
* outside the spinlock, e.g. when walking some list on cleanup. */