diff options
Diffstat (limited to 'drivers/block/drbd/drbd_receiver.c')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 113 |
1 files changed, 18 insertions, 95 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index cba1deb7b271..20abef531c99 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -3555,14 +3555,15 @@ static int receive_bitmap(struct drbd_conf *mdev, struct p_header *h) | |||
3555 | return ok; | 3555 | return ok; |
3556 | } | 3556 | } |
3557 | 3557 | ||
3558 | static int receive_skip(struct drbd_conf *mdev, struct p_header *h) | 3558 | static int receive_skip_(struct drbd_conf *mdev, struct p_header *h, int silent) |
3559 | { | 3559 | { |
3560 | /* TODO zero copy sink :) */ | 3560 | /* TODO zero copy sink :) */ |
3561 | static char sink[128]; | 3561 | static char sink[128]; |
3562 | int size, want, r; | 3562 | int size, want, r; |
3563 | 3563 | ||
3564 | dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n", | 3564 | if (!silent) |
3565 | h->command, h->length); | 3565 | dev_warn(DEV, "skipping unknown optional packet type %d, l: %d!\n", |
3566 | h->command, h->length); | ||
3566 | 3567 | ||
3567 | size = h->length; | 3568 | size = h->length; |
3568 | while (size > 0) { | 3569 | while (size > 0) { |
@@ -3574,101 +3575,25 @@ static int receive_skip(struct drbd_conf *mdev, struct p_header *h) | |||
3574 | return size == 0; | 3575 | return size == 0; |
3575 | } | 3576 | } |
3576 | 3577 | ||
3577 | static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) | 3578 | static int receive_skip(struct drbd_conf *mdev, struct p_header *h) |
3578 | { | ||
3579 | if (mdev->state.disk >= D_INCONSISTENT) | ||
3580 | drbd_kick_lo(mdev); | ||
3581 | |||
3582 | /* Make sure we've acked all the TCP data associated | ||
3583 | * with the data requests being unplugged */ | ||
3584 | drbd_tcp_quickack(mdev->data.socket); | ||
3585 | |||
3586 | return TRUE; | ||
3587 | } | ||
3588 | |||
3589 | static void timeval_sub_us(struct timeval* tv, unsigned int us) | ||
3590 | { | 3579 | { |
3591 | tv->tv_sec -= us / 1000000; | 3580 | return receive_skip_(mdev, h, 0); |
3592 | us = us % 1000000; | ||
3593 | if (tv->tv_usec > us) { | ||
3594 | tv->tv_usec += 1000000; | ||
3595 | tv->tv_sec--; | ||
3596 | } | ||
3597 | tv->tv_usec -= us; | ||
3598 | } | 3581 | } |
3599 | 3582 | ||
3600 | static void got_delay_probe(struct drbd_conf *mdev, int from, struct p_delay_probe *p) | 3583 | static int receive_skip_silent(struct drbd_conf *mdev, struct p_header *h) |
3601 | { | 3584 | { |
3602 | struct delay_probe *dp; | 3585 | return receive_skip_(mdev, h, 1); |
3603 | struct list_head *le; | ||
3604 | struct timeval now; | ||
3605 | int seq_num; | ||
3606 | int offset; | ||
3607 | int data_delay; | ||
3608 | |||
3609 | seq_num = be32_to_cpu(p->seq_num); | ||
3610 | offset = be32_to_cpu(p->offset); | ||
3611 | |||
3612 | spin_lock(&mdev->peer_seq_lock); | ||
3613 | if (!list_empty(&mdev->delay_probes)) { | ||
3614 | if (from == USE_DATA_SOCKET) | ||
3615 | le = mdev->delay_probes.next; | ||
3616 | else | ||
3617 | le = mdev->delay_probes.prev; | ||
3618 | |||
3619 | dp = list_entry(le, struct delay_probe, list); | ||
3620 | |||
3621 | if (dp->seq_num == seq_num) { | ||
3622 | list_del(le); | ||
3623 | spin_unlock(&mdev->peer_seq_lock); | ||
3624 | do_gettimeofday(&now); | ||
3625 | timeval_sub_us(&now, offset); | ||
3626 | data_delay = | ||
3627 | now.tv_usec - dp->time.tv_usec + | ||
3628 | (now.tv_sec - dp->time.tv_sec) * 1000000; | ||
3629 | |||
3630 | if (data_delay > 0) | ||
3631 | mdev->data_delay = data_delay; | ||
3632 | |||
3633 | kfree(dp); | ||
3634 | return; | ||
3635 | } | ||
3636 | |||
3637 | if (dp->seq_num > seq_num) { | ||
3638 | spin_unlock(&mdev->peer_seq_lock); | ||
3639 | dev_warn(DEV, "Previous allocation failure of struct delay_probe?\n"); | ||
3640 | return; /* Do not alloca a struct delay_probe.... */ | ||
3641 | } | ||
3642 | } | ||
3643 | spin_unlock(&mdev->peer_seq_lock); | ||
3644 | |||
3645 | dp = kmalloc(sizeof(struct delay_probe), GFP_NOIO); | ||
3646 | if (!dp) { | ||
3647 | dev_warn(DEV, "Failed to allocate a struct delay_probe, do not worry.\n"); | ||
3648 | return; | ||
3649 | } | ||
3650 | |||
3651 | dp->seq_num = seq_num; | ||
3652 | do_gettimeofday(&dp->time); | ||
3653 | timeval_sub_us(&dp->time, offset); | ||
3654 | |||
3655 | spin_lock(&mdev->peer_seq_lock); | ||
3656 | if (from == USE_DATA_SOCKET) | ||
3657 | list_add(&dp->list, &mdev->delay_probes); | ||
3658 | else | ||
3659 | list_add_tail(&dp->list, &mdev->delay_probes); | ||
3660 | spin_unlock(&mdev->peer_seq_lock); | ||
3661 | } | 3586 | } |
3662 | 3587 | ||
3663 | static int receive_delay_probe(struct drbd_conf *mdev, struct p_header *h) | 3588 | static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) |
3664 | { | 3589 | { |
3665 | struct p_delay_probe *p = (struct p_delay_probe *)h; | 3590 | if (mdev->state.disk >= D_INCONSISTENT) |
3591 | drbd_kick_lo(mdev); | ||
3666 | 3592 | ||
3667 | ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; | 3593 | /* Make sure we've acked all the TCP data associated |
3668 | if (drbd_recv(mdev, h->payload, h->length) != h->length) | 3594 | * with the data requests being unplugged */ |
3669 | return FALSE; | 3595 | drbd_tcp_quickack(mdev->data.socket); |
3670 | 3596 | ||
3671 | got_delay_probe(mdev, USE_DATA_SOCKET, p); | ||
3672 | return TRUE; | 3597 | return TRUE; |
3673 | } | 3598 | } |
3674 | 3599 | ||
@@ -3695,7 +3620,7 @@ static drbd_cmd_handler_f drbd_default_handler[] = { | |||
3695 | [P_OV_REQUEST] = receive_DataRequest, | 3620 | [P_OV_REQUEST] = receive_DataRequest, |
3696 | [P_OV_REPLY] = receive_DataRequest, | 3621 | [P_OV_REPLY] = receive_DataRequest, |
3697 | [P_CSUM_RS_REQUEST] = receive_DataRequest, | 3622 | [P_CSUM_RS_REQUEST] = receive_DataRequest, |
3698 | [P_DELAY_PROBE] = receive_delay_probe, | 3623 | [P_DELAY_PROBE] = receive_skip_silent, |
3699 | /* anything missing from this table is in | 3624 | /* anything missing from this table is in |
3700 | * the asender_tbl, see get_asender_cmd */ | 3625 | * the asender_tbl, see get_asender_cmd */ |
3701 | [P_MAX_CMD] = NULL, | 3626 | [P_MAX_CMD] = NULL, |
@@ -4472,11 +4397,9 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header *h) | |||
4472 | return TRUE; | 4397 | return TRUE; |
4473 | } | 4398 | } |
4474 | 4399 | ||
4475 | static int got_delay_probe_m(struct drbd_conf *mdev, struct p_header *h) | 4400 | static int got_something_to_ignore_m(struct drbd_conf *mdev, struct p_header *h) |
4476 | { | 4401 | { |
4477 | struct p_delay_probe *p = (struct p_delay_probe *)h; | 4402 | /* IGNORE */ |
4478 | |||
4479 | got_delay_probe(mdev, USE_META_SOCKET, p); | ||
4480 | return TRUE; | 4403 | return TRUE; |
4481 | } | 4404 | } |
4482 | 4405 | ||
@@ -4504,7 +4427,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) | |||
4504 | [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, | 4427 | [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, |
4505 | [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, | 4428 | [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, |
4506 | [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, | 4429 | [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, |
4507 | [P_DELAY_PROBE] = { sizeof(struct p_delay_probe), got_delay_probe_m }, | 4430 | [P_DELAY_PROBE] = { sizeof(struct p_delay_probe), got_something_to_ignore_m }, |
4508 | [P_MAX_CMD] = { 0, NULL }, | 4431 | [P_MAX_CMD] = { 0, NULL }, |
4509 | }; | 4432 | }; |
4510 | if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) | 4433 | if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) |