diff options
author | Juergen Gross <jgross@suse.com> | 2019-10-01 11:03:55 -0400 |
---|---|---|
committer | Boris Ostrovsky <boris.ostrovsky@oracle.com> | 2019-10-02 16:40:11 -0400 |
commit | a8fabb38525c51a094607768bac3ba46b3f4a9d5 (patch) | |
tree | 2cd7beab8e2e789f2587ae722d28c4d908d50c02 | |
parent | 09515706857a7d5a2ffb5ce6a44c0bc7859a745b (diff) |
xen/xenbus: fix self-deadlock after killing user process
In case a user process using xenbus has open transactions and is killed
e.g. via ctrl-C the following cleanup of the allocated resources might
result in a deadlock due to trying to end a transaction in the xenbus
worker thread:
[ 2551.474706] INFO: task xenbus:37 blocked for more than 120 seconds.
[ 2551.492215] Tainted: P OE 5.0.0-29-generic #5
[ 2551.510263] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[ 2551.528585] xenbus D 0 37 2 0x80000080
[ 2551.528590] Call Trace:
[ 2551.528603] __schedule+0x2c0/0x870
[ 2551.528606] ? _cond_resched+0x19/0x40
[ 2551.528632] schedule+0x2c/0x70
[ 2551.528637] xs_talkv+0x1ec/0x2b0
[ 2551.528642] ? wait_woken+0x80/0x80
[ 2551.528645] xs_single+0x53/0x80
[ 2551.528648] xenbus_transaction_end+0x3b/0x70
[ 2551.528651] xenbus_file_free+0x5a/0x160
[ 2551.528654] xenbus_dev_queue_reply+0xc4/0x220
[ 2551.528657] xenbus_thread+0x7de/0x880
[ 2551.528660] ? wait_woken+0x80/0x80
[ 2551.528665] kthread+0x121/0x140
[ 2551.528667] ? xb_read+0x1d0/0x1d0
[ 2551.528670] ? kthread_park+0x90/0x90
[ 2551.528673] ret_from_fork+0x35/0x40
Fix this by doing the cleanup via a workqueue instead.
Reported-by: James Dingwall <james@dingwall.me.uk>
Fixes: fd8aa9095a95c ("xen: optimize xenbus driver for multiple concurrent xenstore accesses")
Cc: <stable@vger.kernel.org> # 4.11
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
-rw-r--r-- | drivers/xen/xenbus/xenbus_dev_frontend.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index 08adc590f631..597af455a522 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c | |||
@@ -55,6 +55,7 @@ | |||
55 | #include <linux/string.h> | 55 | #include <linux/string.h> |
56 | #include <linux/slab.h> | 56 | #include <linux/slab.h> |
57 | #include <linux/miscdevice.h> | 57 | #include <linux/miscdevice.h> |
58 | #include <linux/workqueue.h> | ||
58 | 59 | ||
59 | #include <xen/xenbus.h> | 60 | #include <xen/xenbus.h> |
60 | #include <xen/xen.h> | 61 | #include <xen/xen.h> |
@@ -116,6 +117,8 @@ struct xenbus_file_priv { | |||
116 | wait_queue_head_t read_waitq; | 117 | wait_queue_head_t read_waitq; |
117 | 118 | ||
118 | struct kref kref; | 119 | struct kref kref; |
120 | |||
121 | struct work_struct wq; | ||
119 | }; | 122 | }; |
120 | 123 | ||
121 | /* Read out any raw xenbus messages queued up. */ | 124 | /* Read out any raw xenbus messages queued up. */ |
@@ -300,14 +303,14 @@ static void watch_fired(struct xenbus_watch *watch, | |||
300 | mutex_unlock(&adap->dev_data->reply_mutex); | 303 | mutex_unlock(&adap->dev_data->reply_mutex); |
301 | } | 304 | } |
302 | 305 | ||
303 | static void xenbus_file_free(struct kref *kref) | 306 | static void xenbus_worker(struct work_struct *wq) |
304 | { | 307 | { |
305 | struct xenbus_file_priv *u; | 308 | struct xenbus_file_priv *u; |
306 | struct xenbus_transaction_holder *trans, *tmp; | 309 | struct xenbus_transaction_holder *trans, *tmp; |
307 | struct watch_adapter *watch, *tmp_watch; | 310 | struct watch_adapter *watch, *tmp_watch; |
308 | struct read_buffer *rb, *tmp_rb; | 311 | struct read_buffer *rb, *tmp_rb; |
309 | 312 | ||
310 | u = container_of(kref, struct xenbus_file_priv, kref); | 313 | u = container_of(wq, struct xenbus_file_priv, wq); |
311 | 314 | ||
312 | /* | 315 | /* |
313 | * No need for locking here because there are no other users, | 316 | * No need for locking here because there are no other users, |
@@ -333,6 +336,18 @@ static void xenbus_file_free(struct kref *kref) | |||
333 | kfree(u); | 336 | kfree(u); |
334 | } | 337 | } |
335 | 338 | ||
339 | static void xenbus_file_free(struct kref *kref) | ||
340 | { | ||
341 | struct xenbus_file_priv *u; | ||
342 | |||
343 | /* | ||
344 | * We might be called in xenbus_thread(). | ||
345 | * Use workqueue to avoid deadlock. | ||
346 | */ | ||
347 | u = container_of(kref, struct xenbus_file_priv, kref); | ||
348 | schedule_work(&u->wq); | ||
349 | } | ||
350 | |||
336 | static struct xenbus_transaction_holder *xenbus_get_transaction( | 351 | static struct xenbus_transaction_holder *xenbus_get_transaction( |
337 | struct xenbus_file_priv *u, uint32_t tx_id) | 352 | struct xenbus_file_priv *u, uint32_t tx_id) |
338 | { | 353 | { |
@@ -650,6 +665,7 @@ static int xenbus_file_open(struct inode *inode, struct file *filp) | |||
650 | INIT_LIST_HEAD(&u->watches); | 665 | INIT_LIST_HEAD(&u->watches); |
651 | INIT_LIST_HEAD(&u->read_buffers); | 666 | INIT_LIST_HEAD(&u->read_buffers); |
652 | init_waitqueue_head(&u->read_waitq); | 667 | init_waitqueue_head(&u->read_waitq); |
668 | INIT_WORK(&u->wq, xenbus_worker); | ||
653 | 669 | ||
654 | mutex_init(&u->reply_mutex); | 670 | mutex_init(&u->reply_mutex); |
655 | mutex_init(&u->msgbuffer_mutex); | 671 | mutex_init(&u->msgbuffer_mutex); |