summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Ott <sebott@linux.ibm.com>2018-06-25 11:23:26 +0200
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2018-07-17 07:27:54 +0200
commit05b217f4c5573f34f6799698f7d4162c702132bc (patch)
tree5678caf88c1ae544b4f3f81f4cdc8332d0ba19b5
parent71aa11a40d1a1d80196b55d8dd95be2bc4c1649e (diff)
s390/css: validate subchannel prior to allocation
In css_alloc_subchannel we allocate the subchannel and do a validation of the subchannel (to decide if we should look for devices via this subchannel). On a typical LPAR we find lots of subchannels to be invalid (because there is no device attached or the device is blacklisted) leading to lots of useless kmalloc and kfree calls. This patch changes the order to only allocate the subchannels that have been found valid. Signed-off-by: Sebastian Ott <sebott@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r--drivers/s390/cio/cio.c40
-rw-r--r--drivers/s390/cio/cio.h2
-rw-r--r--drivers/s390/cio/css.c11
3 files changed, 23 insertions, 30 deletions
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 5130d7c67239..4b8f29f83421 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -526,34 +526,19 @@ int cio_disable_subchannel(struct subchannel *sch)
}
EXPORT_SYMBOL_GPL(cio_disable_subchannel);
-static int cio_check_devno_blacklisted(struct subchannel *sch)
-{
- if (is_blacklisted(sch->schid.ssid, sch->schib.pmcw.dev)) {
- /*
- * This device must not be known to Linux. So we simply
- * say that there is no device and return ENODEV.
- */
- CIO_MSG_EVENT(6, "Blacklisted device detected "
- "at devno %04X, subchannel set %x\n",
- sch->schib.pmcw.dev, sch->schid.ssid);
- return -ENODEV;
- }
- return 0;
-}
-
/**
* cio_validate_subchannel - basic validation of subchannel
- * @sch: subchannel structure to be filled out
* @schid: subchannel id
+ * @schib: subchannel information block to be filled out
*
- * Find out subchannel type and initialize struct subchannel.
+ * Check if subchannel is valid and should be used.
* Return codes:
* 0 on success
* -ENXIO for non-defined subchannels
* -ENODEV for invalid subchannels or blacklisted devices
* -EIO for subchannels in an invalid subchannel set
*/
-int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
+int cio_validate_subchannel(struct subchannel_id schid, struct schib *schib)
{
char dbf_txt[15];
int ccode;
@@ -568,21 +553,24 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
* If stsch gets an exception, it means the current subchannel set
* is not valid.
*/
- ccode = stsch(schid, &sch->schib);
+ ccode = stsch(schid, schib);
if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode;
goto out;
}
- sch->st = sch->schib.pmcw.st;
- sch->schid = schid;
- switch (sch->st) {
+ switch (schib->pmcw.st) {
case SUBCHANNEL_TYPE_IO:
case SUBCHANNEL_TYPE_MSG:
- if (!css_sch_is_valid(&sch->schib))
+ if (!css_sch_is_valid(schib))
err = -ENODEV;
- else
- err = cio_check_devno_blacklisted(sch);
+ else if (is_blacklisted(schid.ssid, schib->pmcw.dev)) {
+ CIO_MSG_EVENT(6, "Blacklisted device detected "
+ "at devno %04X, subchannel set %x\n",
+ schib->pmcw.dev, schid.ssid);
+ err = -ENODEV;
+ } else
+ err = 0;
break;
default:
err = 0;
@@ -591,7 +579,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
goto out;
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n",
- sch->schid.ssid, sch->schid.sch_no, sch->st);
+ schid.ssid, schid.sch_no, schib->pmcw.st);
out:
return err;
}
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 94cd813bdcfe..234aa068dd8f 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -119,7 +119,7 @@ DECLARE_PER_CPU(struct irb, cio_irb);
#define to_subchannel(n) container_of(n, struct subchannel, dev)
-extern int cio_validate_subchannel (struct subchannel *, struct subchannel_id);
+extern int cio_validate_subchannel(struct subchannel_id, struct schib *);
extern int cio_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index e608e8cad88e..e4d6537cdd87 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -171,15 +171,20 @@ static void css_subchannel_release(struct device *dev)
struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
{
struct subchannel *sch;
+ struct schib schib;
int ret;
+ ret = cio_validate_subchannel(schid, &schib);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA);
if (!sch)
return ERR_PTR(-ENOMEM);
- ret = cio_validate_subchannel(sch, schid);
- if (ret < 0)
- goto err;
+ sch->schid = schid;
+ sch->schib = schib;
+ sch->st = schib.pmcw.st;
ret = css_sch_create_locks(sch);
if (ret)