Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <cornelia.huck@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
b7a610f7 f2962dae

+45 -42
+2 -2
arch/s390/include/asm/ccwgroup.h
··· 66 66 extern int ccwgroup_driver_register (struct ccwgroup_driver *cdriver); 67 67 extern void ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver); 68 68 int ccwgroup_create_dev(struct device *root, unsigned int creator_id, 69 - struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv, 70 - int num_devices, const char *buf); 69 + struct ccwgroup_driver *gdrv, int num_devices, 70 + const char *buf); 71 71 int ccwgroup_create_from_string(struct device *root, unsigned int creator_id, 72 72 struct ccw_driver *cdrv, int num_devices, 73 73 const char *buf);
+30 -39
drivers/s390/cio/ccwgroup.c
··· 15 15 #include <linux/ctype.h> 16 16 #include <linux/dcache.h> 17 17 18 + #include <asm/cio.h> 18 19 #include <asm/ccwdev.h> 19 20 #include <asm/ccwgroup.h> 20 21 21 - #define CCW_BUS_ID_SIZE 20 22 + #include "device.h" 23 + 24 + #define CCW_BUS_ID_SIZE 10 22 25 23 26 /* In Linux 2.4, we had a channel device layer called "chandev" 24 27 * that did all sorts of obscure stuff for networking devices. ··· 257 254 return 0; 258 255 } 259 256 260 - static int __get_next_bus_id(const char **buf, char *bus_id) 257 + static int __get_next_id(const char **buf, struct ccw_dev_id *id) 261 258 { 262 - int rc, len; 259 + unsigned int cssid, ssid, devno; 260 + int ret = 0, len; 263 261 char *start, *end; 264 262 265 263 start = (char *)*buf; ··· 275 271 len = end - start + 1; 276 272 end++; 277 273 } 278 - if (len < CCW_BUS_ID_SIZE) { 279 - strlcpy(bus_id, start, len); 280 - rc = 0; 274 + if (len <= CCW_BUS_ID_SIZE) { 275 + if (sscanf(start, "%2x.%1x.%04x", &cssid, &ssid, &devno) != 3) 276 + ret = -EINVAL; 281 277 } else 282 - rc = -EINVAL; 278 + ret = -EINVAL; 279 + 280 + if (!ret) { 281 + id->ssid = ssid; 282 + id->devno = devno; 283 + } 283 284 *buf = end; 284 - return rc; 285 - } 286 - 287 - static int __is_valid_bus_id(char bus_id[CCW_BUS_ID_SIZE]) 288 - { 289 - int cssid, ssid, devno; 290 - 291 - /* Must be of form %x.%x.%04x */ 292 - if (sscanf(bus_id, "%x.%1x.%04x", &cssid, &ssid, &devno) != 3) 293 - return 0; 294 - return 1; 285 + return ret; 295 286 } 296 287 297 288 /** 298 289 * ccwgroup_create_dev() - create and register a ccw group device 299 290 * @parent: parent device for the new device 300 291 * @creator_id: identifier of creating driver 301 - * @cdrv: ccw driver of slave devices 302 292 * @gdrv: driver for the new group device 303 293 * @num_devices: number of slave devices 304 294 * @buf: buffer containing comma separated bus ids of slave devices 305 295 * 306 296 * Create and register a new ccw group device as a child of @parent. Slave 307 - * devices are obtained from the list of bus ids given in @buf and must all 308 - * belong to @cdrv. 297 + * devices are obtained from the list of bus ids given in @buf. 309 298 * Returns: 310 299 * %0 on success and an error code on failure. 311 300 * Context: 312 301 * non-atomic 313 302 */ 314 303 int ccwgroup_create_dev(struct device *parent, unsigned int creator_id, 315 - struct ccw_driver *cdrv, struct ccwgroup_driver *gdrv, 316 - int num_devices, const char *buf) 304 + struct ccwgroup_driver *gdrv, int num_devices, 305 + const char *buf) 317 306 { 318 307 struct ccwgroup_device *gdev; 308 + struct ccw_dev_id dev_id; 319 309 int rc, i; 320 - char tmp_bus_id[CCW_BUS_ID_SIZE]; 321 - const char *curr_buf; 322 310 323 311 gdev = kzalloc(sizeof(*gdev) + num_devices * sizeof(gdev->cdev[0]), 324 312 GFP_KERNEL); ··· 330 334 gdev->dev.release = ccwgroup_release; 331 335 device_initialize(&gdev->dev); 332 336 333 - curr_buf = buf; 334 - for (i = 0; i < num_devices && curr_buf; i++) { 335 - rc = __get_next_bus_id(&curr_buf, tmp_bus_id); 337 + for (i = 0; i < num_devices && buf; i++) { 338 + rc = __get_next_id(&buf, &dev_id); 336 339 if (rc != 0) 337 340 goto error; 338 - if (!__is_valid_bus_id(tmp_bus_id)) { 339 - rc = -EINVAL; 340 - goto error; 341 - } 342 - gdev->cdev[i] = get_ccwdev_by_busid(cdrv, tmp_bus_id); 341 + gdev->cdev[i] = get_ccwdev_by_dev_id(&dev_id); 343 342 /* 344 343 * All devices have to be of the same type in 345 344 * order to be grouped. 346 345 */ 347 - if (!gdev->cdev[i] 348 - || gdev->cdev[i]->id.driver_info != 346 + if (!gdev->cdev[i] || !gdev->cdev[i]->drv || 347 + gdev->cdev[i]->drv != gdev->cdev[0]->drv || 348 + gdev->cdev[i]->id.driver_info != 349 349 gdev->cdev[0]->id.driver_info) { 350 350 rc = -EINVAL; 351 351 goto error; ··· 357 365 spin_unlock_irq(gdev->cdev[i]->ccwlock); 358 366 } 359 367 /* Check for sufficient number of bus ids. */ 360 - if (i < num_devices && !curr_buf) { 368 + if (i < num_devices) { 361 369 rc = -EINVAL; 362 370 goto error; 363 371 } 364 372 /* Check for trailing stuff. */ 365 - if (i == num_devices && strlen(curr_buf) > 0) { 373 + if (i == num_devices && strlen(buf) > 0) { 366 374 rc = -EINVAL; 367 375 goto error; 368 376 } ··· 422 430 struct ccw_driver *cdrv, int num_devices, 423 431 const char *buf) 424 432 { 425 - return ccwgroup_create_dev(root, creator_id, cdrv, NULL, 426 - num_devices, buf); 433 + return ccwgroup_create_dev(root, creator_id, NULL, num_devices, buf); 427 434 } 428 435 EXPORT_SYMBOL(ccwgroup_create_from_string); 429 436
+12 -1
drivers/s390/cio/device.c
··· 695 695 return ccw_dev_id_is_equal(&cdev->private->dev_id, dev_id); 696 696 } 697 697 698 - static struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) 698 + /** 699 + * get_ccwdev_by_dev_id() - obtain device from a ccw device id 700 + * @dev_id: id of the device to be searched 701 + * 702 + * This function searches all devices attached to the ccw bus for a device 703 + * matching @dev_id. 704 + * Returns: 705 + * If a device is found its reference count is increased and returned; 706 + * else %NULL is returned. 707 + */ 708 + struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id) 699 709 { 700 710 struct device *dev; 701 711 ··· 713 703 714 704 return dev ? to_ccwdev(dev) : NULL; 715 705 } 706 + EXPORT_SYMBOL_GPL(get_ccwdev_by_dev_id); 716 707 717 708 static void ccw_device_do_unbind_bind(struct ccw_device *cdev) 718 709 {
+1
drivers/s390/cio/device.h
··· 101 101 void ccw_device_schedule_sch_unregister(struct ccw_device *); 102 102 int ccw_purge_blacklisted(void); 103 103 void ccw_device_sched_todo(struct ccw_device *cdev, enum cdev_todo todo); 104 + struct ccw_device *get_ccwdev_by_dev_id(struct ccw_dev_id *dev_id); 104 105 105 106 /* Function prototypes for device status and basic sense stuff. */ 106 107 void ccw_device_accumulate_irb(struct ccw_device *, struct irb *);