Commit 05b217f4 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky

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: default avatarSebastian Ott <sebott@linux.ibm.com>
Reviewed-by: default avatarPeter Oberparleiter <oberpar@linux.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 71aa11a4
...@@ -526,34 +526,19 @@ int cio_disable_subchannel(struct subchannel *sch) ...@@ -526,34 +526,19 @@ int cio_disable_subchannel(struct subchannel *sch)
} }
EXPORT_SYMBOL_GPL(cio_disable_subchannel); 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 * cio_validate_subchannel - basic validation of subchannel
* @sch: subchannel structure to be filled out
* @schid: subchannel id * @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: * Return codes:
* 0 on success * 0 on success
* -ENXIO for non-defined subchannels * -ENXIO for non-defined subchannels
* -ENODEV for invalid subchannels or blacklisted devices * -ENODEV for invalid subchannels or blacklisted devices
* -EIO for subchannels in an invalid subchannel set * -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]; char dbf_txt[15];
int ccode; int ccode;
...@@ -568,21 +553,24 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) ...@@ -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 * If stsch gets an exception, it means the current subchannel set
* is not valid. * is not valid.
*/ */
ccode = stsch(schid, &sch->schib); ccode = stsch(schid, schib);
if (ccode) { if (ccode) {
err = (ccode == 3) ? -ENXIO : ccode; err = (ccode == 3) ? -ENXIO : ccode;
goto out; 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_IO:
case SUBCHANNEL_TYPE_MSG: case SUBCHANNEL_TYPE_MSG:
if (!css_sch_is_valid(&sch->schib)) if (!css_sch_is_valid(schib))
err = -ENODEV; err = -ENODEV;
else else if (is_blacklisted(schid.ssid, schib->pmcw.dev)) {
err = cio_check_devno_blacklisted(sch); 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; break;
default: default:
err = 0; err = 0;
...@@ -591,7 +579,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) ...@@ -591,7 +579,7 @@ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid)
goto out; goto out;
CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n", 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: out:
return err; return err;
} }
......
...@@ -119,7 +119,7 @@ DECLARE_PER_CPU(struct irb, cio_irb); ...@@ -119,7 +119,7 @@ DECLARE_PER_CPU(struct irb, cio_irb);
#define to_subchannel(n) container_of(n, struct subchannel, dev) #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_enable_subchannel(struct subchannel *, u32);
extern int cio_disable_subchannel (struct subchannel *); extern int cio_disable_subchannel (struct subchannel *);
extern int cio_cancel (struct subchannel *); extern int cio_cancel (struct subchannel *);
......
...@@ -171,15 +171,20 @@ static void css_subchannel_release(struct device *dev) ...@@ -171,15 +171,20 @@ static void css_subchannel_release(struct device *dev)
struct subchannel *css_alloc_subchannel(struct subchannel_id schid) struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
{ {
struct subchannel *sch; struct subchannel *sch;
struct schib schib;
int ret; int ret;
ret = cio_validate_subchannel(schid, &schib);
if (ret < 0)
return ERR_PTR(ret);
sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA); sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA);
if (!sch) if (!sch)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
ret = cio_validate_subchannel(sch, schid); sch->schid = schid;
if (ret < 0) sch->schib = schib;
goto err; sch->st = schib.pmcw.st;
ret = css_sch_create_locks(sch); ret = css_sch_create_locks(sch);
if (ret) if (ret)
......
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