diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c index 1ffa904837b3..2d4fe24cecbf 100644 --- a/drivers/hv/mshv_vtl_main.c +++ b/drivers/hv/mshv_vtl_main.c @@ -73,6 +73,7 @@ struct mshv_vtl_poll_file { wait_queue_entry_t wait; wait_queue_head_t *wqh; poll_table pt; + int error; int cpu; }; @@ -482,7 +483,18 @@ static void mshv_vtl_ptable_queue_proc(struct file *file, wait_queue_head_t *wqh { struct mshv_vtl_poll_file *poll_file = container_of(pt, struct mshv_vtl_poll_file, pt); - WARN_ON(poll_file->wqh); + if (poll_file->error) + return; + + if (poll_file->wqh) { + if (poll_file->wqh == wqh) + return; + + mshv_vtl_poll_file_remove_wait_queue(poll_file); + poll_file->error = -EINVAL; + return; + } + poll_file->wqh = wqh; add_wait_queue(wqh, &poll_file->wait); } @@ -492,6 +504,7 @@ static int mshv_vtl_ioctl_set_poll_file(struct mshv_vtl_set_poll_file __user *us struct file *file, *old_file; struct mshv_vtl_poll_file *poll_file; struct mshv_vtl_set_poll_file input; + int ret; if (copy_from_user(&input, user_input, sizeof(input))) return -EFAULT; @@ -518,6 +531,7 @@ static int mshv_vtl_ioctl_set_poll_file(struct mshv_vtl_set_poll_file __user *us old_file = poll_file->file; poll_file->file = file; + poll_file->error = 0; poll_file->cpu = input.cpu; if (file) { @@ -525,13 +539,18 @@ static int mshv_vtl_ioctl_set_poll_file(struct mshv_vtl_set_poll_file __user *us init_poll_funcptr(&poll_file->pt, mshv_vtl_ptable_queue_proc); vfs_poll(file, &poll_file->pt); } + ret = poll_file->error; + if (ret) + poll_file->file = NULL; mutex_unlock(&mshv_vtl_poll_file_lock); if (old_file) fput(old_file); + if (ret) + fput(file); - return 0; + return ret; } /* Static table mapping register names to their corresponding actions */