From 0a27f9d6fc4d185ef66cbaffdda8fd3c8c677eac Mon Sep 17 00:00:00 2001 From: sephe Date: Wed, 15 Jun 2016 09:39:41 +0000 Subject: [PATCH] MFC 297219 hyperv/vmbus: use a better retry method in hv_vmbus_post_message() Most often, hv_vmbus_post_message() doesn't fail. However, it fails intermittently when GPADLs of large shared memory is to be established with the host, e.g. on the hn(4) attach path: a GPADL of 15MB sendbuf is created, for which lots of messages will be flooded to the host. The host side tries to throttle the message rate by returning HV_STATUS_INSUFFICIENT_BUFFERS. Before this commit, we do several retries for failed messages, but the delay between each retry is pretty/too low, which will cause sporadic message posting failure. We now use large delay (>=1ms) between each retry to fix the message posting failure. Submitted by: Dexuan Cui Reviewed by: sephe MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D5715 git-svn-id: svn://svn.freebsd.org/base/stable/10@301924 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- sys/dev/hyperv/vmbus/hv_connection.c | 40 +++++++++++++++------------- sys/dev/hyperv/vmbus/hv_vmbus_priv.h | 1 + 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/sys/dev/hyperv/vmbus/hv_connection.c b/sys/dev/hyperv/vmbus/hv_connection.c index fb1879d6f..facb797dd 100644 --- a/sys/dev/hyperv/vmbus/hv_connection.c +++ b/sys/dev/hyperv/vmbus/hv_connection.c @@ -367,31 +367,35 @@ hv_vmbus_on_events(int cpu) /** * Send a msg on the vmbus's message connection */ -int hv_vmbus_post_message(void *buffer, size_t bufferLen) { - int ret = 0; +int hv_vmbus_post_message(void *buffer, size_t bufferLen) +{ hv_vmbus_connection_id connId; - unsigned retries = 0; + sbintime_t time = SBT_1MS; + int retries; + int ret; - /* NetScaler delays from previous code were consolidated here */ - static int delayAmount[] = {100, 100, 100, 500, 500, 5000, 5000, 5000}; + connId.as_uint32_t = 0; + connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID; - /* for(each entry in delayAmount) try to post message, - * delay a little bit before retrying + /* + * We retry to cope with transient failures caused by host side's + * insufficient resources. 20 times should suffice in practice. */ - for (retries = 0; - retries < sizeof(delayAmount)/sizeof(delayAmount[0]); retries++) { - connId.as_uint32_t = 0; - connId.u.id = HV_VMBUS_MESSAGE_CONNECTION_ID; - ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, bufferLen); - if (ret != HV_STATUS_INSUFFICIENT_BUFFERS) - break; - /* TODO: KYS We should use a blocking wait call */ - DELAY(delayAmount[retries]); + for (retries = 0; retries < 20; retries++) { + ret = hv_vmbus_post_msg_via_msg_ipc(connId, 1, buffer, + bufferLen); + if (ret == HV_STATUS_SUCCESS) + return (0); + + pause_sbt("pstmsg", time, 0, C_HARDCLOCK); + if (time < SBT_1S * 2) + time *= 2; } - KASSERT(ret == 0, ("Error VMBUS: Message Post Failed\n")); + KASSERT(ret == HV_STATUS_SUCCESS, + ("Error VMBUS: Message Post Failed, ret=%d\n", ret)); - return (ret); + return (EAGAIN); } /** diff --git a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h index 62fa22a99..6b9329b98 100644 --- a/sys/dev/hyperv/vmbus/hv_vmbus_priv.h +++ b/sys/dev/hyperv/vmbus/hv_vmbus_priv.h @@ -70,6 +70,7 @@ typedef uint16_t hv_vmbus_status; * You did not supply enough message buffers to send a message. */ +#define HV_STATUS_SUCCESS ((uint16_t)0) #define HV_STATUS_INSUFFICIENT_BUFFERS ((uint16_t)0x0013) typedef void (*hv_vmbus_channel_callback)(void *context); -- 2.45.0