diff options
author | Alan Cox <alan@redhat.com> | 2008-10-13 05:37:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-13 12:51:40 -0400 |
commit | 9c9f4ded90a59eee84e15f5fd38c03d60184e112 (patch) | |
tree | 925a7f7c30136477b3f8551123fd86b355fd60fb /drivers/char/tty_io.c | |
parent | 348eb12e5598be97400c749d3d93a71856ae0b2b (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.c | 54 |
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 | */ |
1438 | static void release_one_tty(struct tty_struct *tty, int idx) | 1447 | static 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 | |||
1490 | void tty_kref_put(struct tty_struct *tty) | ||
1491 | { | ||
1492 | if (tty) | ||
1493 | kref_put(&tty->kref, release_one_tty); | ||
1494 | } | ||
1495 | EXPORT_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 | */ |
1481 | static void release_tty(struct tty_struct *tty, int idx) | 1512 | static 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); | |||
2798 | static void initialize_tty_struct(struct tty_struct *tty) | 2832 | static 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 | ||
3054 | void proc_clear_tty(struct task_struct *p) | 3089 | void 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 | ||