diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index 23c70799ad8a..8b2ba98831ec 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c @@ -83,6 +83,12 @@ static void fcopy_timeout_func(struct work_struct *dummy) hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); } +static void fcopy_register_done(void) +{ + pr_debug("FCP: userspace daemon registered\n"); + hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); +} + static int fcopy_handle_handshake(u32 version) { u32 our_ver = FCOPY_CURRENT_VERSION; @@ -94,7 +100,8 @@ static int fcopy_handle_handshake(u32 version) break; case FCOPY_VERSION_1: /* Daemon expects us to reply with our own version */ - if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) + if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), + fcopy_register_done)) return -EFAULT; dm_reg_value = version; break; @@ -107,8 +114,7 @@ static int fcopy_handle_handshake(u32 version) */ return -EINVAL; } - pr_debug("FCP: userspace daemon ver. %d registered\n", version); - hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper); + pr_debug("FCP: userspace daemon ver. %d connected\n", version); return 0; } @@ -161,7 +167,7 @@ static void fcopy_send_data(struct work_struct *dummy) } fcopy_transaction.state = HVUTIL_USERSPACE_REQ; - rc = hvutil_transport_send(hvt, out_src, out_len); + rc = hvutil_transport_send(hvt, out_src, out_len, NULL); if (rc) { pr_debug("FCP: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&fcopy_timeout_work)) { diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index cb1a9160aab1..5e1fdc8d32ab 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c @@ -102,6 +102,17 @@ static void kvp_poll_wrapper(void *channel) hv_kvp_onchannelcallback(channel); } +static void kvp_register_done(void) +{ + /* + * If we're still negotiating with the host cancel the timeout + * work to not poll the channel twice. + */ + pr_debug("KVP: userspace daemon registered\n"); + cancel_delayed_work_sync(&kvp_host_handshake_work); + hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); +} + static void kvp_register(int reg_value) { @@ -116,7 +127,8 @@ kvp_register(int reg_value) kvp_msg->kvp_hdr.operation = reg_value; strcpy(version, HV_DRV_VERSION); - hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg)); + hvutil_transport_send(hvt, kvp_msg, sizeof(*kvp_msg), + kvp_register_done); kfree(kvp_msg); } } @@ -158,17 +170,10 @@ static int kvp_handle_handshake(struct hv_kvp_msg *msg) /* * We have a compatible daemon; complete the handshake. */ - pr_debug("KVP: userspace daemon ver. %d registered\n", - KVP_OP_REGISTER); + pr_debug("KVP: userspace daemon ver. %d connected\n", + msg->kvp_hdr.operation); kvp_register(dm_reg_value); - /* - * If we're still negotiating with the host cancel the timeout - * work to not poll the channel twice. - */ - cancel_delayed_work_sync(&kvp_host_handshake_work); - hv_poll_channel(kvp_transaction.recv_channel, kvp_poll_wrapper); - return 0; } @@ -455,7 +460,7 @@ kvp_send_key(struct work_struct *dummy) } kvp_transaction.state = HVUTIL_USERSPACE_REQ; - rc = hvutil_transport_send(hvt, message, sizeof(*message)); + rc = hvutil_transport_send(hvt, message, sizeof(*message), NULL); if (rc) { pr_debug("KVP: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&kvp_timeout_work)) { diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 3fba14e88f03..fde45865579a 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -95,6 +95,12 @@ static void vss_timeout_func(struct work_struct *dummy) hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); } +static void vss_register_done(void) +{ + hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); + pr_debug("VSS: userspace daemon registered\n"); +} + static int vss_handle_handshake(struct hv_vss_msg *vss_msg) { u32 our_ver = VSS_OP_REGISTER1; @@ -105,16 +111,16 @@ static int vss_handle_handshake(struct hv_vss_msg *vss_msg) dm_reg_value = VSS_OP_REGISTER; break; case VSS_OP_REGISTER1: - /* Daemon expects us to reply with our own version*/ - if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver))) + /* Daemon expects us to reply with our own version */ + if (hvutil_transport_send(hvt, &our_ver, sizeof(our_ver), + vss_register_done)) return -EFAULT; dm_reg_value = VSS_OP_REGISTER1; break; default: return -EINVAL; } - hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); - pr_debug("VSS: userspace daemon ver. %d registered\n", dm_reg_value); + pr_debug("VSS: userspace daemon ver. %d connected\n", dm_reg_value); return 0; } @@ -168,7 +174,7 @@ static void vss_send_op(struct work_struct *dummy) vss_msg->vss_hdr.operation = op; vss_transaction.state = HVUTIL_USERSPACE_REQ; - rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg)); + rc = hvutil_transport_send(hvt, vss_msg, sizeof(*vss_msg), NULL); if (rc) { pr_warn("VSS: failed to communicate to the daemon: %d\n", rc); if (cancel_delayed_work_sync(&vss_timeout_work)) { diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index 9a9983fa4531..c235a9515267 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c @@ -72,6 +72,10 @@ static ssize_t hvt_op_read(struct file *file, char __user *buf, hvt->outmsg = NULL; hvt->outmsg_len = 0; + if (hvt->on_read) + hvt->on_read(); + hvt->on_read = NULL; + out_unlock: mutex_unlock(&hvt->lock); return ret; @@ -219,7 +223,8 @@ static void hvt_cn_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) mutex_unlock(&hvt->lock); } -int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) +int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len, + void (*on_read_cb)(void)) { struct cn_msg *cn_msg; int ret = 0; @@ -237,6 +242,13 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) memcpy(cn_msg->data, msg, len); ret = cn_netlink_send(cn_msg, 0, 0, GFP_ATOMIC); kfree(cn_msg); + /* + * We don't know when netlink messages are delivered but unlike + * in CHARDEV mode we're not blocked and we can send next + * messages right away. + */ + if (on_read_cb) + on_read_cb(); return ret; } /* HVUTIL_TRANSPORT_CHARDEV */ @@ -255,6 +267,7 @@ int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len) if (hvt->outmsg) { memcpy(hvt->outmsg, msg, len); hvt->outmsg_len = len; + hvt->on_read = on_read_cb; wake_up_interruptible(&hvt->outmsg_q); } else ret = -ENOMEM; diff --git a/drivers/hv/hv_utils_transport.h b/drivers/hv/hv_utils_transport.h index 06254a165a18..d98f5225c3e6 100644 --- a/drivers/hv/hv_utils_transport.h +++ b/drivers/hv/hv_utils_transport.h @@ -36,6 +36,7 @@ struct hvutil_transport { struct list_head list; /* hvt_list */ int (*on_msg)(void *, int); /* callback on new user message */ void (*on_reset)(void); /* callback when userspace drops */ + void (*on_read)(void); /* callback on message read */ u8 *outmsg; /* message to the userspace */ int outmsg_len; /* its length */ wait_queue_head_t outmsg_q; /* poll/read wait queue */ @@ -46,7 +47,8 @@ struct hvutil_transport *hvutil_transport_init(const char *name, u32 cn_idx, u32 cn_val, int (*on_msg)(void *, int), void (*on_reset)(void)); -int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len); +int hvutil_transport_send(struct hvutil_transport *hvt, void *msg, int len, + void (*on_read_cb)(void)); void hvutil_transport_destroy(struct hvutil_transport *hvt); #endif /* _HV_UTILS_TRANSPORT_H */