mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	Avoid usb reset crashes by making tty_io cdevs truly dynamic
Avoid usb reset crashes by making tty_io cdevs truly dynamic Signed-off-by: Richard Watts <rrw@kynesim.co.uk> Reported-by: Duncan Mackintosh <DMackintosh@cbnl.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
		
							parent
							
								
									458e2c82c5
								
							
						
					
					
						commit
						a3a10ce342
					
				
					 2 changed files with 17 additions and 9 deletions
				
			
		| 
						 | 
					@ -3152,9 +3152,12 @@ static int tty_cdev_add(struct tty_driver *driver, dev_t dev,
 | 
				
			||||||
		unsigned int index, unsigned int count)
 | 
							unsigned int index, unsigned int count)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	/* init here, since reused cdevs cause crashes */
 | 
						/* init here, since reused cdevs cause crashes */
 | 
				
			||||||
	cdev_init(&driver->cdevs[index], &tty_fops);
 | 
						driver->cdevs[index] = cdev_alloc();
 | 
				
			||||||
	driver->cdevs[index].owner = driver->owner;
 | 
						if (!driver->cdevs[index])
 | 
				
			||||||
	return cdev_add(&driver->cdevs[index], dev, count);
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
						cdev_init(driver->cdevs[index], &tty_fops);
 | 
				
			||||||
 | 
						driver->cdevs[index]->owner = driver->owner;
 | 
				
			||||||
 | 
						return cdev_add(driver->cdevs[index], dev, count);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					@ -3260,8 +3263,10 @@ struct device *tty_register_device_attr(struct tty_driver *driver,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	put_device(dev);
 | 
						put_device(dev);
 | 
				
			||||||
	if (cdev)
 | 
						if (cdev) {
 | 
				
			||||||
		cdev_del(&driver->cdevs[index]);
 | 
							cdev_del(driver->cdevs[index]);
 | 
				
			||||||
 | 
							driver->cdevs[index] = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	return ERR_PTR(retval);
 | 
						return ERR_PTR(retval);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(tty_register_device_attr);
 | 
					EXPORT_SYMBOL_GPL(tty_register_device_attr);
 | 
				
			||||||
| 
						 | 
					@ -3281,8 +3286,10 @@ void tty_unregister_device(struct tty_driver *driver, unsigned index)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	device_destroy(tty_class,
 | 
						device_destroy(tty_class,
 | 
				
			||||||
		MKDEV(driver->major, driver->minor_start) + index);
 | 
							MKDEV(driver->major, driver->minor_start) + index);
 | 
				
			||||||
	if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC))
 | 
						if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) {
 | 
				
			||||||
		cdev_del(&driver->cdevs[index]);
 | 
							cdev_del(driver->cdevs[index]);
 | 
				
			||||||
 | 
							driver->cdevs[index] = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(tty_unregister_device);
 | 
					EXPORT_SYMBOL(tty_unregister_device);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3347,6 +3354,7 @@ struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner,
 | 
				
			||||||
	kfree(driver->ports);
 | 
						kfree(driver->ports);
 | 
				
			||||||
	kfree(driver->ttys);
 | 
						kfree(driver->ttys);
 | 
				
			||||||
	kfree(driver->termios);
 | 
						kfree(driver->termios);
 | 
				
			||||||
 | 
						kfree(driver->cdevs);
 | 
				
			||||||
	kfree(driver);
 | 
						kfree(driver);
 | 
				
			||||||
	return ERR_PTR(err);
 | 
						return ERR_PTR(err);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -3375,7 +3383,7 @@ static void destruct_tty_driver(struct kref *kref)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		proc_tty_unregister_driver(driver);
 | 
							proc_tty_unregister_driver(driver);
 | 
				
			||||||
		if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
 | 
							if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)
 | 
				
			||||||
			cdev_del(&driver->cdevs[0]);
 | 
								cdev_del(driver->cdevs[0]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	kfree(driver->cdevs);
 | 
						kfree(driver->cdevs);
 | 
				
			||||||
	kfree(driver->ports);
 | 
						kfree(driver->ports);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -296,7 +296,7 @@ struct tty_operations {
 | 
				
			||||||
struct tty_driver {
 | 
					struct tty_driver {
 | 
				
			||||||
	int	magic;		/* magic number for this structure */
 | 
						int	magic;		/* magic number for this structure */
 | 
				
			||||||
	struct kref kref;	/* Reference management */
 | 
						struct kref kref;	/* Reference management */
 | 
				
			||||||
	struct cdev *cdevs;
 | 
						struct cdev **cdevs;
 | 
				
			||||||
	struct module	*owner;
 | 
						struct module	*owner;
 | 
				
			||||||
	const char	*driver_name;
 | 
						const char	*driver_name;
 | 
				
			||||||
	const char	*name;
 | 
						const char	*name;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue