Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9487cfd3 authored by Stefan Haberland's avatar Stefan Haberland Committed by Martin Schwidefsky
Browse files

s390/dasd: fix handling of internal requests



Internal DASD device driver I/O such as query host access count or
path verification is started using the _sleep_on() function.
To mark a request as started or ended the callback_data is set to either
DASD_SLEEPON_START_TAG or DASD_SLEEPON_END_TAG.

In cases where the request has to be stopped unconditionally the status is
set to DASD_SLEEPON_END_TAG as well which leads to immediate clearing of
the request.
But the request might still be on a device request queue for normal
operation which might lead to a panic because of a BUG() statement in
__dasd_device_process_final_queue() or a list corruption of the device
request queue.

Fix by removing the setting of DASD_SLEEPON_END_TAG in the
dasd_cancel_req() and dasd_generic_requeue_all_requests() functions and
ensure that the request is not deleted in the requeue function.
Trigger the device tasklet in the requeue function and let the normal
processing cleanup the request.

Signed-off-by: default avatarStefan Haberland <sth@linux.vnet.ibm.com>
Reviewed-by: default avatarJan Hoeppner <hoeppner@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 91ab883e
Loading
Loading
Loading
Loading
+7 −14
Original line number Original line Diff line number Diff line
@@ -2581,8 +2581,6 @@ int dasd_cancel_req(struct dasd_ccw_req *cqr)
	case DASD_CQR_QUEUED:
	case DASD_CQR_QUEUED:
		/* request was not started - just set to cleared */
		/* request was not started - just set to cleared */
		cqr->status = DASD_CQR_CLEARED;
		cqr->status = DASD_CQR_CLEARED;
		if (cqr->callback_data == DASD_SLEEPON_START_TAG)
			cqr->callback_data = DASD_SLEEPON_END_TAG;
		break;
		break;
	case DASD_CQR_IN_IO:
	case DASD_CQR_IN_IO:
		/* request in IO - terminate IO and release again */
		/* request in IO - terminate IO and release again */
@@ -3902,9 +3900,12 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
		wait_event(dasd_flush_wq,
		wait_event(dasd_flush_wq,
			   (cqr->status != DASD_CQR_CLEAR_PENDING));
			   (cqr->status != DASD_CQR_CLEAR_PENDING));


		/* mark sleepon requests as ended */
		/*
		if (cqr->callback_data == DASD_SLEEPON_START_TAG)
		 * requeue requests to blocklayer will only work
			cqr->callback_data = DASD_SLEEPON_END_TAG;
		 * for block device requests
		 */
		if (_dasd_requeue_request(cqr))
			continue;


		/* remove requests from device and block queue */
		/* remove requests from device and block queue */
		list_del_init(&cqr->devlist);
		list_del_init(&cqr->devlist);
@@ -3917,13 +3918,6 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
			cqr = refers;
			cqr = refers;
		}
		}


		/*
		 * requeue requests to blocklayer will only work
		 * for block device requests
		 */
		if (_dasd_requeue_request(cqr))
			continue;

		if (cqr->block)
		if (cqr->block)
			list_del_init(&cqr->blocklist);
			list_del_init(&cqr->blocklist);
		cqr->block->base->discipline->free_cp(
		cqr->block->base->discipline->free_cp(
@@ -3940,8 +3934,7 @@ static int dasd_generic_requeue_all_requests(struct dasd_device *device)
		list_splice_tail(&requeue_queue, &device->ccw_queue);
		list_splice_tail(&requeue_queue, &device->ccw_queue);
		spin_unlock_irq(get_ccwdev_lock(device->cdev));
		spin_unlock_irq(get_ccwdev_lock(device->cdev));
	}
	}
	/* wake up generic waitqueue for eventually ended sleepon requests */
	dasd_schedule_device_bh(device);
	wake_up(&generic_waitq);
	return rc;
	return rc;
}
}