Commit e9c18ae6 authored by Vitaly Kuznetsov's avatar Vitaly Kuznetsov Committed by Greg Kroah-Hartman

Drivers: hv: util: move waiting for release to hv_utils_transport itself

Waiting for release_event in all three drivers introduced issues on release
as on_reset() hook is not always called. E.g. if the device was never
opened we will never get the completion.

Move the waiting code to hvutil_transport_destroy() and make sure it is
only called when the device is open. hvt->lock serialization should
guarantee the absence of races.

Fixes: 5a66fecb ("Drivers: hv: util: kvp: Fix a rescind processing issue")
Fixes: 20951c75 ("Drivers: hv: util: Fcopy: Fix a rescind processing issue")
Fixes: d77044d1 ("Drivers: hv: util: Backup: Fix a rescind processing issue")
Reported-by: default avatarDexuan Cui <decui@microsoft.com>
Tested-by: default avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: default avatarVitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent dad72a1d
...@@ -71,7 +71,6 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data); ...@@ -71,7 +71,6 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data);
static const char fcopy_devname[] = "vmbus/hv_fcopy"; static const char fcopy_devname[] = "vmbus/hv_fcopy";
static u8 *recv_buffer; static u8 *recv_buffer;
static struct hvutil_transport *hvt; static struct hvutil_transport *hvt;
static struct completion release_event;
/* /*
* This state maintains the version number registered by the daemon. * This state maintains the version number registered by the daemon.
*/ */
...@@ -331,7 +330,6 @@ static void fcopy_on_reset(void) ...@@ -331,7 +330,6 @@ static void fcopy_on_reset(void)
if (cancel_delayed_work_sync(&fcopy_timeout_work)) if (cancel_delayed_work_sync(&fcopy_timeout_work))
fcopy_respond_to_host(HV_E_FAIL); fcopy_respond_to_host(HV_E_FAIL);
complete(&release_event);
} }
int hv_fcopy_init(struct hv_util_service *srv) int hv_fcopy_init(struct hv_util_service *srv)
...@@ -339,7 +337,6 @@ int hv_fcopy_init(struct hv_util_service *srv) ...@@ -339,7 +337,6 @@ int hv_fcopy_init(struct hv_util_service *srv)
recv_buffer = srv->recv_buffer; recv_buffer = srv->recv_buffer;
fcopy_transaction.recv_channel = srv->channel; fcopy_transaction.recv_channel = srv->channel;
init_completion(&release_event);
/* /*
* When this driver loads, the user level daemon that * When this driver loads, the user level daemon that
* processes the host requests may not yet be running. * processes the host requests may not yet be running.
...@@ -361,5 +358,4 @@ void hv_fcopy_deinit(void) ...@@ -361,5 +358,4 @@ void hv_fcopy_deinit(void)
fcopy_transaction.state = HVUTIL_DEVICE_DYING; fcopy_transaction.state = HVUTIL_DEVICE_DYING;
cancel_delayed_work_sync(&fcopy_timeout_work); cancel_delayed_work_sync(&fcopy_timeout_work);
hvutil_transport_destroy(hvt); hvutil_transport_destroy(hvt);
wait_for_completion(&release_event);
} }
...@@ -101,7 +101,6 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); ...@@ -101,7 +101,6 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key);
static const char kvp_devname[] = "vmbus/hv_kvp"; static const char kvp_devname[] = "vmbus/hv_kvp";
static u8 *recv_buffer; static u8 *recv_buffer;
static struct hvutil_transport *hvt; static struct hvutil_transport *hvt;
static struct completion release_event;
/* /*
* Register the kernel component with the user-level daemon. * Register the kernel component with the user-level daemon.
* As part of this registration, pass the LIC version number. * As part of this registration, pass the LIC version number.
...@@ -714,7 +713,6 @@ static void kvp_on_reset(void) ...@@ -714,7 +713,6 @@ static void kvp_on_reset(void)
if (cancel_delayed_work_sync(&kvp_timeout_work)) if (cancel_delayed_work_sync(&kvp_timeout_work))
kvp_respond_to_host(NULL, HV_E_FAIL); kvp_respond_to_host(NULL, HV_E_FAIL);
kvp_transaction.state = HVUTIL_DEVICE_INIT; kvp_transaction.state = HVUTIL_DEVICE_INIT;
complete(&release_event);
} }
int int
...@@ -723,7 +721,6 @@ hv_kvp_init(struct hv_util_service *srv) ...@@ -723,7 +721,6 @@ hv_kvp_init(struct hv_util_service *srv)
recv_buffer = srv->recv_buffer; recv_buffer = srv->recv_buffer;
kvp_transaction.recv_channel = srv->channel; kvp_transaction.recv_channel = srv->channel;
init_completion(&release_event);
/* /*
* When this driver loads, the user level daemon that * When this driver loads, the user level daemon that
* processes the host requests may not yet be running. * processes the host requests may not yet be running.
...@@ -747,5 +744,4 @@ void hv_kvp_deinit(void) ...@@ -747,5 +744,4 @@ void hv_kvp_deinit(void)
cancel_delayed_work_sync(&kvp_timeout_work); cancel_delayed_work_sync(&kvp_timeout_work);
cancel_work_sync(&kvp_sendkey_work); cancel_work_sync(&kvp_sendkey_work);
hvutil_transport_destroy(hvt); hvutil_transport_destroy(hvt);
wait_for_completion(&release_event);
} }
...@@ -79,7 +79,6 @@ static int dm_reg_value; ...@@ -79,7 +79,6 @@ static int dm_reg_value;
static const char vss_devname[] = "vmbus/hv_vss"; static const char vss_devname[] = "vmbus/hv_vss";
static __u8 *recv_buffer; static __u8 *recv_buffer;
static struct hvutil_transport *hvt; static struct hvutil_transport *hvt;
static struct completion release_event;
static void vss_timeout_func(struct work_struct *dummy); static void vss_timeout_func(struct work_struct *dummy);
static void vss_handle_request(struct work_struct *dummy); static void vss_handle_request(struct work_struct *dummy);
...@@ -361,13 +360,11 @@ static void vss_on_reset(void) ...@@ -361,13 +360,11 @@ static void vss_on_reset(void)
if (cancel_delayed_work_sync(&vss_timeout_work)) if (cancel_delayed_work_sync(&vss_timeout_work))
vss_respond_to_host(HV_E_FAIL); vss_respond_to_host(HV_E_FAIL);
vss_transaction.state = HVUTIL_DEVICE_INIT; vss_transaction.state = HVUTIL_DEVICE_INIT;
complete(&release_event);
} }
int int
hv_vss_init(struct hv_util_service *srv) hv_vss_init(struct hv_util_service *srv)
{ {
init_completion(&release_event);
if (vmbus_proto_version < VERSION_WIN8_1) { if (vmbus_proto_version < VERSION_WIN8_1) {
pr_warn("Integration service 'Backup (volume snapshot)'" pr_warn("Integration service 'Backup (volume snapshot)'"
" not supported on this host version.\n"); " not supported on this host version.\n");
...@@ -400,5 +397,4 @@ void hv_vss_deinit(void) ...@@ -400,5 +397,4 @@ void hv_vss_deinit(void)
cancel_delayed_work_sync(&vss_timeout_work); cancel_delayed_work_sync(&vss_timeout_work);
cancel_work_sync(&vss_handle_request_work); cancel_work_sync(&vss_handle_request_work);
hvutil_transport_destroy(hvt); hvutil_transport_destroy(hvt);
wait_for_completion(&release_event);
} }
...@@ -182,10 +182,11 @@ static int hvt_op_release(struct inode *inode, struct file *file) ...@@ -182,10 +182,11 @@ static int hvt_op_release(struct inode *inode, struct file *file)
* connects back. * connects back.
*/ */
hvt_reset(hvt); hvt_reset(hvt);
mutex_unlock(&hvt->lock);
if (mode_old == HVUTIL_TRANSPORT_DESTROY) if (mode_old == HVUTIL_TRANSPORT_DESTROY)
hvt_transport_free(hvt); complete(&hvt->release);
mutex_unlock(&hvt->lock);
return 0; return 0;
} }
...@@ -304,6 +305,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name, ...@@ -304,6 +305,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name,
init_waitqueue_head(&hvt->outmsg_q); init_waitqueue_head(&hvt->outmsg_q);
mutex_init(&hvt->lock); mutex_init(&hvt->lock);
init_completion(&hvt->release);
spin_lock(&hvt_list_lock); spin_lock(&hvt_list_lock);
list_add(&hvt->list, &hvt_list); list_add(&hvt->list, &hvt_list);
...@@ -351,6 +353,8 @@ void hvutil_transport_destroy(struct hvutil_transport *hvt) ...@@ -351,6 +353,8 @@ void hvutil_transport_destroy(struct hvutil_transport *hvt)
if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0)
cn_del_callback(&hvt->cn_id); cn_del_callback(&hvt->cn_id);
if (mode_old != HVUTIL_TRANSPORT_CHARDEV) if (mode_old == HVUTIL_TRANSPORT_CHARDEV)
hvt_transport_free(hvt); wait_for_completion(&hvt->release);
hvt_transport_free(hvt);
} }
...@@ -41,6 +41,7 @@ struct hvutil_transport { ...@@ -41,6 +41,7 @@ struct hvutil_transport {
int outmsg_len; /* its length */ int outmsg_len; /* its length */
wait_queue_head_t outmsg_q; /* poll/read wait queue */ wait_queue_head_t outmsg_q; /* poll/read wait queue */
struct mutex lock; /* protects struct members */ struct mutex lock; /* protects struct members */
struct completion release; /* synchronize with fd release */
}; };
struct hvutil_transport *hvutil_transport_init(const char *name, struct hvutil_transport *hvutil_transport_init(const char *name,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment