diff options
author | Philipp Reisner <philipp.reisner@linbit.com> | 2010-04-30 09:26:20 -0400 |
---|---|---|
committer | Philipp Reisner <philipp.reisner@linbit.com> | 2010-05-17 19:22:11 -0400 |
commit | 0ced55a3bed25b0e30dcb3c7dce9634ce3c60cf2 (patch) | |
tree | 7c5770c396588432619ecd2af5793a04ca7080b5 /drivers/block/drbd/drbd_receiver.c | |
parent | 5223671bb0315d83f9ad7becbbb9e703aa735bbe (diff) |
drbd: Receiving of delay_probes
Delay_probes are new packets in the DRBD protocol, which allow
DRBD to know the current delay packets have on the data socket.
(relative to the meta data socket)
Signed-off-by: Philipp Reisner <philipp.reisner@linbit.com>
Signed-off-by: Lars Ellenberg <lars.ellenberg@linbit.com>
Diffstat (limited to 'drivers/block/drbd/drbd_receiver.c')
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 96 |
1 files changed, 96 insertions, 0 deletions
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c index b27f4dd36f89..fee0d249adf7 100644 --- a/drivers/block/drbd/drbd_receiver.c +++ b/drivers/block/drbd/drbd_receiver.c | |||
@@ -3501,6 +3501,92 @@ static int receive_UnplugRemote(struct drbd_conf *mdev, struct p_header *h) | |||
3501 | return TRUE; | 3501 | return TRUE; |
3502 | } | 3502 | } |
3503 | 3503 | ||
3504 | static void timeval_sub_us(struct timeval* tv, unsigned int us) | ||
3505 | { | ||
3506 | tv->tv_sec -= us / 1000000; | ||
3507 | us = us % 1000000; | ||
3508 | if (tv->tv_usec > us) { | ||
3509 | tv->tv_usec += 1000000; | ||
3510 | tv->tv_sec--; | ||
3511 | } | ||
3512 | tv->tv_usec -= us; | ||
3513 | } | ||
3514 | |||
3515 | static void got_delay_probe(struct drbd_conf *mdev, int from, struct p_delay_probe *p) | ||
3516 | { | ||
3517 | struct delay_probe *dp; | ||
3518 | struct list_head *le; | ||
3519 | struct timeval now; | ||
3520 | int seq_num; | ||
3521 | int offset; | ||
3522 | int data_delay; | ||
3523 | |||
3524 | seq_num = be32_to_cpu(p->seq_num); | ||
3525 | offset = be32_to_cpu(p->offset); | ||
3526 | |||
3527 | spin_lock(&mdev->peer_seq_lock); | ||
3528 | if (!list_empty(&mdev->delay_probes)) { | ||
3529 | if (from == USE_DATA_SOCKET) | ||
3530 | le = mdev->delay_probes.next; | ||
3531 | else | ||
3532 | le = mdev->delay_probes.prev; | ||
3533 | |||
3534 | dp = list_entry(le, struct delay_probe, list); | ||
3535 | |||
3536 | if (dp->seq_num == seq_num) { | ||
3537 | list_del(le); | ||
3538 | spin_unlock(&mdev->peer_seq_lock); | ||
3539 | do_gettimeofday(&now); | ||
3540 | timeval_sub_us(&now, offset); | ||
3541 | data_delay = | ||
3542 | now.tv_usec - dp->time.tv_usec + | ||
3543 | (now.tv_sec - dp->time.tv_sec) * 1000000; | ||
3544 | |||
3545 | if (data_delay > 0) | ||
3546 | mdev->data_delay = data_delay; | ||
3547 | |||
3548 | kfree(dp); | ||
3549 | return; | ||
3550 | } | ||
3551 | |||
3552 | if (dp->seq_num > seq_num) { | ||
3553 | spin_unlock(&mdev->peer_seq_lock); | ||
3554 | dev_warn(DEV, "Previous allocation failure of struct delay_probe?\n"); | ||
3555 | return; /* Do not alloca a struct delay_probe.... */ | ||
3556 | } | ||
3557 | } | ||
3558 | spin_unlock(&mdev->peer_seq_lock); | ||
3559 | |||
3560 | dp = kmalloc(sizeof(struct delay_probe), GFP_NOIO); | ||
3561 | if (!dp) { | ||
3562 | dev_warn(DEV, "Failed to allocate a struct delay_probe, do not worry.\n"); | ||
3563 | return; | ||
3564 | } | ||
3565 | |||
3566 | dp->seq_num = seq_num; | ||
3567 | do_gettimeofday(&dp->time); | ||
3568 | timeval_sub_us(&dp->time, offset); | ||
3569 | |||
3570 | spin_lock(&mdev->peer_seq_lock); | ||
3571 | if (from == USE_DATA_SOCKET) | ||
3572 | list_add(&dp->list, &mdev->delay_probes); | ||
3573 | else | ||
3574 | list_add_tail(&dp->list, &mdev->delay_probes); | ||
3575 | spin_unlock(&mdev->peer_seq_lock); | ||
3576 | } | ||
3577 | |||
3578 | static int receive_delay_probe(struct drbd_conf *mdev, struct p_header *h) | ||
3579 | { | ||
3580 | struct p_delay_probe *p = (struct p_delay_probe *)h; | ||
3581 | |||
3582 | ERR_IF(h->length != (sizeof(*p)-sizeof(*h))) return FALSE; | ||
3583 | if (drbd_recv(mdev, h->payload, h->length) != h->length) | ||
3584 | return FALSE; | ||
3585 | |||
3586 | got_delay_probe(mdev, USE_DATA_SOCKET, p); | ||
3587 | return TRUE; | ||
3588 | } | ||
3589 | |||
3504 | typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header *); | 3590 | typedef int (*drbd_cmd_handler_f)(struct drbd_conf *, struct p_header *); |
3505 | 3591 | ||
3506 | static drbd_cmd_handler_f drbd_default_handler[] = { | 3592 | static drbd_cmd_handler_f drbd_default_handler[] = { |
@@ -3524,6 +3610,7 @@ static drbd_cmd_handler_f drbd_default_handler[] = { | |||
3524 | [P_OV_REQUEST] = receive_DataRequest, | 3610 | [P_OV_REQUEST] = receive_DataRequest, |
3525 | [P_OV_REPLY] = receive_DataRequest, | 3611 | [P_OV_REPLY] = receive_DataRequest, |
3526 | [P_CSUM_RS_REQUEST] = receive_DataRequest, | 3612 | [P_CSUM_RS_REQUEST] = receive_DataRequest, |
3613 | [P_DELAY_PROBE] = receive_delay_probe, | ||
3527 | /* anything missing from this table is in | 3614 | /* anything missing from this table is in |
3528 | * the asender_tbl, see get_asender_cmd */ | 3615 | * the asender_tbl, see get_asender_cmd */ |
3529 | [P_MAX_CMD] = NULL, | 3616 | [P_MAX_CMD] = NULL, |
@@ -4300,6 +4387,14 @@ static int got_OVResult(struct drbd_conf *mdev, struct p_header *h) | |||
4300 | return TRUE; | 4387 | return TRUE; |
4301 | } | 4388 | } |
4302 | 4389 | ||
4390 | static int got_delay_probe_m(struct drbd_conf *mdev, struct p_header *h) | ||
4391 | { | ||
4392 | struct p_delay_probe *p = (struct p_delay_probe *)h; | ||
4393 | |||
4394 | got_delay_probe(mdev, USE_META_SOCKET, p); | ||
4395 | return TRUE; | ||
4396 | } | ||
4397 | |||
4303 | struct asender_cmd { | 4398 | struct asender_cmd { |
4304 | size_t pkt_size; | 4399 | size_t pkt_size; |
4305 | int (*process)(struct drbd_conf *mdev, struct p_header *h); | 4400 | int (*process)(struct drbd_conf *mdev, struct p_header *h); |
@@ -4324,6 +4419,7 @@ static struct asender_cmd *get_asender_cmd(int cmd) | |||
4324 | [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, | 4419 | [P_BARRIER_ACK] = { sizeof(struct p_barrier_ack), got_BarrierAck }, |
4325 | [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, | 4420 | [P_STATE_CHG_REPLY] = { sizeof(struct p_req_state_reply), got_RqSReply }, |
4326 | [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, | 4421 | [P_RS_IS_IN_SYNC] = { sizeof(struct p_block_ack), got_IsInSync }, |
4422 | [P_DELAY_PROBE] = { sizeof(struct p_delay_probe), got_delay_probe_m }, | ||
4327 | [P_MAX_CMD] = { 0, NULL }, | 4423 | [P_MAX_CMD] = { 0, NULL }, |
4328 | }; | 4424 | }; |
4329 | if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) | 4425 | if (cmd > P_MAX_CMD || asender_tbl[cmd].process == NULL) |