| From 11c2d78b5d3ebc50ec9c9a1ec18614cdadd95346 Mon Sep 17 00:00:00 2001 |
| From: Juergen Gross <jgross@suse.com> |
| Date: Tue, 1 Oct 2019 17:03:55 +0200 |
| Subject: [PATCH] xen/xenbus: fix self-deadlock after killing user process |
| |
| commit a8fabb38525c51a094607768bac3ba46b3f4a9d5 upstream. |
| |
| 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> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| 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 @@ |
| #include <linux/string.h> |
| #include <linux/slab.h> |
| #include <linux/miscdevice.h> |
| +#include <linux/workqueue.h> |
| |
| #include <xen/xenbus.h> |
| #include <xen/xen.h> |
| @@ -116,6 +117,8 @@ struct xenbus_file_priv { |
| wait_queue_head_t read_waitq; |
| |
| struct kref kref; |
| + |
| + struct work_struct wq; |
| }; |
| |
| /* Read out any raw xenbus messages queued up. */ |
| @@ -300,14 +303,14 @@ static void watch_fired(struct xenbus_watch *watch, |
| mutex_unlock(&adap->dev_data->reply_mutex); |
| } |
| |
| -static void xenbus_file_free(struct kref *kref) |
| +static void xenbus_worker(struct work_struct *wq) |
| { |
| struct xenbus_file_priv *u; |
| struct xenbus_transaction_holder *trans, *tmp; |
| struct watch_adapter *watch, *tmp_watch; |
| struct read_buffer *rb, *tmp_rb; |
| |
| - u = container_of(kref, struct xenbus_file_priv, kref); |
| + u = container_of(wq, struct xenbus_file_priv, wq); |
| |
| /* |
| * No need for locking here because there are no other users, |
| @@ -333,6 +336,18 @@ static void xenbus_file_free(struct kref *kref) |
| kfree(u); |
| } |
| |
| +static void xenbus_file_free(struct kref *kref) |
| +{ |
| + struct xenbus_file_priv *u; |
| + |
| + /* |
| + * We might be called in xenbus_thread(). |
| + * Use workqueue to avoid deadlock. |
| + */ |
| + u = container_of(kref, struct xenbus_file_priv, kref); |
| + schedule_work(&u->wq); |
| +} |
| + |
| static struct xenbus_transaction_holder *xenbus_get_transaction( |
| struct xenbus_file_priv *u, uint32_t tx_id) |
| { |
| @@ -650,6 +665,7 @@ static int xenbus_file_open(struct inode *inode, struct file *filp) |
| INIT_LIST_HEAD(&u->watches); |
| INIT_LIST_HEAD(&u->read_buffers); |
| init_waitqueue_head(&u->read_waitq); |
| + INIT_WORK(&u->wq, xenbus_worker); |
| |
| mutex_init(&u->reply_mutex); |
| mutex_init(&u->msgbuffer_mutex); |
| -- |
| 2.7.4 |
| |