Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Drivers: hv: vmbus: Drivers: hv: vmbus: Introduce CHANNELMSG_MODIFYCHANNEL_RESPONSE

Introduce the CHANNELMSG_MODIFYCHANNEL_RESPONSE message type, and code
to receive and process such a message.

Signed-off-by: Andrea Parri (Microsoft) <parri.andrea@gmail.com>
Reviewed-by: Michael Kelley <mikelley@microsoft.com>
Link: https://lore.kernel.org/r/20210416143449.16185-3-parri.andrea@gmail.com
Signed-off-by: Wei Liu <wei.liu@kernel.org>

authored by

Andrea Parri (Microsoft) and committed by
Wei Liu
870ced05 1df53d21

+152 -19
+82 -17
drivers/hv/channel.c
··· 209 209 } 210 210 EXPORT_SYMBOL_GPL(vmbus_send_tl_connect_request); 211 211 212 + static int send_modifychannel_without_ack(struct vmbus_channel *channel, u32 target_vp) 213 + { 214 + struct vmbus_channel_modifychannel msg; 215 + int ret; 216 + 217 + memset(&msg, 0, sizeof(msg)); 218 + msg.header.msgtype = CHANNELMSG_MODIFYCHANNEL; 219 + msg.child_relid = channel->offermsg.child_relid; 220 + msg.target_vp = target_vp; 221 + 222 + ret = vmbus_post_msg(&msg, sizeof(msg), true); 223 + trace_vmbus_send_modifychannel(&msg, ret); 224 + 225 + return ret; 226 + } 227 + 228 + static int send_modifychannel_with_ack(struct vmbus_channel *channel, u32 target_vp) 229 + { 230 + struct vmbus_channel_modifychannel *msg; 231 + struct vmbus_channel_msginfo *info; 232 + unsigned long flags; 233 + int ret; 234 + 235 + info = kzalloc(sizeof(struct vmbus_channel_msginfo) + 236 + sizeof(struct vmbus_channel_modifychannel), 237 + GFP_KERNEL); 238 + if (!info) 239 + return -ENOMEM; 240 + 241 + init_completion(&info->waitevent); 242 + info->waiting_channel = channel; 243 + 244 + msg = (struct vmbus_channel_modifychannel *)info->msg; 245 + msg->header.msgtype = CHANNELMSG_MODIFYCHANNEL; 246 + msg->child_relid = channel->offermsg.child_relid; 247 + msg->target_vp = target_vp; 248 + 249 + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 250 + list_add_tail(&info->msglistentry, &vmbus_connection.chn_msg_list); 251 + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 252 + 253 + ret = vmbus_post_msg(msg, sizeof(*msg), true); 254 + trace_vmbus_send_modifychannel(msg, ret); 255 + if (ret != 0) { 256 + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 257 + list_del(&info->msglistentry); 258 + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 259 + goto free_info; 260 + } 261 + 262 + /* 263 + * Release channel_mutex; otherwise, vmbus_onoffer_rescind() could block on 264 + * the mutex and be unable to signal the completion. 265 + * 266 + * See the caller target_cpu_store() for information about the usage of the 267 + * mutex. 268 + */ 269 + mutex_unlock(&vmbus_connection.channel_mutex); 270 + wait_for_completion(&info->waitevent); 271 + mutex_lock(&vmbus_connection.channel_mutex); 272 + 273 + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 274 + list_del(&info->msglistentry); 275 + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 276 + 277 + if (info->response.modify_response.status) 278 + ret = -EAGAIN; 279 + 280 + free_info: 281 + kfree(info); 282 + return ret; 283 + } 284 + 212 285 /* 213 286 * Set/change the vCPU (@target_vp) the channel (@child_relid) will interrupt. 214 287 * 215 - * CHANNELMSG_MODIFYCHANNEL messages are aynchronous. Also, Hyper-V does not 216 - * ACK such messages. IOW we can't know when the host will stop interrupting 217 - * the "old" vCPU and start interrupting the "new" vCPU for the given channel. 288 + * CHANNELMSG_MODIFYCHANNEL messages are aynchronous. When VMbus version 5.3 289 + * or later is negotiated, Hyper-V always sends an ACK in response to such a 290 + * message. For VMbus version 5.2 and earlier, it never sends an ACK. With- 291 + * out an ACK, we can not know when the host will stop interrupting the "old" 292 + * vCPU and start interrupting the "new" vCPU for the given channel. 218 293 * 219 294 * The CHANNELMSG_MODIFYCHANNEL message type is supported since VMBus version 220 295 * VERSION_WIN10_V4_1. 221 296 */ 222 - int vmbus_send_modifychannel(u32 child_relid, u32 target_vp) 297 + int vmbus_send_modifychannel(struct vmbus_channel *channel, u32 target_vp) 223 298 { 224 - struct vmbus_channel_modifychannel conn_msg; 225 - int ret; 226 - 227 - memset(&conn_msg, 0, sizeof(conn_msg)); 228 - conn_msg.header.msgtype = CHANNELMSG_MODIFYCHANNEL; 229 - conn_msg.child_relid = child_relid; 230 - conn_msg.target_vp = target_vp; 231 - 232 - ret = vmbus_post_msg(&conn_msg, sizeof(conn_msg), true); 233 - 234 - trace_vmbus_send_modifychannel(&conn_msg, ret); 235 - 236 - return ret; 299 + if (vmbus_proto_version >= VERSION_WIN10_V5_3) 300 + return send_modifychannel_with_ack(channel, target_vp); 301 + return send_modifychannel_without_ack(channel, target_vp); 237 302 } 238 303 EXPORT_SYMBOL_GPL(vmbus_send_modifychannel); 239 304
+42
drivers/hv/channel_mgmt.c
··· 1312 1312 } 1313 1313 1314 1314 /* 1315 + * vmbus_onmodifychannel_response - Modify Channel response handler. 1316 + * 1317 + * This is invoked when we received a response to our channel modify request. 1318 + * Find the matching request, copy the response and signal the requesting thread. 1319 + */ 1320 + static void vmbus_onmodifychannel_response(struct vmbus_channel_message_header *hdr) 1321 + { 1322 + struct vmbus_channel_modifychannel_response *response; 1323 + struct vmbus_channel_msginfo *msginfo; 1324 + unsigned long flags; 1325 + 1326 + response = (struct vmbus_channel_modifychannel_response *)hdr; 1327 + 1328 + trace_vmbus_onmodifychannel_response(response); 1329 + 1330 + /* 1331 + * Find the modify msg, copy the response and signal/unblock the wait event. 1332 + */ 1333 + spin_lock_irqsave(&vmbus_connection.channelmsg_lock, flags); 1334 + 1335 + list_for_each_entry(msginfo, &vmbus_connection.chn_msg_list, msglistentry) { 1336 + struct vmbus_channel_message_header *responseheader = 1337 + (struct vmbus_channel_message_header *)msginfo->msg; 1338 + 1339 + if (responseheader->msgtype == CHANNELMSG_MODIFYCHANNEL) { 1340 + struct vmbus_channel_modifychannel *modifymsg; 1341 + 1342 + modifymsg = (struct vmbus_channel_modifychannel *)msginfo->msg; 1343 + if (modifymsg->child_relid == response->child_relid) { 1344 + memcpy(&msginfo->response.modify_response, response, 1345 + sizeof(*response)); 1346 + complete(&msginfo->waitevent); 1347 + break; 1348 + } 1349 + } 1350 + } 1351 + spin_unlock_irqrestore(&vmbus_connection.channelmsg_lock, flags); 1352 + } 1353 + 1354 + /* 1315 1355 * vmbus_ongpadl_torndown - GPADL torndown handler. 1316 1356 * 1317 1357 * This is invoked when we received a response to our gpadl teardown request. ··· 1468 1428 { CHANNELMSG_TL_CONNECT_REQUEST, 0, NULL, 0}, 1469 1429 { CHANNELMSG_MODIFYCHANNEL, 0, NULL, 0}, 1470 1430 { CHANNELMSG_TL_CONNECT_RESULT, 0, NULL, 0}, 1431 + { CHANNELMSG_MODIFYCHANNEL_RESPONSE, 1, vmbus_onmodifychannel_response, 1432 + sizeof(struct vmbus_channel_modifychannel_response)}, 1471 1433 }; 1472 1434 1473 1435 /*
+15
drivers/hv/hv_trace.h
··· 103 103 ) 104 104 ); 105 105 106 + TRACE_EVENT(vmbus_onmodifychannel_response, 107 + TP_PROTO(const struct vmbus_channel_modifychannel_response *response), 108 + TP_ARGS(response), 109 + TP_STRUCT__entry( 110 + __field(u32, child_relid) 111 + __field(u32, status) 112 + ), 113 + TP_fast_assign(__entry->child_relid = response->child_relid; 114 + __entry->status = response->status; 115 + ), 116 + TP_printk("child_relid 0x%x, status %d", 117 + __entry->child_relid, __entry->status 118 + ) 119 + ); 120 + 106 121 TRACE_EVENT(vmbus_ongpadl_torndown, 107 122 TP_PROTO(const struct vmbus_channel_gpadl_torndown *gpadltorndown), 108 123 TP_ARGS(gpadltorndown),
+3 -1
drivers/hv/vmbus_drv.c
··· 1848 1848 if (target_cpu == origin_cpu) 1849 1849 goto cpu_store_unlock; 1850 1850 1851 - if (vmbus_send_modifychannel(channel->offermsg.child_relid, 1851 + if (vmbus_send_modifychannel(channel, 1852 1852 hv_cpu_number_to_vp_number(target_cpu))) { 1853 1853 ret = -EIO; 1854 1854 goto cpu_store_unlock; 1855 1855 } 1856 1856 1857 1857 /* 1858 + * For version before VERSION_WIN10_V5_3, the following warning holds: 1859 + * 1858 1860 * Warning. At this point, there is *no* guarantee that the host will 1859 1861 * have successfully processed the vmbus_send_modifychannel() request. 1860 1862 * See the header comment of vmbus_send_modifychannel() for more info.
+10 -1
include/linux/hyperv.h
··· 477 477 CHANNELMSG_TL_CONNECT_REQUEST = 21, 478 478 CHANNELMSG_MODIFYCHANNEL = 22, 479 479 CHANNELMSG_TL_CONNECT_RESULT = 23, 480 + CHANNELMSG_MODIFYCHANNEL_RESPONSE = 24, 480 481 CHANNELMSG_COUNT 481 482 }; 482 483 ··· 588 587 struct vmbus_channel_message_header header; 589 588 u32 child_relid; 590 589 u32 openid; 590 + u32 status; 591 + } __packed; 592 + 593 + /* Modify Channel Result parameters */ 594 + struct vmbus_channel_modifychannel_response { 595 + struct vmbus_channel_message_header header; 596 + u32 child_relid; 591 597 u32 status; 592 598 } __packed; 593 599 ··· 730 722 struct vmbus_channel_gpadl_torndown gpadl_torndown; 731 723 struct vmbus_channel_gpadl_created gpadl_created; 732 724 struct vmbus_channel_version_response version_response; 725 + struct vmbus_channel_modifychannel_response modify_response; 733 726 } response; 734 727 735 728 u32 msgsize; ··· 1605 1596 1606 1597 int vmbus_send_tl_connect_request(const guid_t *shv_guest_servie_id, 1607 1598 const guid_t *shv_host_servie_id); 1608 - int vmbus_send_modifychannel(u32 child_relid, u32 target_vp); 1599 + int vmbus_send_modifychannel(struct vmbus_channel *channel, u32 target_vp); 1609 1600 void vmbus_set_event(struct vmbus_channel *channel); 1610 1601 1611 1602 /* Get the start of the ring buffer. */