From: Sebastian Ott Date: Tue, 15 May 2012 15:52:07 +0000 (+0200) Subject: s390/ccwgroup: exploit ccwdev_by_dev_id X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=b7a610f7b4cb95150ee58ea7454ca2ace10634c5;p=linux-beck.git s390/ccwgroup: exploit ccwdev_by_dev_id Instead of finding devices via driver_find_device use the bus_find_device wrapper get_ccwdev_by_dev_id. This allows us to get rid of the ccw_driver argument of ccwgroup_create_dev and thus simplify the interface. Reviewed-by: Cornelia Huck Signed-off-by: Sebastian Ott Signed-off-by: Martin Schwidefsky --- diff --git a/arch/s390/include/asm/ccwgroup.h b/arch/s390/include/asm/ccwgroup.h index f5cfb7925867..70c3d4d2efe8 100644 --- a/arch/s390/include/asm/ccwgroup.h +++ b/arch/s390/include/asm/ccwgroup.h @@ -66,8 +66,8 @@ struct ccwgroup_driver { extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); int ccwgroup_create_dev(struct device *root, unsigned int creator_id, - struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv, - int num_devices, const char *buf); + struct ccwgroup_driver *gdrv, int num_devices, + const char *buf); int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, struct ccw_driver *cdrv, int num_devices, const char *buf); diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 0c7ed30ac87e..c69cee607aed 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c @@ -15,10 +15,13 @@ #include #include +#include #include #include -#define CCW_BUS_ID_SIZE 20 +#include "device.h" + +#define CCW_BUS_ID_SIZE 10 /* In Linux 2.4, we had a channel device layer called "chandev" * that did all sorts of obscure stuff for networking devices. @@ -254,9 +257,10 @@ static int __ccwgroup_create_symlinks(struct ccwgroup_device *gdev) return 0; } -static int __get_next_bus_id(const char **buf, char *bus_id) +static int __get_next_id(const char **buf, struct ccw_dev_id *id) { - int rc, len; + unsigned int cssid, ssid, devno; + int ret = 0, len; char *start, *end; start = (char *)*buf; @@ -271,50 +275,42 @@ static int __get_next_bus_id(const char **buf, char *bus_id) len = end - start + 1; end++; } - if (len < CCW_BUS_ID_SIZE) { - strlcpy(bus_id, start, len); - rc = 0; + if (len <= CCW_BUS_ID_SIZE) { + if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3) + ret = -EINVAL; } else - rc = -EINVAL; - *buf = end; - return rc; -} - -static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) -{ - int cssid, ssid, devno; + ret = -EINVAL; - /* Must be of form %x.%x.%04x */ - if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) - return 0; - return 1; + if (!ret) { + id->ssid = ssid; + id->devno = devno; + } + *buf = end; + return ret; } /** * ccwgroup_create_dev() - create and register a ccw group device * @parent: parent device for the new device * @creator_id: identifier of creating driver - * @cdrv: ccw driver of slave devices * @gdrv: driver for the new group device * @num_devices: number of slave devices * @buf: buffer containing comma separated bus ids of slave devices * * Create and register a new ccw group device as a child of @parent. Slave - * devices are obtained from the list of bus ids given in @buf and must all - * belong to @cdrv. + * devices are obtained from the list of bus ids given in @buf. * Returns: * %0 on success and an error code on failure. * Context: * non-atomic */ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id, - struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv, - int num_devices, const char *buf) + struct ccwgroup_driver *gdrv, int num_devices, + const char *buf) { struct ccwgroup_device *gdev; + struct ccw_dev_id dev_id; int rc, i; - char tmp_bus_id[CCW_BUS_ID_SIZE]; - const char *curr_buf; gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), GFP_KERNEL); @@ -334,22 +330,18 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id, gdev->dev.release = ccwgroup_release; device_initialize(&gdev->dev); - curr_buf = buf; - for (i = 0; i < num_devices && curr_buf; i++) { - rc = __get_next_bus_id(&curr_buf, tmp_bus_id); + for (i = 0; i < num_devices && buf; i++) { + rc = __get_next_id(&buf, &dev_id); if (rc != 0) goto error; - if (!__is_valid_bus_id(tmp_bus_id)) { - rc = -EINVAL; - goto error; - } - gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); + gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id); /* * All devices have to be of the same type in * order to be grouped. */ - if (!gdev->cdev[i] - || gdev->cdev[i]->id.driver_info != + if (!gdev->cdev[i] || !gdev->cdev[i]->drv || + gdev->cdev[i]->drv != gdev->cdev[0]->drv || + gdev->cdev[i]->id.driver_info != gdev->cdev[0]->id.driver_info) { rc = -EINVAL; goto error; @@ -365,12 +357,12 @@ int ccwgroup_create_dev(struct device *parent, unsigned int creator_id, spin_unlock_irq(gdev->cdev[i]->ccwlock); } /* Check for sufficient number of bus ids. */ - if (i < num_devices && !curr_buf) { + if (i < num_devices) { rc = -EINVAL; goto error; } /* Check for trailing stuff. */ - if (i == num_devices && strlen(curr_buf) > 0) { + if (i == num_devices && strlen(buf) > 0) { rc = -EINVAL; goto error; } @@ -430,8 +422,7 @@ int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, struct ccw_driver *cdrv, int num_devices, const char *buf) { - return ccwgroup_create_dev(root, creator_id, cdrv, NULL, - num_devices, buf); + return ccwgroup_create_dev(root, creator_id, NULL, num_devices, buf); } EXPORT_SYMBOL(ccwgroup_create_from_string); diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c index 02d015259461..f8f952d52045 100644 --- a/drivers/s390/cio/device.c +++ b/drivers/s390/cio/device.c @@ -695,7 +695,17 @@ static int match_dev_id(struct device *dev, void *data) return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); } -static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) +/** + * get_ccwdev_by_dev_id() - obtain device from a ccw device id + * @dev_id: id of the device to be searched + * + * This function searches all devices attached to the ccw bus for a device + * matching @dev_id. + * Returns: + * If a device is found its reference count is increased and returned; + * else %NULL is returned. + */ +struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) { struct device *dev; @@ -703,6 +713,7 @@ static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) return dev ? to_ccwdev(dev) : NULL; } +EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id); static void ccw_device_do_unbind_bind(struct ccw_device *cdev) { diff --git a/drivers/s390/cio/device.h b/drivers/s390/cio/device.h index 179824b3082f..6bace6942396 100644 --- a/drivers/s390/cio/device.h +++ b/drivers/s390/cio/device.h @@ -101,6 +101,7 @@ int ccw_device_test_sense_data(struct ccw_device *); void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo); +struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id); /* Function prototypes for device status and basic sense stuff. */ void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);