diff options
Diffstat (limited to 'drivers/hv/hv_snapshot.c')
-rw-r--r-- | drivers/hv/hv_snapshot.c | 109 |
1 files changed, 57 insertions, 52 deletions
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index 3fba14e88f03..a6707133c297 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c @@ -67,11 +67,11 @@ static const char vss_devname[] = "vmbus/hv_vss"; static __u8 *recv_buffer; static struct hvutil_transport *hvt; -static void vss_send_op(struct work_struct *dummy); static void vss_timeout_func(struct work_struct *dummy); +static void vss_handle_request(struct work_struct *dummy); static DECLARE_DELAYED_WORK(vss_timeout_work, vss_timeout_func); -static DECLARE_WORK(vss_send_op_work, vss_send_op); +static DECLARE_WORK(vss_handle_request_work, vss_handle_request); static void vss_poll_wrapper(void *channel) { @@ -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; } @@ -136,6 +142,11 @@ static int vss_on_msg(void *msg, int len) return vss_handle_handshake(vss_msg); } else if (vss_transaction.state == HVUTIL_USERSPACE_REQ) { vss_transaction.state = HVUTIL_USERSPACE_RECV; + + if (vss_msg->vss_hdr.operation == VSS_OP_HOT_BACKUP) + vss_transaction.msg->vss_cf.flags = + VSS_HBU_NO_AUTO_RECOVERY; + if (cancel_delayed_work_sync(&vss_timeout_work)) { vss_respond_to_host(vss_msg->error); /* Transaction is finished, reset the state. */ @@ -150,8 +161,7 @@ static int vss_on_msg(void *msg, int len) return 0; } - -static void vss_send_op(struct work_struct *dummy) +static void vss_send_op(void) { int op = vss_transaction.msg->vss_hdr.operation; int rc; @@ -168,7 +178,10 @@ 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)); + + schedule_delayed_work(&vss_timeout_work, VSS_USERSPACE_TIMEOUT); + + 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)) { @@ -182,6 +195,38 @@ static void vss_send_op(struct work_struct *dummy) return; } +static void vss_handle_request(struct work_struct *dummy) +{ + switch (vss_transaction.msg->vss_hdr.operation) { + /* + * Initiate a "freeze/thaw" operation in the guest. + * We respond to the host once the operation is complete. + * + * We send the message to the user space daemon and the operation is + * performed in the daemon. + */ + case VSS_OP_THAW: + case VSS_OP_FREEZE: + case VSS_OP_HOT_BACKUP: + if (vss_transaction.state < HVUTIL_READY) { + /* Userspace is not registered yet */ + vss_respond_to_host(HV_E_FAIL); + return; + } + vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED; + vss_send_op(); + return; + case VSS_OP_GET_DM_INFO: + vss_transaction.msg->dm_info.flags = 0; + break; + default: + break; + } + + vss_respond_to_host(0); + hv_poll_channel(vss_transaction.recv_channel, vss_poll_wrapper); +} + /* * Send a response back to the host. */ @@ -266,48 +311,8 @@ void hv_vss_onchannelcallback(void *context) vss_transaction.recv_req_id = requestid; vss_transaction.msg = (struct hv_vss_msg *)vss_msg; - switch (vss_msg->vss_hdr.operation) { - /* - * Initiate a "freeze/thaw" - * operation in the guest. - * We respond to the host once - * the operation is complete. - * - * We send the message to the - * user space daemon and the - * operation is performed in - * the daemon. - */ - case VSS_OP_FREEZE: - case VSS_OP_THAW: - if (vss_transaction.state < HVUTIL_READY) { - /* Userspace is not registered yet */ - vss_respond_to_host(HV_E_FAIL); - return; - } - vss_transaction.state = HVUTIL_HOSTMSG_RECEIVED; - schedule_work(&vss_send_op_work); - schedule_delayed_work(&vss_timeout_work, - VSS_USERSPACE_TIMEOUT); - return; - - case VSS_OP_HOT_BACKUP: - vss_msg->vss_cf.flags = - VSS_HBU_NO_AUTO_RECOVERY; - vss_respond_to_host(0); - return; - - case VSS_OP_GET_DM_INFO: - vss_msg->dm_info.flags = 0; - vss_respond_to_host(0); - return; - - default: - vss_respond_to_host(0); - return; - - } - + schedule_work(&vss_handle_request_work); + return; } icmsghdrp->icflags = ICMSGHDRFLAG_TRANSACTION @@ -358,6 +363,6 @@ void hv_vss_deinit(void) { vss_transaction.state = HVUTIL_DEVICE_DYING; cancel_delayed_work_sync(&vss_timeout_work); - cancel_work_sync(&vss_send_op_work); + cancel_work_sync(&vss_handle_request_work); hvutil_transport_destroy(hvt); } |