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 | |
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')
-rw-r--r-- | drivers/block/drbd/drbd_int.h | 20 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_main.c | 3 | ||||
-rw-r--r-- | drivers/block/drbd/drbd_receiver.c | 96 |
3 files changed, 118 insertions, 1 deletions
diff --git a/drivers/block/drbd/drbd_int.h b/drivers/block/drbd/drbd_int.h index 2409de12f013..fd7615f1e526 100644 --- a/drivers/block/drbd/drbd_int.h +++ b/drivers/block/drbd/drbd_int.h | |||
@@ -209,8 +209,11 @@ enum drbd_packets { | |||
209 | P_RS_IS_IN_SYNC = 0x22, /* meta socket */ | 209 | P_RS_IS_IN_SYNC = 0x22, /* meta socket */ |
210 | P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */ | 210 | P_SYNC_PARAM89 = 0x23, /* data socket, protocol version 89 replacement for P_SYNC_PARAM */ |
211 | P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */ | 211 | P_COMPRESSED_BITMAP = 0x24, /* compressed or otherwise encoded bitmap transfer */ |
212 | /* P_CKPT_FENCE_REQ = 0x25, * currently reserved for protocol D */ | ||
213 | /* P_CKPT_DISABLE_REQ = 0x26, * currently reserved for protocol D */ | ||
214 | P_DELAY_PROBE = 0x27, /* is used on BOTH sockets */ | ||
212 | 215 | ||
213 | P_MAX_CMD = 0x25, | 216 | P_MAX_CMD = 0x28, |
214 | P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ | 217 | P_MAY_IGNORE = 0x100, /* Flag to test if (cmd > P_MAY_IGNORE) ... */ |
215 | P_MAX_OPT_CMD = 0x101, | 218 | P_MAX_OPT_CMD = 0x101, |
216 | 219 | ||
@@ -540,6 +543,18 @@ struct p_compressed_bm { | |||
540 | u8 code[0]; | 543 | u8 code[0]; |
541 | } __packed; | 544 | } __packed; |
542 | 545 | ||
546 | struct p_delay_probe { | ||
547 | struct p_header head; | ||
548 | u32 seq_num; /* sequence number to match the two probe packets */ | ||
549 | u32 offset; /* usecs the probe got sent after the reference time point */ | ||
550 | } __packed; | ||
551 | |||
552 | struct delay_probe { | ||
553 | struct list_head list; | ||
554 | int seq_num; | ||
555 | struct timeval time; | ||
556 | }; | ||
557 | |||
543 | /* DCBP: Drbd Compressed Bitmap Packet ... */ | 558 | /* DCBP: Drbd Compressed Bitmap Packet ... */ |
544 | static inline enum drbd_bitmap_code | 559 | static inline enum drbd_bitmap_code |
545 | DCBP_get_code(struct p_compressed_bm *p) | 560 | DCBP_get_code(struct p_compressed_bm *p) |
@@ -1028,6 +1043,9 @@ struct drbd_conf { | |||
1028 | u64 ed_uuid; /* UUID of the exposed data */ | 1043 | u64 ed_uuid; /* UUID of the exposed data */ |
1029 | struct mutex state_mutex; | 1044 | struct mutex state_mutex; |
1030 | char congestion_reason; /* Why we where congested... */ | 1045 | char congestion_reason; /* Why we where congested... */ |
1046 | struct list_head delay_probes; /* protected by peer_seq_lock */ | ||
1047 | int data_delay; /* Delay of packets on the data-sock behind meta-sock */ | ||
1048 | atomic_t delay_seq; /* To generate sequence numbers of delay probes */ | ||
1031 | }; | 1049 | }; |
1032 | 1050 | ||
1033 | static inline struct drbd_conf *minor_to_mdev(unsigned int minor) | 1051 | static inline struct drbd_conf *minor_to_mdev(unsigned int minor) |
diff --git a/drivers/block/drbd/drbd_main.c b/drivers/block/drbd/drbd_main.c index 7468d2ce7347..3d5fe307a19d 100644 --- a/drivers/block/drbd/drbd_main.c +++ b/drivers/block/drbd/drbd_main.c | |||
@@ -2608,6 +2608,7 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) | |||
2608 | atomic_set(&mdev->net_cnt, 0); | 2608 | atomic_set(&mdev->net_cnt, 0); |
2609 | atomic_set(&mdev->packet_seq, 0); | 2609 | atomic_set(&mdev->packet_seq, 0); |
2610 | atomic_set(&mdev->pp_in_use, 0); | 2610 | atomic_set(&mdev->pp_in_use, 0); |
2611 | atomic_set(&mdev->delay_seq, 0); | ||
2611 | 2612 | ||
2612 | mutex_init(&mdev->md_io_mutex); | 2613 | mutex_init(&mdev->md_io_mutex); |
2613 | mutex_init(&mdev->data.mutex); | 2614 | mutex_init(&mdev->data.mutex); |
@@ -2636,6 +2637,8 @@ void drbd_init_set_defaults(struct drbd_conf *mdev) | |||
2636 | INIT_LIST_HEAD(&mdev->unplug_work.list); | 2637 | INIT_LIST_HEAD(&mdev->unplug_work.list); |
2637 | INIT_LIST_HEAD(&mdev->md_sync_work.list); | 2638 | INIT_LIST_HEAD(&mdev->md_sync_work.list); |
2638 | INIT_LIST_HEAD(&mdev->bm_io_work.w.list); | 2639 | INIT_LIST_HEAD(&mdev->bm_io_work.w.list); |
2640 | INIT_LIST_HEAD(&mdev->delay_probes); | ||
2641 | |||
2639 | mdev->resync_work.cb = w_resync_inactive; | 2642 | mdev->resync_work.cb = w_resync_inactive; |
2640 | mdev->unplug_work.cb = w_send_write_hint; | 2643 | mdev->unplug_work.cb = w_send_write_hint; |
2641 | mdev->md_sync_work.cb = w_md_sync; | 2644 | mdev->md_sync_work.cb = w_md_sync; |
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) |