aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_io.c
diff options
context:
space:
mode:
authorAlan Cox <alan@redhat.com>2008-10-13 05:37:26 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-13 12:51:40 -0400
commit9c9f4ded90a59eee84e15f5fd38c03d60184e112 (patch)
tree925a7f7c30136477b3f8551123fd86b355fd60fb /drivers/char/tty_io.c
parent348eb12e5598be97400c749d3d93a71856ae0b2b (diff)
tty: Add a kref count
Introduce a kref to the tty structure and use it to protect the tty->signal tty references. For now we don't introduce it for anything else. Signed-off-by: Alan Cox <alan@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char/tty_io.c')
-rw-r--r--drivers/char/tty_io.c54
1 files changed, 48 insertions, 6 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 732316899ca4..310e0703e4a1 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -559,6 +559,7 @@ static void do_tty_hangup(struct work_struct *work)
559 struct tty_ldisc *ld; 559 struct tty_ldisc *ld;
560 int closecount = 0, n; 560 int closecount = 0, n;
561 unsigned long flags; 561 unsigned long flags;
562 int refs = 0;
562 563
563 if (!tty) 564 if (!tty)
564 return; 565 return;
@@ -625,8 +626,12 @@ static void do_tty_hangup(struct work_struct *work)
625 if (tty->session) { 626 if (tty->session) {
626 do_each_pid_task(tty->session, PIDTYPE_SID, p) { 627 do_each_pid_task(tty->session, PIDTYPE_SID, p) {
627 spin_lock_irq(&p->sighand->siglock); 628 spin_lock_irq(&p->sighand->siglock);
628 if (p->signal->tty == tty) 629 if (p->signal->tty == tty) {
629 p->signal->tty = NULL; 630 p->signal->tty = NULL;
631 /* We defer the dereferences outside fo
632 the tasklist lock */
633 refs++;
634 }
630 if (!p->signal->leader) { 635 if (!p->signal->leader) {
631 spin_unlock_irq(&p->sighand->siglock); 636 spin_unlock_irq(&p->sighand->siglock);
632 continue; 637 continue;
@@ -652,6 +657,10 @@ static void do_tty_hangup(struct work_struct *work)
652 tty->ctrl_status = 0; 657 tty->ctrl_status = 0;
653 spin_unlock_irqrestore(&tty->ctrl_lock, flags); 658 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
654 659
660 /* Account for the p->signal references we killed */
661 while (refs--)
662 tty_kref_put(tty);
663
655 /* 664 /*
656 * If one of the devices matches a console pointer, we 665 * If one of the devices matches a console pointer, we
657 * cannot just call hangup() because that will cause 666 * cannot just call hangup() because that will cause
@@ -1424,6 +1433,7 @@ release_mem_out:
1424 1433
1425/** 1434/**
1426 * release_one_tty - release tty structure memory 1435 * release_one_tty - release tty structure memory
1436 * @kref: kref of tty we are obliterating
1427 * 1437 *
1428 * Releases memory associated with a tty structure, and clears out the 1438 * Releases memory associated with a tty structure, and clears out the
1429 * driver table slots. This function is called when a device is no longer 1439 * driver table slots. This function is called when a device is no longer
@@ -1433,17 +1443,19 @@ release_mem_out:
1433 * tty_mutex - sometimes only 1443 * tty_mutex - sometimes only
1434 * takes the file list lock internally when working on the list 1444 * takes the file list lock internally when working on the list
1435 * of ttys that the driver keeps. 1445 * of ttys that the driver keeps.
1436 * FIXME: should we require tty_mutex is held here ??
1437 */ 1446 */
1438static void release_one_tty(struct tty_struct *tty, int idx) 1447static void release_one_tty(struct kref *kref)
1439{ 1448{
1449 struct tty_struct *tty = container_of(kref, struct tty_struct, kref);
1440 int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM; 1450 int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
1441 struct ktermios *tp; 1451 struct ktermios *tp;
1452 int idx = tty->index;
1442 1453
1443 if (!devpts) 1454 if (!devpts)
1444 tty->driver->ttys[idx] = NULL; 1455 tty->driver->ttys[idx] = NULL;
1445 1456
1446 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) { 1457 if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
1458 /* FIXME: Locking on ->termios array */
1447 tp = tty->termios; 1459 tp = tty->termios;
1448 if (!devpts) 1460 if (!devpts)
1449 tty->driver->termios[idx] = NULL; 1461 tty->driver->termios[idx] = NULL;
@@ -1457,6 +1469,7 @@ static void release_one_tty(struct tty_struct *tty, int idx)
1457 1469
1458 1470
1459 tty->magic = 0; 1471 tty->magic = 0;
1472 /* FIXME: locking on tty->driver->refcount */
1460 tty->driver->refcount--; 1473 tty->driver->refcount--;
1461 1474
1462 file_list_lock(); 1475 file_list_lock();
@@ -1467,6 +1480,21 @@ static void release_one_tty(struct tty_struct *tty, int idx)
1467} 1480}
1468 1481
1469/** 1482/**
1483 * tty_kref_put - release a tty kref
1484 * @tty: tty device
1485 *
1486 * Release a reference to a tty device and if need be let the kref
1487 * layer destruct the object for us
1488 */
1489
1490void tty_kref_put(struct tty_struct *tty)
1491{
1492 if (tty)
1493 kref_put(&tty->kref, release_one_tty);
1494}
1495EXPORT_SYMBOL(tty_kref_put);
1496
1497/**
1470 * release_tty - release tty structure memory 1498 * release_tty - release tty structure memory
1471 * 1499 *
1472 * Release both @tty and a possible linked partner (think pty pair), 1500 * Release both @tty and a possible linked partner (think pty pair),
@@ -1477,14 +1505,20 @@ static void release_one_tty(struct tty_struct *tty, int idx)
1477 * takes the file list lock internally when working on the list 1505 * takes the file list lock internally when working on the list
1478 * of ttys that the driver keeps. 1506 * of ttys that the driver keeps.
1479 * FIXME: should we require tty_mutex is held here ?? 1507 * FIXME: should we require tty_mutex is held here ??
1508 *
1509 * FIXME: We want to defer the module put of the driver to the
1510 * destructor.
1480 */ 1511 */
1481static void release_tty(struct tty_struct *tty, int idx) 1512static void release_tty(struct tty_struct *tty, int idx)
1482{ 1513{
1483 struct tty_driver *driver = tty->driver; 1514 struct tty_driver *driver = tty->driver;
1484 1515
1516 /* This should always be true but check for the moment */
1517 WARN_ON(tty->index != idx);
1518
1485 if (tty->link) 1519 if (tty->link)
1486 release_one_tty(tty->link, idx); 1520 tty_kref_put(tty->link);
1487 release_one_tty(tty, idx); 1521 tty_kref_put(tty);
1488 module_put(driver->owner); 1522 module_put(driver->owner);
1489} 1523}
1490 1524
@@ -2798,6 +2832,7 @@ EXPORT_SYMBOL(do_SAK);
2798static void initialize_tty_struct(struct tty_struct *tty) 2832static void initialize_tty_struct(struct tty_struct *tty)
2799{ 2833{
2800 memset(tty, 0, sizeof(struct tty_struct)); 2834 memset(tty, 0, sizeof(struct tty_struct));
2835 kref_init(&tty->kref);
2801 tty->magic = TTY_MAGIC; 2836 tty->magic = TTY_MAGIC;
2802 tty_ldisc_init(tty); 2837 tty_ldisc_init(tty);
2803 tty->session = NULL; 2838 tty->session = NULL;
@@ -3053,9 +3088,12 @@ EXPORT_SYMBOL(tty_devnum);
3053 3088
3054void proc_clear_tty(struct task_struct *p) 3089void proc_clear_tty(struct task_struct *p)
3055{ 3090{
3091 struct tty_struct *tty;
3056 spin_lock_irq(&p->sighand->siglock); 3092 spin_lock_irq(&p->sighand->siglock);
3093 tty = p->signal->tty;
3057 p->signal->tty = NULL; 3094 p->signal->tty = NULL;
3058 spin_unlock_irq(&p->sighand->siglock); 3095 spin_unlock_irq(&p->sighand->siglock);
3096 tty_kref_put(tty);
3059} 3097}
3060 3098
3061/* Called under the sighand lock */ 3099/* Called under the sighand lock */
@@ -3071,9 +3109,13 @@ static void __proc_set_tty(struct task_struct *tsk, struct tty_struct *tty)
3071 tty->pgrp = get_pid(task_pgrp(tsk)); 3109 tty->pgrp = get_pid(task_pgrp(tsk));
3072 spin_unlock_irqrestore(&tty->ctrl_lock, flags); 3110 spin_unlock_irqrestore(&tty->ctrl_lock, flags);
3073 tty->session = get_pid(task_session(tsk)); 3111 tty->session = get_pid(task_session(tsk));
3112 if (tsk->signal->tty) {
3113 printk(KERN_DEBUG "tty not NULL!!\n");
3114 tty_kref_put(tsk->signal->tty);
3115 }
3074 } 3116 }
3075 put_pid(tsk->signal->tty_old_pgrp); 3117 put_pid(tsk->signal->tty_old_pgrp);
3076 tsk->signal->tty = tty; 3118 tsk->signal->tty = tty_kref_get(tty);
3077 tsk->signal->tty_old_pgrp = NULL; 3119 tsk->signal->tty_old_pgrp = NULL;
3078} 3120}
3079 3121