mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-16 16:54:20 +08:00
[S390] cio: Fix parsing mechanism for blacklisted devices.
New format cssid.ssid.devno is now parsed correctly. Signed-off-by: Michael Ernst <mernst@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
139b83dd57
commit
5b8909871b
@ -19,6 +19,7 @@
|
||||
|
||||
#include <asm/cio.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/cio.h>
|
||||
|
||||
#include "blacklist.h"
|
||||
#include "cio.h"
|
||||
@ -43,163 +44,169 @@ typedef enum {add, free} range_action;
|
||||
* Function: blacklist_range
|
||||
* (Un-)blacklist the devices from-to
|
||||
*/
|
||||
static void
|
||||
blacklist_range (range_action action, unsigned int from, unsigned int to,
|
||||
unsigned int ssid)
|
||||
static int blacklist_range(range_action action, unsigned int from_ssid,
|
||||
unsigned int to_ssid, unsigned int from,
|
||||
unsigned int to, int msgtrigger)
|
||||
{
|
||||
if (!to)
|
||||
to = from;
|
||||
|
||||
if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
|
||||
printk (KERN_WARNING "cio: Invalid blacklist range "
|
||||
"0.%x.%04x to 0.%x.%04x, skipping\n",
|
||||
ssid, from, ssid, to);
|
||||
return;
|
||||
if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
|
||||
if (msgtrigger)
|
||||
printk(KERN_WARNING "cio: Invalid cio_ignore range "
|
||||
"0.%x.%04x-0.%x.%04x\n", from_ssid, from,
|
||||
to_ssid, to);
|
||||
return 1;
|
||||
}
|
||||
for (; from <= to; from++) {
|
||||
|
||||
while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
|
||||
(from <= to))) {
|
||||
if (action == add)
|
||||
set_bit (from, bl_dev[ssid]);
|
||||
set_bit(from, bl_dev[from_ssid]);
|
||||
else
|
||||
clear_bit (from, bl_dev[ssid]);
|
||||
clear_bit(from, bl_dev[from_ssid]);
|
||||
from++;
|
||||
if (from > __MAX_SUBCHANNEL) {
|
||||
from_ssid++;
|
||||
from = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: blacklist_busid
|
||||
* Get devno/busid from given string.
|
||||
* Shamelessly grabbed from dasd_devmap.c.
|
||||
*/
|
||||
static int
|
||||
blacklist_busid(char **str, int *id0, int *ssid, int *devno)
|
||||
{
|
||||
int val, old_style;
|
||||
char *sav;
|
||||
|
||||
sav = *str;
|
||||
|
||||
/* check for leading '0x' */
|
||||
old_style = 0;
|
||||
if ((*str)[0] == '0' && (*str)[1] == 'x') {
|
||||
*str += 2;
|
||||
old_style = 1;
|
||||
}
|
||||
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
|
||||
goto confused;
|
||||
val = simple_strtoul(*str, str, 16);
|
||||
if (old_style || (*str)[0] != '.') {
|
||||
*id0 = *ssid = 0;
|
||||
if (val < 0 || val > 0xffff)
|
||||
goto confused;
|
||||
*devno = val;
|
||||
if ((*str)[0] != ',' && (*str)[0] != '-' &&
|
||||
(*str)[0] != '\n' && (*str)[0] != '\0')
|
||||
goto confused;
|
||||
return 0;
|
||||
}
|
||||
/* New style x.y.z busid */
|
||||
if (val < 0 || val > 0xff)
|
||||
goto confused;
|
||||
*id0 = val;
|
||||
(*str)++;
|
||||
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
|
||||
goto confused;
|
||||
val = simple_strtoul(*str, str, 16);
|
||||
if (val < 0 || val > 0xff || (*str)++[0] != '.')
|
||||
goto confused;
|
||||
*ssid = val;
|
||||
if (!isxdigit((*str)[0])) /* We require at least one hex digit */
|
||||
goto confused;
|
||||
val = simple_strtoul(*str, str, 16);
|
||||
if (val < 0 || val > 0xffff)
|
||||
goto confused;
|
||||
*devno = val;
|
||||
if ((*str)[0] != ',' && (*str)[0] != '-' &&
|
||||
(*str)[0] != '\n' && (*str)[0] != '\0')
|
||||
goto confused;
|
||||
return 0;
|
||||
confused:
|
||||
strsep(str, ",\n");
|
||||
printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
blacklist_parse_parameters (char *str, range_action action)
|
||||
static int pure_hex(char **cp, unsigned int *val, int min_digit,
|
||||
int max_digit, int max_val)
|
||||
{
|
||||
int from, to, from_id0, to_id0, from_ssid, to_ssid;
|
||||
int diff;
|
||||
unsigned int value;
|
||||
|
||||
while (*str != 0 && *str != '\n') {
|
||||
range_action ra = action;
|
||||
while(*str == ',')
|
||||
str++;
|
||||
if (*str == '!') {
|
||||
ra = !action;
|
||||
++str;
|
||||
}
|
||||
diff = 0;
|
||||
*val = 0;
|
||||
|
||||
/*
|
||||
* Since we have to parse the proc commands and the
|
||||
* kernel arguments we have to check four cases
|
||||
*/
|
||||
if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
|
||||
strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
|
||||
int j;
|
||||
while (isxdigit(**cp) && (diff <= max_digit)) {
|
||||
|
||||
str += 3;
|
||||
for (j=0; j <= __MAX_SSID; j++)
|
||||
blacklist_range(ra, 0, __MAX_SUBCHANNEL, j);
|
||||
} else {
|
||||
int rc;
|
||||
|
||||
rc = blacklist_busid(&str, &from_id0,
|
||||
&from_ssid, &from);
|
||||
if (rc)
|
||||
continue;
|
||||
to = from;
|
||||
to_id0 = from_id0;
|
||||
to_ssid = from_ssid;
|
||||
if (*str == '-') {
|
||||
str++;
|
||||
rc = blacklist_busid(&str, &to_id0,
|
||||
&to_ssid, &to);
|
||||
if (rc)
|
||||
continue;
|
||||
}
|
||||
if (*str == '-') {
|
||||
printk(KERN_WARNING "cio: invalid cio_ignore "
|
||||
"parameter '%s'\n",
|
||||
strsep(&str, ",\n"));
|
||||
continue;
|
||||
}
|
||||
if ((from_id0 != to_id0) ||
|
||||
(from_ssid != to_ssid)) {
|
||||
printk(KERN_WARNING "cio: invalid cio_ignore "
|
||||
"range %x.%x.%04x-%x.%x.%04x\n",
|
||||
from_id0, from_ssid, from,
|
||||
to_id0, to_ssid, to);
|
||||
continue;
|
||||
}
|
||||
blacklist_range (ra, from, to, to_ssid);
|
||||
}
|
||||
if (isdigit(**cp))
|
||||
value = **cp - '0';
|
||||
else
|
||||
value = tolower(**cp) - 'a' + 10;
|
||||
*val = *val * 16 + value;
|
||||
(*cp)++;
|
||||
diff++;
|
||||
}
|
||||
return 1;
|
||||
|
||||
if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_busid(char *str, int *cssid, int *ssid, int *devno,
|
||||
int msgtrigger)
|
||||
{
|
||||
char *str_work;
|
||||
int val, rc, ret;
|
||||
|
||||
rc = 1;
|
||||
|
||||
if (*str == '\0')
|
||||
goto out;
|
||||
|
||||
/* old style */
|
||||
str_work = str;
|
||||
val = simple_strtoul(str, &str_work, 16);
|
||||
|
||||
if (*str_work == '\0') {
|
||||
if (val <= __MAX_SUBCHANNEL) {
|
||||
*devno = val;
|
||||
*ssid = 0;
|
||||
*cssid = 0;
|
||||
rc = 0;
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* new style */
|
||||
str_work = str;
|
||||
ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
|
||||
if (ret || (str_work[0] != '.'))
|
||||
goto out;
|
||||
str_work++;
|
||||
ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
|
||||
if (ret || (str_work[0] != '.'))
|
||||
goto out;
|
||||
str_work++;
|
||||
ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
|
||||
if (ret || (str_work[0] != '\0'))
|
||||
goto out;
|
||||
|
||||
rc = 0;
|
||||
out:
|
||||
if (rc && msgtrigger)
|
||||
printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n",
|
||||
str);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int blacklist_parse_parameters(char *str, range_action action,
|
||||
int msgtrigger)
|
||||
{
|
||||
int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
|
||||
int rc, totalrc;
|
||||
char *parm;
|
||||
range_action ra;
|
||||
|
||||
totalrc = 0;
|
||||
|
||||
while ((parm = strsep(&str, ","))) {
|
||||
rc = 0;
|
||||
ra = action;
|
||||
if (*parm == '!') {
|
||||
if (ra == add)
|
||||
ra = free;
|
||||
else
|
||||
ra = add;
|
||||
parm++;
|
||||
}
|
||||
if (strcmp(parm, "all") == 0) {
|
||||
from_cssid = 0;
|
||||
from_ssid = 0;
|
||||
from = 0;
|
||||
to_cssid = __MAX_CSSID;
|
||||
to_ssid = __MAX_SSID;
|
||||
to = __MAX_SUBCHANNEL;
|
||||
} else {
|
||||
rc = parse_busid(strsep(&parm, "-"), &from_cssid,
|
||||
&from_ssid, &from, msgtrigger);
|
||||
if (!rc) {
|
||||
if (parm != NULL)
|
||||
rc = parse_busid(parm, &to_cssid,
|
||||
&to_ssid, &to,
|
||||
msgtrigger);
|
||||
else {
|
||||
to_cssid = from_cssid;
|
||||
to_ssid = from_ssid;
|
||||
to = from;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!rc) {
|
||||
rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
|
||||
msgtrigger);
|
||||
if (rc)
|
||||
totalrc = 1;
|
||||
} else
|
||||
totalrc = 1;
|
||||
}
|
||||
|
||||
return totalrc;
|
||||
}
|
||||
|
||||
/* Parsing the commandline for blacklist parameters, e.g. to blacklist
|
||||
* bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of:
|
||||
* - cio_ignore=1234-1236
|
||||
* - cio_ignore=0x1234-0x1235,1236
|
||||
* - cio_ignore=0x1234,1235-1236
|
||||
* - cio_ignore=1236 cio_ignore=1234-0x1236
|
||||
* - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
|
||||
* - cio_ignore=0.0.1234-0.0.1236
|
||||
* - cio_ignore=0.0.1234,0x1235,1236
|
||||
* - ...
|
||||
*/
|
||||
static int __init
|
||||
blacklist_setup (char *str)
|
||||
{
|
||||
return blacklist_parse_parameters (str, add);
|
||||
CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
|
||||
if (blacklist_parse_parameters(str, add, 1))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
__setup ("cio_ignore=", blacklist_setup);
|
||||
@ -223,27 +230,23 @@ is_blacklisted (int ssid, int devno)
|
||||
* Function: blacklist_parse_proc_parameters
|
||||
* parse the stuff which is piped to /proc/cio_ignore
|
||||
*/
|
||||
static void
|
||||
blacklist_parse_proc_parameters (char *buf)
|
||||
static int blacklist_parse_proc_parameters(char *buf)
|
||||
{
|
||||
if (strncmp (buf, "free ", 5) == 0) {
|
||||
blacklist_parse_parameters (buf + 5, free);
|
||||
} else if (strncmp (buf, "add ", 4) == 0) {
|
||||
/*
|
||||
* We don't need to check for known devices since
|
||||
* css_probe_device will handle this correctly.
|
||||
*/
|
||||
blacklist_parse_parameters (buf + 4, add);
|
||||
} else {
|
||||
printk (KERN_WARNING "cio: cio_ignore: Parse error; \n"
|
||||
KERN_WARNING "try using 'free all|<devno-range>,"
|
||||
"<devno-range>,...'\n"
|
||||
KERN_WARNING "or 'add <devno-range>,"
|
||||
"<devno-range>,...'\n");
|
||||
return;
|
||||
}
|
||||
int rc;
|
||||
char *parm;
|
||||
|
||||
parm = strsep(&buf, " ");
|
||||
|
||||
if (strcmp("free", parm) == 0)
|
||||
rc = blacklist_parse_parameters(buf, free, 0);
|
||||
else if (strcmp("add", parm) == 0)
|
||||
rc = blacklist_parse_parameters(buf, add, 0);
|
||||
else
|
||||
return 1;
|
||||
|
||||
css_schedule_reprobe();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Iterator struct for all devices. */
|
||||
@ -327,6 +330,8 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
|
||||
size_t user_len, loff_t *offset)
|
||||
{
|
||||
char *buf;
|
||||
size_t i;
|
||||
ssize_t rc, ret;
|
||||
|
||||
if (*offset)
|
||||
return -EINVAL;
|
||||
@ -335,16 +340,27 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
|
||||
buf = vmalloc (user_len + 1); /* maybe better use the stack? */
|
||||
if (buf == NULL)
|
||||
return -ENOMEM;
|
||||
memset(buf, 0, user_len + 1);
|
||||
|
||||
if (strncpy_from_user (buf, user_buf, user_len) < 0) {
|
||||
vfree (buf);
|
||||
return -EFAULT;
|
||||
rc = -EFAULT;
|
||||
goto out_free;
|
||||
}
|
||||
buf[user_len] = '\0';
|
||||
|
||||
blacklist_parse_proc_parameters (buf);
|
||||
i = user_len - 1;
|
||||
while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
|
||||
buf[i] = '\0';
|
||||
i--;
|
||||
}
|
||||
ret = blacklist_parse_proc_parameters(buf);
|
||||
if (ret)
|
||||
rc = -EINVAL;
|
||||
else
|
||||
rc = user_len;
|
||||
|
||||
out_free:
|
||||
vfree (buf);
|
||||
return user_len;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct seq_operations cio_ignore_proc_seq_ops = {
|
||||
|
Loading…
Reference in New Issue
Block a user