Commit f932bcea authored by Stefan Weinhuber's avatar Stefan Weinhuber Committed by Martin Schwidefsky

[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: default avatarStefan Weinhuber <wein@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent eafd2b6d
...@@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */ ...@@ -82,6 +82,14 @@ static struct ccw_driver dasd_eckd_driver; /* see below */
#define INIT_CQR_UNFORMATTED 1 #define INIT_CQR_UNFORMATTED 1
#define INIT_CQR_ERROR 2 #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 /* initial attempt at a probe function. this can be simplified once
* the other detection code is gone */ * the other detection code is gone */
...@@ -2645,15 +2653,23 @@ dasd_eckd_release(struct dasd_device *device) ...@@ -2645,15 +2653,23 @@ dasd_eckd_release(struct dasd_device *device)
struct dasd_ccw_req *cqr; struct dasd_ccw_req *cqr;
int rc; int rc;
struct ccw1 *ccw; struct ccw1 *ccw;
int useglobal;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
useglobal = 0;
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
if (IS_ERR(cqr)) { if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s", mutex_lock(&dasd_reserve_mutex);
"Could not allocate initialization request"); useglobal = 1;
return PTR_ERR(cqr); 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 = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_RELEASE; ccw->cmd_code = DASD_ECKD_CCW_RELEASE;
...@@ -2671,7 +2687,10 @@ dasd_eckd_release(struct dasd_device *device) ...@@ -2671,7 +2687,10 @@ dasd_eckd_release(struct dasd_device *device)
rc = dasd_sleep_on_immediatly(cqr); 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; return rc;
} }
...@@ -2687,15 +2706,23 @@ dasd_eckd_reserve(struct dasd_device *device) ...@@ -2687,15 +2706,23 @@ dasd_eckd_reserve(struct dasd_device *device)
struct dasd_ccw_req *cqr; struct dasd_ccw_req *cqr;
int rc; int rc;
struct ccw1 *ccw; struct ccw1 *ccw;
int useglobal;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
useglobal = 0;
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
if (IS_ERR(cqr)) { if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s", mutex_lock(&dasd_reserve_mutex);
"Could not allocate initialization request"); useglobal = 1;
return PTR_ERR(cqr); 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 = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_RESERVE; ccw->cmd_code = DASD_ECKD_CCW_RESERVE;
...@@ -2713,7 +2740,10 @@ dasd_eckd_reserve(struct dasd_device *device) ...@@ -2713,7 +2740,10 @@ dasd_eckd_reserve(struct dasd_device *device)
rc = dasd_sleep_on_immediatly(cqr); 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; return rc;
} }
...@@ -2728,15 +2758,23 @@ dasd_eckd_steal_lock(struct dasd_device *device) ...@@ -2728,15 +2758,23 @@ dasd_eckd_steal_lock(struct dasd_device *device)
struct dasd_ccw_req *cqr; struct dasd_ccw_req *cqr;
int rc; int rc;
struct ccw1 *ccw; struct ccw1 *ccw;
int useglobal;
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EACCES; return -EACCES;
useglobal = 0;
cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device); cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1, 32, device);
if (IS_ERR(cqr)) { if (IS_ERR(cqr)) {
DBF_DEV_EVENT(DBF_WARNING, device, "%s", mutex_lock(&dasd_reserve_mutex);
"Could not allocate initialization request"); useglobal = 1;
return PTR_ERR(cqr); 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 = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_SLCK; ccw->cmd_code = DASD_ECKD_CCW_SLCK;
...@@ -2754,7 +2792,10 @@ dasd_eckd_steal_lock(struct dasd_device *device) ...@@ -2754,7 +2792,10 @@ dasd_eckd_steal_lock(struct dasd_device *device)
rc = dasd_sleep_on_immediatly(cqr); 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; return rc;
} }
...@@ -3488,10 +3529,15 @@ dasd_eckd_init(void) ...@@ -3488,10 +3529,15 @@ dasd_eckd_init(void)
int ret; int ret;
ASCEBC(dasd_eckd_discipline.ebcname, 4); 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); ret = ccw_driver_register(&dasd_eckd_driver);
if (!ret) if (!ret)
wait_for_device_probe(); wait_for_device_probe();
else
kfree(dasd_reserve_req);
return ret; return ret;
} }
...@@ -3499,6 +3545,7 @@ static void __exit ...@@ -3499,6 +3545,7 @@ static void __exit
dasd_eckd_cleanup(void) dasd_eckd_cleanup(void)
{ {
ccw_driver_unregister(&dasd_eckd_driver); ccw_driver_unregister(&dasd_eckd_driver);
kfree(dasd_reserve_req);
} }
module_init(dasd_eckd_init); module_init(dasd_eckd_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment