FAILED: patch "[PATCH] s390/qdio: fix roll-back after timeout on ESTABLISH ccw" failed to apply to 5.4-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 2c197870e4701610ec3b1143808d4e31152caf30 Mon Sep 17 00:00:00 2001
From: Julian Wiedmann <[email protected]>
Date: Mon, 31 May 2021 18:40:06 +0300
Subject: [PATCH] s390/qdio: fix roll-back after timeout on ESTABLISH ccw
When qdio_establish() times out while waiting for the ESTABLISH ccw to complete, it calls qdio_shutdown() to roll back all of its previous actions. But at this point the qdio_irq's state is still QDIO_IRQ_STATE_INACTIVE, so qdio_shutdown() will exit immediately without doing any actual work.
Which means that eg. the qdio_irq's thinint-indicator stays registered, and cdev->handler isn't restored to its old value. And since commit 954d6235be41 ("s390/qdio: make thinint registration symmetric") the qdio_irq also stays on the tiq_list, so on the next qdio_establish() we might get a helpful BUG from the list-debugging code:
...
[ 4633.512591] list_add double add: new=00000000005a4110, prev=00000001b357db78, next=00000000005a4110. [ 4633.512621] ------------[ cut here ]------------ [ 4633.512623] kernel BUG at lib/list_debug.c:29! ... [ 4633.512796] [<00000001b2c6ee9a>] __list_add_valid+0x82/0xa0 [ 4633.512798] ([<00000001b2c6ee96>] __list_add_valid+0x7e/0xa0) [ 4633.512800] [<00000001b2fcecce>] qdio_establish_thinint+0x116/0x190 [ 4633.512805] [<00000001b2fcbe58>] qdio_establish+0x128/0x498
...
Fix this by extracting a goto-chain from the existing error exits in qdio_establish(), and check the return value of the wait_event_...() to detect the timeout condition.
drivers/s390/cio/qdio_main.c +19 -12
@@ -1083,6 +1083,7 @@ int qdio_establish(struct ccw_device *cdev, {struct qdio_irq *irq_ptr = cdev->private->qdio_data;struct subchannel_id schid; +long timeout;int rc;ccw_device_get_schid (cdev, &schid);
@@ -1111,11 +1112,8 @@ int qdio_establish(struct ccw_device *cdev,qdio_setup_irq (irq_ptr, init_data); rc =qdio_establish_thinint (irq_ptr); -if (rc) { -qdio_shutdown_irq (irq_ptr); -mutex_unlock (&irq_ptr->setup_mutex); -return rc; - } +if (rc) + goto err_thinint;/* establish q */ irq_ptr->ccw.cmd_code = irq_ptr->equeue.cmd;
@@ -1131,15 +1129,16 @@ int qdio_establish(struct ccw_device *cdev,if (rc) {DBF_ERROR ("%4x est IO ERR" , irq_ptr->schid.sch_no);DBF_ERROR ("rc:%4x" , rc); -qdio_shutdown_thinint (irq_ptr); -qdio_shutdown_irq (irq_ptr); -mutex_unlock (&irq_ptr->setup_mutex); -return rc; + goto err_ccw_start; } -wait_event_interruptible_timeout (cdev->private->wait_q, - irq_ptr->state ==QDIO_IRQ_STATE_ESTABLISHED || - irq_ptr->state ==QDIO_IRQ_STATE_ERR ,HZ ); + timeout =wait_event_interruptible_timeout (cdev->private->wait_q, + irq_ptr->state ==QDIO_IRQ_STATE_ESTABLISHED || + irq_ptr->state ==QDIO_IRQ_STATE_ERR ,HZ ); +if (timeout <=0 ) { + rc = (timeout == -ERESTARTSYS ) ? -EINTR : -ETIME ; + goto err_ccw_timeout; + }if (irq_ptr->state !=QDIO_IRQ_STATE_ESTABLISHED ) {mutex_unlock (&irq_ptr->setup_mutex);
@@ -1156,6 +1155,14 @@ int qdio_establish(struct ccw_device *cdev,qdio_print_subchannel_info (irq_ptr);qdio_setup_debug_entries (irq_ptr);return 0 ; + +err_ccw_timeout: +err_ccw_start: +qdio_shutdown_thinint (irq_ptr); +err_thinint: +qdio_shutdown_irq (irq_ptr); +mutex_unlock (&irq_ptr->setup_mutex); +return rc; }EXPORT_SYMBOL_GPL (qdio_establish);