struct hv_fcopy_hdr *fcopy_msg; /* current message */
struct vmbus_channel *recv_channel; /* chn we got the request */
u64 recv_req_id; /* request ID. */
- void *fcopy_context; /* for the channel callback */
} fcopy_transaction;
static void fcopy_respond_to_host(int error);
static const char fcopy_devname[] = "vmbus/hv_fcopy";
static u8 *recv_buffer;
static struct hvutil_transport *hvt;
+static struct completion release_event;
/*
* This state maintains the version number registered by the daemon.
*/
static int dm_reg_value;
+static void fcopy_poll_wrapper(void *channel)
+{
+ /* Transaction is finished, reset the state here to avoid races. */
+ fcopy_transaction.state = HVUTIL_READY;
+ hv_fcopy_onchannelcallback(channel);
+}
+
static void fcopy_timeout_func(struct work_struct *dummy)
{
/*
* process the pending transaction.
*/
fcopy_respond_to_host(HV_E_FAIL);
-
- /* Transaction is finished, reset the state. */
- if (fcopy_transaction.state > HVUTIL_READY)
- fcopy_transaction.state = HVUTIL_READY;
-
- hv_poll_channel(fcopy_transaction.fcopy_context,
- hv_fcopy_onchannelcallback);
+ hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
}
static int fcopy_handle_handshake(u32 version)
return -EINVAL;
}
pr_debug("FCP: userspace daemon ver. %d registered\n", version);
- fcopy_transaction.state = HVUTIL_READY;
- hv_poll_channel(fcopy_transaction.fcopy_context,
- hv_fcopy_onchannelcallback);
+ hv_poll_channel(fcopy_transaction.recv_channel, fcopy_poll_wrapper);
return 0;
}
int util_fw_version;
int fcopy_srv_version;
- if (fcopy_transaction.state > HVUTIL_READY) {
- /*
- * We will defer processing this callback once
- * the current transaction is complete.
- */
- fcopy_transaction.fcopy_context = context;
+ if (fcopy_transaction.state > HVUTIL_READY)
return;
- }
- fcopy_transaction.fcopy_context = NULL;
vmbus_recvpacket(channel, recv_buffer, PAGE_SIZE * 2, &recvlen,
&requestid);
* Send the information to the user-level daemon.
*/
schedule_work(&fcopy_send_work);
- schedule_delayed_work(&fcopy_timeout_work, 5*HZ);
+ schedule_delayed_work(&fcopy_timeout_work,
+ HV_UTIL_TIMEOUT * HZ);
return;
}
icmsghdr->icflags = ICMSGHDRFLAG_TRANSACTION | ICMSGHDRFLAG_RESPONSE;
if (cancel_delayed_work_sync(&fcopy_timeout_work)) {
fcopy_transaction.state = HVUTIL_USERSPACE_RECV;
fcopy_respond_to_host(*val);
- fcopy_transaction.state = HVUTIL_READY;
- hv_poll_channel(fcopy_transaction.fcopy_context,
- hv_fcopy_onchannelcallback);
+ hv_poll_channel(fcopy_transaction.recv_channel,
+ fcopy_poll_wrapper);
}
return 0;
if (cancel_delayed_work_sync(&fcopy_timeout_work))
fcopy_respond_to_host(HV_E_FAIL);
+ complete(&release_event);
}
int hv_fcopy_init(struct hv_util_service *srv)
{
recv_buffer = srv->recv_buffer;
+ init_completion(&release_event);
/*
* When this driver loads, the user level daemon that
* processes the host requests may not yet be running.
fcopy_transaction.state = HVUTIL_DEVICE_DYING;
cancel_delayed_work_sync(&fcopy_timeout_work);
hvutil_transport_destroy(hvt);
+ wait_for_completion(&release_event);
}