Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vitaly Kuznetsov and committed by
Greg Kroah-Hartman
e9c18ae6 dad72a1d

+9 -16
-4
drivers/hv/hv_fcopy.c
··· 71 71 static const char fcopy_devname[] = "vmbus/hv_fcopy"; 72 72 static u8 *recv_buffer; 73 73 static struct hvutil_transport *hvt; 74 - static struct completion release_event; 75 74 /* 76 75 * This state maintains the version number registered by the daemon. 77 76 */ ··· 330 331 331 332 if (cancel_delayed_work_sync(&fcopy_timeout_work)) 332 333 fcopy_respond_to_host(HV_E_FAIL); 333 - complete(&release_event); 334 334 } 335 335 336 336 int hv_fcopy_init(struct hv_util_service *srv) ··· 337 339 recv_buffer = srv->recv_buffer; 338 340 fcopy_transaction.recv_channel = srv->channel; 339 341 340 - init_completion(&release_event); 341 342 /* 342 343 * When this driver loads, the user level daemon that 343 344 * processes the host requests may not yet be running. ··· 358 361 fcopy_transaction.state = HVUTIL_DEVICE_DYING; 359 362 cancel_delayed_work_sync(&fcopy_timeout_work); 360 363 hvutil_transport_destroy(hvt); 361 - wait_for_completion(&release_event); 362 364 }
-4
drivers/hv/hv_kvp.c
··· 101 101 static const char kvp_devname[] = "vmbus/hv_kvp"; 102 102 static u8 *recv_buffer; 103 103 static struct hvutil_transport *hvt; 104 - static struct completion release_event; 105 104 /* 106 105 * Register the kernel component with the user-level daemon. 107 106 * As part of this registration, pass the LIC version number. ··· 713 714 if (cancel_delayed_work_sync(&kvp_timeout_work)) 714 715 kvp_respond_to_host(NULL, HV_E_FAIL); 715 716 kvp_transaction.state = HVUTIL_DEVICE_INIT; 716 - complete(&release_event); 717 717 } 718 718 719 719 int ··· 721 723 recv_buffer = srv->recv_buffer; 722 724 kvp_transaction.recv_channel = srv->channel; 723 725 724 - init_completion(&release_event); 725 726 /* 726 727 * When this driver loads, the user level daemon that 727 728 * processes the host requests may not yet be running. ··· 744 747 cancel_delayed_work_sync(&kvp_timeout_work); 745 748 cancel_work_sync(&kvp_sendkey_work); 746 749 hvutil_transport_destroy(hvt); 747 - wait_for_completion(&release_event); 748 750 }
-4
drivers/hv/hv_snapshot.c
··· 79 79 static const char vss_devname[] = "vmbus/hv_vss"; 80 80 static __u8 *recv_buffer; 81 81 static struct hvutil_transport *hvt; 82 - static struct completion release_event; 83 82 84 83 static void vss_timeout_func(struct work_struct *dummy); 85 84 static void vss_handle_request(struct work_struct *dummy); ··· 360 361 if (cancel_delayed_work_sync(&vss_timeout_work)) 361 362 vss_respond_to_host(HV_E_FAIL); 362 363 vss_transaction.state = HVUTIL_DEVICE_INIT; 363 - complete(&release_event); 364 364 } 365 365 366 366 int 367 367 hv_vss_init(struct hv_util_service *srv) 368 368 { 369 - init_completion(&release_event); 370 369 if (vmbus_proto_version < VERSION_WIN8_1) { 371 370 pr_warn("Integration service 'Backup (volume snapshot)'" 372 371 " not supported on this host version.\n"); ··· 397 400 cancel_delayed_work_sync(&vss_timeout_work); 398 401 cancel_work_sync(&vss_handle_request_work); 399 402 hvutil_transport_destroy(hvt); 400 - wait_for_completion(&release_event); 401 403 }
+8 -4
drivers/hv/hv_utils_transport.c
··· 182 182 * connects back. 183 183 */ 184 184 hvt_reset(hvt); 185 - mutex_unlock(&hvt->lock); 186 185 187 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 191 return 0; 191 192 } ··· 305 304 306 305 init_waitqueue_head(&hvt->outmsg_q); 307 306 mutex_init(&hvt->lock); 307 + init_completion(&hvt->release); 308 308 309 309 spin_lock(&hvt_list_lock); 310 310 list_add(&hvt->list, &hvt_list); ··· 353 351 if (hvt->cn_id.idx > 0 && hvt->cn_id.val > 0) 354 352 cn_del_callback(&hvt->cn_id); 355 353 356 - if (mode_old != HVUTIL_TRANSPORT_CHARDEV) 357 - hvt_transport_free(hvt); 354 + if (mode_old == HVUTIL_TRANSPORT_CHARDEV) 355 + wait_for_completion(&hvt->release); 356 + 357 + hvt_transport_free(hvt); 358 358 }
+1
drivers/hv/hv_utils_transport.h
··· 41 41 int outmsg_len; /* its length */ 42 42 wait_queue_head_t outmsg_q; /* poll/read wait queue */ 43 43 struct mutex lock; /* protects struct members */ 44 + struct completion release; /* synchronize with fd release */ 44 45 }; 45 46 46 47 struct hvutil_transport *hvutil_transport_init(const char *name,