tty: kref the tty driver object

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Alan Cox 2008-10-13 10:42:09 +01:00 committed by Linus Torvalds
parent 99f1fe189d
commit 7d7b93c145
5 changed files with 81 additions and 59 deletions

View File

@ -264,8 +264,8 @@ static int tracewrap;
/**********/ /**********/
#if defined(MODULE) && defined(IP2DEBUG_OPEN) #if defined(MODULE) && defined(IP2DEBUG_OPEN)
#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] ttyc=%d, modc=%x -> %s\n", \
tty->name,(pCh->flags),ip2_tty_driver->refcount, \ tty->name,(pCh->flags), \
tty->count,/*GET_USE_COUNT(module)*/0,s) tty->count,/*GET_USE_COUNT(module)*/0,s)
#else #else
#define DBG_CNT(s) #define DBG_CNT(s)
@ -2893,7 +2893,7 @@ ip2_ipl_ioctl (struct file *pFile, UINT cmd, ULONG arg )
case 13: case 13:
switch ( cmd ) { switch ( cmd ) {
case 64: /* Driver - ip2stat */ case 64: /* Driver - ip2stat */
rc = put_user(ip2_tty_driver->refcount, pIndex++ ); rc = put_user(-1, pIndex++ );
rc = put_user(irq_counter, pIndex++ ); rc = put_user(irq_counter, pIndex++ );
rc = put_user(bh_counter, pIndex++ ); rc = put_user(bh_counter, pIndex++ );
break; break;

View File

@ -571,8 +571,11 @@ static void __init unix98_pty_init(void)
if (tty_register_driver(pts_driver)) if (tty_register_driver(pts_driver))
panic("Couldn't register Unix98 pts driver"); panic("Couldn't register Unix98 pts driver");
/* FIXME: WTF */
#if 0
pty_table[1].data = &ptm_driver->refcount; pty_table[1].data = &ptm_driver->refcount;
register_sysctl_table(pty_root_table); #endif
register_sysctl_table(pty_root_table);
/* Now create the /dev/ptmx special device */ /* Now create the /dev/ptmx special device */
tty_default_fops(&ptmx_fops); tty_default_fops(&ptmx_fops);

View File

@ -276,7 +276,7 @@ static struct tty_driver *get_tty_driver(dev_t device, int *index)
if (device < base || device >= base + p->num) if (device < base || device >= base + p->num)
continue; continue;
*index = device - base; *index = device - base;
return p; return tty_driver_kref_get(p);
} }
return NULL; return NULL;
} }
@ -320,7 +320,7 @@ struct tty_driver *tty_find_polling_driver(char *name, int *line)
if (tty_line >= 0 && tty_line <= p->num && p->ops && if (tty_line >= 0 && tty_line <= p->num && p->ops &&
p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) { p->ops->poll_init && !p->ops->poll_init(p, tty_line, str)) {
res = p; res = tty_driver_kref_get(p);
*line = tty_line; *line = tty_line;
break; break;
} }
@ -1410,7 +1410,7 @@ int tty_init_dev(struct tty_driver *driver, int idx,
*o_ltp_loc = o_ltp; *o_ltp_loc = o_ltp;
o_tty->termios = *o_tp_loc; o_tty->termios = *o_tp_loc;
o_tty->termios_locked = *o_ltp_loc; o_tty->termios_locked = *o_ltp_loc;
driver->other->refcount++; tty_driver_kref_get(driver->other);
if (driver->subtype == PTY_TYPE_MASTER) if (driver->subtype == PTY_TYPE_MASTER)
o_tty->count++; o_tty->count++;
@ -1438,7 +1438,7 @@ int tty_init_dev(struct tty_driver *driver, int idx,
/* Compatibility until drivers always set this */ /* Compatibility until drivers always set this */
tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios); tty->termios->c_ispeed = tty_termios_input_baud_rate(tty->termios);
tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios); tty->termios->c_ospeed = tty_termios_baud_rate(tty->termios);
driver->refcount++; tty_driver_kref_get(driver);
tty->count++; tty->count++;
/* /*
@ -1530,8 +1530,7 @@ static void release_one_tty(struct kref *kref)
else else
tty_shutdown(tty); tty_shutdown(tty);
tty->magic = 0; tty->magic = 0;
/* FIXME: locking on tty->driver->refcount */ tty_driver_kref_put(driver);
tty->driver->refcount--;
module_put(driver->owner); module_put(driver->owner);
file_list_lock(); file_list_lock();
@ -1854,7 +1853,7 @@ retry_open:
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
return -ENXIO; return -ENXIO;
} }
driver = tty->driver; driver = tty_driver_kref_get(tty->driver);
index = tty->index; index = tty->index;
filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
/* noctty = 1; */ /* noctty = 1; */
@ -1865,14 +1864,14 @@ retry_open:
#ifdef CONFIG_VT #ifdef CONFIG_VT
if (device == MKDEV(TTY_MAJOR, 0)) { if (device == MKDEV(TTY_MAJOR, 0)) {
extern struct tty_driver *console_driver; extern struct tty_driver *console_driver;
driver = console_driver; driver = tty_driver_kref_get(console_driver);
index = fg_console; index = fg_console;
noctty = 1; noctty = 1;
goto got_driver; goto got_driver;
} }
#endif #endif
if (device == MKDEV(TTYAUX_MAJOR, 1)) { if (device == MKDEV(TTYAUX_MAJOR, 1)) {
driver = console_device(&index); driver = tty_driver_kref_get(console_device(&index));
if (driver) { if (driver) {
/* Don't let /dev/console block */ /* Don't let /dev/console block */
filp->f_flags |= O_NONBLOCK; filp->f_flags |= O_NONBLOCK;
@ -1891,6 +1890,7 @@ retry_open:
got_driver: got_driver:
retval = tty_init_dev(driver, index, &tty, 0); retval = tty_init_dev(driver, index, &tty, 0);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
tty_driver_kref_put(driver);
if (retval) if (retval)
return retval; return retval;
@ -2866,7 +2866,6 @@ int tty_put_char(struct tty_struct *tty, unsigned char ch)
return tty->ops->put_char(tty, ch); return tty->ops->put_char(tty, ch);
return tty->ops->write(tty, &ch, 1); return tty->ops->write(tty, &ch, 1);
} }
EXPORT_SYMBOL_GPL(tty_put_char); EXPORT_SYMBOL_GPL(tty_put_char);
struct class *tty_class; struct class *tty_class;
@ -2909,6 +2908,7 @@ struct device *tty_register_device(struct tty_driver *driver, unsigned index,
return device_create_drvdata(tty_class, device, dev, NULL, name); return device_create_drvdata(tty_class, device, dev, NULL, name);
} }
EXPORT_SYMBOL(tty_register_device);
/** /**
* tty_unregister_device - unregister a tty device * tty_unregister_device - unregister a tty device
@ -2926,8 +2926,6 @@ 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);
} }
EXPORT_SYMBOL(tty_register_device);
EXPORT_SYMBOL(tty_unregister_device); EXPORT_SYMBOL(tty_unregister_device);
struct tty_driver *alloc_tty_driver(int lines) struct tty_driver *alloc_tty_driver(int lines)
@ -2936,28 +2934,71 @@ struct tty_driver *alloc_tty_driver(int lines)
driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL);
if (driver) { if (driver) {
kref_init(&driver->kref);
driver->magic = TTY_DRIVER_MAGIC; driver->magic = TTY_DRIVER_MAGIC;
driver->num = lines; driver->num = lines;
/* later we'll move allocation of tables here */ /* later we'll move allocation of tables here */
} }
return driver; return driver;
} }
EXPORT_SYMBOL(alloc_tty_driver);
void put_tty_driver(struct tty_driver *driver) static void destruct_tty_driver(struct kref *kref)
{ {
struct tty_driver *driver = container_of(kref, struct tty_driver, kref);
int i;
struct ktermios *tp;
void *p;
if (driver->flags & TTY_DRIVER_INSTALLED) {
/*
* Free the termios and termios_locked structures because
* we don't want to get memory leaks when modular tty
* drivers are removed from the kernel.
*/
for (i = 0; i < driver->num; i++) {
tp = driver->termios[i];
if (tp) {
driver->termios[i] = NULL;
kfree(tp);
}
tp = driver->termios_locked[i];
if (tp) {
driver->termios_locked[i] = NULL;
kfree(tp);
}
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
p = driver->ttys;
proc_tty_unregister_driver(driver);
driver->ttys = NULL;
driver->termios = driver->termios_locked = NULL;
kfree(p);
cdev_del(&driver->cdev);
}
kfree(driver); kfree(driver);
} }
void tty_driver_kref_put(struct tty_driver *driver)
{
kref_put(&driver->kref, destruct_tty_driver);
}
EXPORT_SYMBOL(tty_driver_kref_put);
void tty_set_operations(struct tty_driver *driver, void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op) const struct tty_operations *op)
{ {
driver->ops = op; driver->ops = op;
}; };
EXPORT_SYMBOL(alloc_tty_driver);
EXPORT_SYMBOL(put_tty_driver);
EXPORT_SYMBOL(tty_set_operations); EXPORT_SYMBOL(tty_set_operations);
void put_tty_driver(struct tty_driver *d)
{
tty_driver_kref_put(d);
}
EXPORT_SYMBOL(put_tty_driver);
/* /*
* Called by a tty driver to register itself. * Called by a tty driver to register itself.
*/ */
@ -2968,9 +3009,6 @@ int tty_register_driver(struct tty_driver *driver)
dev_t dev; dev_t dev;
void **p = NULL; void **p = NULL;
if (driver->flags & TTY_DRIVER_INSTALLED)
return 0;
if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) { if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM) && driver->num) {
p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL); p = kzalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
if (!p) if (!p)
@ -3024,6 +3062,7 @@ int tty_register_driver(struct tty_driver *driver)
tty_register_device(driver, i, NULL); tty_register_device(driver, i, NULL);
} }
proc_tty_register_driver(driver); proc_tty_register_driver(driver);
driver->flags |= TTY_DRIVER_INSTALLED;
return 0; return 0;
} }
@ -3034,46 +3073,19 @@ EXPORT_SYMBOL(tty_register_driver);
*/ */
int tty_unregister_driver(struct tty_driver *driver) int tty_unregister_driver(struct tty_driver *driver)
{ {
int i; #if 0
struct ktermios *tp; /* FIXME */
void *p;
if (driver->refcount) if (driver->refcount)
return -EBUSY; return -EBUSY;
#endif
unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
driver->num); driver->num);
mutex_lock(&tty_mutex); mutex_lock(&tty_mutex);
list_del(&driver->tty_drivers); list_del(&driver->tty_drivers);
mutex_unlock(&tty_mutex); mutex_unlock(&tty_mutex);
/*
* Free the termios and termios_locked structures because
* we don't want to get memory leaks when modular tty
* drivers are removed from the kernel.
*/
for (i = 0; i < driver->num; i++) {
tp = driver->termios[i];
if (tp) {
driver->termios[i] = NULL;
kfree(tp);
}
tp = driver->termios_locked[i];
if (tp) {
driver->termios_locked[i] = NULL;
kfree(tp);
}
if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV))
tty_unregister_device(driver, i);
}
p = driver->ttys;
proc_tty_unregister_driver(driver);
driver->ttys = NULL;
driver->termios = driver->termios_locked = NULL;
kfree(p);
cdev_del(&driver->cdev);
return 0; return 0;
} }
EXPORT_SYMBOL(tty_unregister_driver); EXPORT_SYMBOL(tty_unregister_driver);
dev_t tty_devnum(struct tty_struct *tty) dev_t tty_devnum(struct tty_struct *tty)

View File

@ -205,7 +205,7 @@ config WANXL_BUILD_FIRMWARE
config PC300 config PC300
tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)"
depends on HDLC && PCI depends on HDLC && PCI && BROKEN
---help--- ---help---
Driver for the Cyclades-PC300 synchronous communication boards. Driver for the Cyclades-PC300 synchronous communication boards.

View File

@ -253,6 +253,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 cdev cdev; struct cdev cdev;
struct module *owner; struct module *owner;
const char *driver_name; const char *driver_name;
@ -266,7 +267,6 @@ struct tty_driver {
short subtype; /* subtype of tty driver */ short subtype; /* subtype of tty driver */
struct ktermios init_termios; /* Initial termios */ struct ktermios init_termios; /* Initial termios */
int flags; /* tty driver flags */ int flags; /* tty driver flags */
int refcount; /* for loadable tty drivers */
struct proc_dir_entry *proc_entry; /* /proc fs entry */ struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */ struct tty_driver *other; /* only used for the PTY driver */
@ -288,12 +288,19 @@ struct tty_driver {
extern struct list_head tty_drivers; extern struct list_head tty_drivers;
struct tty_driver *alloc_tty_driver(int lines); extern struct tty_driver *alloc_tty_driver(int lines);
void put_tty_driver(struct tty_driver *driver); extern void put_tty_driver(struct tty_driver *driver);
void tty_set_operations(struct tty_driver *driver, extern void tty_set_operations(struct tty_driver *driver,
const struct tty_operations *op); const struct tty_operations *op);
extern struct tty_driver *tty_find_polling_driver(char *name, int *line); extern struct tty_driver *tty_find_polling_driver(char *name, int *line);
extern void tty_driver_kref_put(struct tty_driver *driver);
extern inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d)
{
kref_get(&d->kref);
return d;
}
/* tty driver magic number */ /* tty driver magic number */
#define TTY_DRIVER_MAGIC 0x5402 #define TTY_DRIVER_MAGIC 0x5402