From f932bcea6b7317312ab38df12a84710fc6c67a81 Mon Sep 17 00:00:00 2001 From: Stefan Weinhuber Date: Mon, 9 Aug 2010 18:12:59 +0200 Subject: [PATCH] [S390] dasd: allocate fallback cqr for reserve/release The DASD reserve and release ioctls use the preallocated memory pool of the respective device to build their CCW requests. However, when the device is busy, the pool may already be empty and the ioctl fails. Usually this can be recovered by calling the ioctl again, but in a situation in which we need to issue an unconditional reserve to make a device operational again, this would be not recoverable. To avoid a failure due to lack of memory, DASD device driver will preallocate enough memory for a single reserve/release request, which can be used if normal allocation fails. Signed-off-by: Stefan Weinhuber Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_eckd.c | 73 ++++++++++++++++++++++++++++------ 1 file changed, 60 insertions(+), 13 deletions(-) diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index ab84da5592e8..0483b2e76b11 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */ #define INIT_CQR_UNFORMATTED 1 #define INIT_CQR_ERROR 2 +/* emergency request for reserve/release */ +static struct { + struct dasd_ccw_req cqr; + struct ccw1 ccw; + char data[32]; +} *dasd_reserve_req; +static DEFINE_MUTEX(dasd_reserve_mutex); + /* initial attempt at a probe function. this can be simplified once * the other detection code is gone */ @@ -2645,15 +2653,23 @@ dasd_eckd_release(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RELEASE; @@ -2671,7 +2687,10 @@ dasd_eckd_release(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -2687,15 +2706,23 @@ dasd_eckd_reserve(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_RESERVE; @@ -2713,7 +2740,10 @@ dasd_eckd_reserve(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -2728,15 +2758,23 @@ dasd_eckd_steal_lock(struct dasd_device *device) struct dasd_ccw_req *cqr; int rc; struct ccw1 *ccw; + int useglobal; if (!capable(CAP_SYS_ADMIN)) return -EACCES; + useglobal = 0; cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); if (IS_ERR(cqr)) { - DBF_DEV_EVENT(DBF_WARNING, device, "%s", - "Could not allocate initialization request"); - return PTR_ERR(cqr); + mutex_lock(&dasd_reserve_mutex); + useglobal = 1; + cqr = &dasd_reserve_req->cqr; + memset(cqr, 0, sizeof(*cqr)); + memset(&dasd_reserve_req->ccw, 0, + sizeof(dasd_reserve_req->ccw)); + cqr->cpaddr = &dasd_reserve_req->ccw; + cqr->data = &dasd_reserve_req->data; + cqr->magic = DASD_ECKD_MAGIC; } ccw = cqr->cpaddr; ccw->cmd_code = DASD_ECKD_CCW_SLCK; @@ -2754,7 +2792,10 @@ dasd_eckd_steal_lock(struct dasd_device *device) rc = dasd_sleep_on_immediatly(cqr); - dasd_sfree_request(cqr, cqr->memdev); + if (useglobal) + mutex_unlock(&dasd_reserve_mutex); + else + dasd_sfree_request(cqr, cqr->memdev); return rc; } @@ -3488,10 +3529,15 @@ dasd_eckd_init(void) int ret; ASCEBC(dasd_eckd_discipline.ebcname, 4); + dasd_reserve_req = kmalloc(sizeof(*dasd_reserve_req), + GFP_KERNEL | GFP_DMA); + if (!dasd_reserve_req) + return -ENOMEM; ret = ccw_driver_register(&dasd_eckd_driver); if (!ret) wait_for_device_probe(); - + else + kfree(dasd_reserve_req); return ret; } @@ -3499,6 +3545,7 @@ static void __exit dasd_eckd_cleanup(void) { ccw_driver_unregister(&dasd_eckd_driver); + kfree(dasd_reserve_req); } module_init(dasd_eckd_init);