diff options
author | Vitaly Kuznetsov <vkuznets@redhat.com> | 2017-03-04 20:13:59 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-16 03:42:00 -0400 |
commit | e9c18ae6eb2b312f16c63e34b43ea23926daa398 (patch) | |
tree | 78bd2c2344d415e4fb95b1c8964508c59dfbc724 | |
parent | dad72a1d28442b03aac86836a42de2d00a1014ab (diff) |
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: 5a66fecbf6aa ("Drivers: hv: util: kvp: Fix a rescind processing issue")
Fixes: 20951c7535b5 ("Drivers: hv: util: Fcopy: Fix a rescind processing issue")
Fixes: d77044d142e9 ("Drivers: hv: util: Backup: Fix a rescind processing issue")
Reported-by: Dexuan Cui <decui@microsoft.com>
Tested-by: Dexuan Cui <decui@microsoft.com>
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Signed-off-by: K. Y. Srinivasan <kys@microsoft.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/hv/hv_fcopy.c | 4 | ||||
-rw-r--r-- | drivers/hv/hv_kvp.c | 4 | ||||
-rw-r--r-- | drivers/hv/hv_snapshot.c | 4 | ||||
-rw-r--r-- | drivers/hv/hv_utils_transport.c | 12 | ||||
-rw-r--r-- | drivers/hv/hv_utils_transport.h | 1 |
5 files changed, 9 insertions, 16 deletions
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c index 9aee6014339d..a5596a642ed0 100644 --- a/drivers/hv/hv_fcopy.c +++ b/drivers/hv/hv_fcopy.c | |||
@@ -71,7 +71,6 @@ static DECLARE_WORK(fcopy_send_work, fcopy_send_data); | |||
71 | static const char fcopy_devname[] = "vmbus/hv_fcopy"; | 71 | static const char fcopy_devname[] = "vmbus/hv_fcopy"; |
72 | static u8 *recv_buffer; | 72 | static u8 *recv_buffer; |
73 | static struct hvutil_transport *hvt; | 73 | static struct hvutil_transport *hvt; |
74 | static struct completion release_event; | ||
75 | /* | 74 | /* |
76 | * This state maintains the version number registered by the daemon. | 75 | * This state maintains the version number registered by the daemon. |
77 | */ | 76 | */ |
@@ -331,7 +330,6 @@ static void fcopy_on_reset(void) | |||
331 | 330 | ||
332 | if (cancel_delayed_work_sync(&fcopy_timeout_work)) | 331 | if (cancel_delayed_work_sync(&fcopy_timeout_work)) |
333 | fcopy_respond_to_host(HV_E_FAIL); | 332 | fcopy_respond_to_host(HV_E_FAIL); |
334 | complete(&release_event); | ||
335 | } | 333 | } |
336 | 334 | ||
337 | int hv_fcopy_init(struct hv_util_service *srv) | 335 | int hv_fcopy_init(struct hv_util_service *srv) |
@@ -339,7 +337,6 @@ int hv_fcopy_init(struct hv_util_service *srv) | |||
339 | recv_buffer = srv->recv_buffer; | 337 | recv_buffer = srv->recv_buffer; |
340 | fcopy_transaction.recv_channel = srv->channel; | 338 | fcopy_transaction.recv_channel = srv->channel; |
341 | 339 | ||
342 | init_completion(&release_event); | ||
343 | /* | 340 | /* |
344 | * When this driver loads, the user level daemon that | 341 | * When this driver loads, the user level daemon that |
345 | * processes the host requests may not yet be running. | 342 | * processes the host requests may not yet be running. |
@@ -361,5 +358,4 @@ void hv_fcopy_deinit(void) | |||
361 | fcopy_transaction.state = HVUTIL_DEVICE_DYING; | 358 | fcopy_transaction.state = HVUTIL_DEVICE_DYING; |
362 | cancel_delayed_work_sync(&fcopy_timeout_work); | 359 | cancel_delayed_work_sync(&fcopy_timeout_work); |
363 | hvutil_transport_destroy(hvt); | 360 | hvutil_transport_destroy(hvt); |
364 | wait_for_completion(&release_event); | ||
365 | } | 361 | } |
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c index de263712e247..a1adfe2cfb34 100644 --- a/drivers/hv/hv_kvp.c +++ b/drivers/hv/hv_kvp.c | |||
@@ -101,7 +101,6 @@ static DECLARE_WORK(kvp_sendkey_work, kvp_send_key); | |||
101 | static const char kvp_devname[] = "vmbus/hv_kvp"; | 101 | static const char kvp_devname[] = "vmbus/hv_kvp"; |
102 | static u8 *recv_buffer; | 102 | static u8 *recv_buffer; |
103 | static struct hvutil_transport *hvt; | 103 | static struct hvutil_transport *hvt; |
104 | static struct completion release_event; | ||
105 | /* | 104 | /* |
106 | * Register the kernel component with the user-level daemon. | 105 | * Register the kernel component with the user-level daemon. |
107 | * As part of this registration, pass the LIC version number. | 106 | * As part of this registration, pass the LIC version number. |
@@ -714,7 +713,6 @@ static void kvp_on_reset(void) | |||
714 | if (cancel_delayed_work_sync(&kvp_timeout_work)) | 713 | if (cancel_delayed_work_sync(&kvp_timeout_work)) |
715 | kvp_respond_to_host(NULL, HV_E_FAIL); | 714 | kvp_respond_to_host(NULL, HV_E_FAIL); |
716 | kvp_transaction.state = HVUTIL_DEVICE_INIT; | 715 | kvp_transaction.state = HVUTIL_DEVICE_INIT; |
717 | complete(&release_event); | ||
718 | } | 716 | } |
719 | 717 | ||
720 | int | 718 | int |
@@ -723,7 +721,6 @@ hv_kvp_init(struct hv_util_service *srv) | |||
723 | recv_buffer = srv->recv_buffer; | 721 | recv_buffer = srv->recv_buffer; |
724 | kvp_transaction.recv_channel = srv->channel; | 722 | kvp_transaction.recv_channel = srv->channel; |
725 | 723 | ||
726 | init_completion(&release_event); | ||
727 | /* | 724 | /* |
728 | * When this driver loads, the user level daemon that | 725 | * When this driver loads, the user level daemon that |
729 | * processes the host requests may not yet be running. | 726 | * processes the host requests may not yet be running. |
@@ -747,5 +744,4 @@ void hv_kvp_deinit(void) | |||
747 | cancel_delayed_work_sync(&kvp_timeout_work); | 744 | cancel_delayed_work_sync(&kvp_timeout_work); |
748 | cancel_work_sync(&kvp_sendkey_work); | 745 | cancel_work_sync(&kvp_sendkey_work); |
749 | hvutil_transport_destroy(hvt); | 746 | hvutil_transport_destroy(hvt); |
750 | wait_for_completion(&release_event); | ||
751 | } | 747 | } |
diff --git a/drivers/hv/hv_snapshot.c b/drivers/hv/hv_snapshot.c index bcc03f0748d6..e659d1b94a57 100644 --- a/drivers/hv/hv_snapshot.c +++ b/drivers/hv/hv_snapshot.c | |||
@@ -79,7 +79,6 @@ static int dm_reg_value; | |||
79 | static const char vss_devname[] = "vmbus/hv_vss"; | 79 | static const char vss_devname[] = "vmbus/hv_vss"; |
80 | static __u8 *recv_buffer; | 80 | static __u8 *recv_buffer; |
81 | static struct hvutil_transport *hvt; | 81 | static struct hvutil_transport *hvt; |
82 | static struct completion release_event; | ||
83 | 82 | ||
84 | static void vss_timeout_func(struct work_struct *dummy); | 83 | static void vss_timeout_func(struct work_struct *dummy); |
85 | static void vss_handle_request(struct work_struct *dummy); | 84 | static void vss_handle_request(struct work_struct *dummy); |
@@ -361,13 +360,11 @@ static void vss_on_reset(void) | |||
361 | if (cancel_delayed_work_sync(&vss_timeout_work)) | 360 | if (cancel_delayed_work_sync(&vss_timeout_work)) |
362 | vss_respond_to_host(HV_E_FAIL); | 361 | vss_respond_to_host(HV_E_FAIL); |
363 | vss_transaction.state = HVUTIL_DEVICE_INIT; | 362 | vss_transaction.state = HVUTIL_DEVICE_INIT; |
364 | complete(&release_event); | ||
365 | } | 363 | } |
366 | 364 | ||
367 | int | 365 | int |
368 | hv_vss_init(struct hv_util_service *srv) | 366 | hv_vss_init(struct hv_util_service *srv) |
369 | { | 367 | { |
370 | init_completion(&release_event); | ||
371 | if (vmbus_proto_version < VERSION_WIN8_1) { | 368 | if (vmbus_proto_version < VERSION_WIN8_1) { |
372 | pr_warn("Integration service 'Backup (volume snapshot)'" | 369 | pr_warn("Integration service 'Backup (volume snapshot)'" |
373 | " not supported on this host version.\n"); | 370 | " not supported on this host version.\n"); |
@@ -400,5 +397,4 @@ void hv_vss_deinit(void) | |||
400 | cancel_delayed_work_sync(&vss_timeout_work); | 397 | cancel_delayed_work_sync(&vss_timeout_work); |
401 | cancel_work_sync(&vss_handle_request_work); | 398 | cancel_work_sync(&vss_handle_request_work); |
402 | hvutil_transport_destroy(hvt); | 399 | hvutil_transport_destroy(hvt); |
403 | wait_for_completion(&release_event); | ||
404 | } | 400 | } |
diff --git a/drivers/hv/hv_utils_transport.c b/drivers/hv/hv_utils_transport.c index c235a9515267..4402a71e23f7 100644 --- a/drivers/hv/hv_utils_transport.c +++ b/drivers/hv/hv_utils_transport.c | |||
@@ -182,10 +182,11 @@ static int hvt_op_release(struct inode *inode, struct file *file) | |||
182 | * connects back. | 182 | * connects back. |
183 | */ | 183 | */ |
184 | hvt_reset(hvt); | 184 | hvt_reset(hvt); |
185 | mutex_unlock(&hvt->lock); | ||
186 | 185 | ||
187 | if (mode_old == HVUTIL_TRANSPORT_DESTROY) | 186 | if (mode_old == HVUTIL_TRANSPORT_DESTROY) |
188 | hvt_transport_free(hvt); | 187 | complete(&hvt->release); |
188 | |||
189 | mutex_unlock(&hvt->lock); | ||
189 | 190 | ||
190 | return 0; | 191 | return 0; |
191 | } | 192 | } |
@@ -304,6 +305,7 @@ struct hvutil_transport *hvutil_transport_init(const char *name, | |||
304 | 305 | ||
305 | init_waitqueue_head(&hvt->outmsg_q); | 306 | init_waitqueue_head(&hvt->outmsg_q); |
306 | mutex_init(&hvt->lock); | 307 | mutex_init(&hvt->lock); |
308 | init_completion(&hvt->release); | ||
307 | 309 | ||
308 | spin_lock(&hvt_list_lock); | 310 | spin_lock(&hvt_list_lock); |
309 | list_add(&hvt->list, &hvt_list); | 311 | list_add(&hvt->list, &hvt_list); |
@@ -351,6 +353,8 @@ void hvutil_transport_destroy(struct hvutil_transport *hvt) | |||
351 | if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) | 353 | if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) |
352 | cn_del_callback(&hvt->cn_id); | 354 | cn_del_callback(&hvt->cn_id); |
353 | 355 | ||
354 | if (mode_old != HVUTIL_TRANSPORT_CHARDEV) | 356 | if (mode_old == HVUTIL_TRANSPORT_CHARDEV) |
355 | hvt_transport_free(hvt); | 357 | wait_for_completion(&hvt->release); |
358 | |||
359 | hvt_transport_free(hvt); | ||
356 | } | 360 | } |
diff --git a/drivers/hv/hv_utils_transport.h b/drivers/hv/hv_utils_transport.h index d98f5225c3e6..79afb626e166 100644 --- a/drivers/hv/hv_utils_transport.h +++ b/drivers/hv/hv_utils_transport.h | |||
@@ -41,6 +41,7 @@ struct hvutil_transport { | |||
41 | int outmsg_len; /* its length */ | 41 | int outmsg_len; /* its length */ |
42 | wait_queue_head_t outmsg_q; /* poll/read wait queue */ | 42 | wait_queue_head_t outmsg_q; /* poll/read wait queue */ |
43 | struct mutex lock; /* protects struct members */ | 43 | struct mutex lock; /* protects struct members */ |
44 | struct completion release; /* synchronize with fd release */ | ||
44 | }; | 45 | }; |
45 | 46 | ||
46 | struct hvutil_transport *hvutil_transport_init(const char *name, | 47 | struct hvutil_transport *hvutil_transport_init(const char *name, |