Merge tag 'regmap-v4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie...
[cascardo/linux.git] / drivers / hv / hv_snapshot.c
index 3fba14e..a670713 100644 (file)
@@ -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);
 }