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 <decui microsoft com> Reviewed by: sephe MFC after: 1 week Sponsored by: Microsoft OSTC Differential Revision: https://reviews.freebsd.org/D5715
This commit is contained in:
parent
7a2c1d8c60
commit
25a40f12b0
@ -364,31 +364,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user