aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/char/tty_io.c54
-rw-r--r--include/linux/tty.h18
-rw-r--r--kernel/fork.c5
-rw-r--r--kernel/sys.c4
4 files changed, 71 insertions, 10 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
diff --git a/include/linux/tty.h b/include/linux/tty.h
index e3612c3ac194..b6e6c26883ee 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -209,6 +209,7 @@ struct tty_operations;
209 209
210struct tty_struct { 210struct tty_struct {
211 int magic; 211 int magic;
212 struct kref kref;
212 struct tty_driver *driver; 213 struct tty_driver *driver;
213 const struct tty_operations *ops; 214 const struct tty_operations *ops;
214 int index; 215 int index;
@@ -311,6 +312,23 @@ extern int kmsg_redirect;
311extern void console_init(void); 312extern void console_init(void);
312extern int vcs_init(void); 313extern int vcs_init(void);
313 314
315/**
316 * tty_kref_get - get a tty reference
317 * @tty: tty device
318 *
319 * Return a new reference to a tty object. The caller must hold
320 * sufficient locks/counts to ensure that their existing reference cannot
321 * go away
322 */
323
324extern inline struct tty_struct *tty_kref_get(struct tty_struct *tty)
325{
326 if (tty)
327 kref_get(&tty->kref);
328 return tty;
329}
330extern void tty_kref_put(struct tty_struct *tty);
331
314extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, 332extern int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
315 const char *routine); 333 const char *routine);
316extern char *tty_name(struct tty_struct *tty, char *buf); 334extern char *tty_name(struct tty_struct *tty, char *buf);
diff --git a/kernel/fork.c b/kernel/fork.c
index 7ce2ebe84796..30de644a40c4 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -802,6 +802,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
802 802
803 sig->leader = 0; /* session leadership doesn't inherit */ 803 sig->leader = 0; /* session leadership doesn't inherit */
804 sig->tty_old_pgrp = NULL; 804 sig->tty_old_pgrp = NULL;
805 sig->tty = NULL;
805 806
806 sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero; 807 sig->utime = sig->stime = sig->cutime = sig->cstime = cputime_zero;
807 sig->gtime = cputime_zero; 808 sig->gtime = cputime_zero;
@@ -838,6 +839,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
838void __cleanup_signal(struct signal_struct *sig) 839void __cleanup_signal(struct signal_struct *sig)
839{ 840{
840 exit_thread_group_keys(sig); 841 exit_thread_group_keys(sig);
842 tty_kref_put(sig->tty);
841 kmem_cache_free(signal_cachep, sig); 843 kmem_cache_free(signal_cachep, sig);
842} 844}
843 845
@@ -1227,7 +1229,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
1227 p->nsproxy->pid_ns->child_reaper = p; 1229 p->nsproxy->pid_ns->child_reaper = p;
1228 1230
1229 p->signal->leader_pid = pid; 1231 p->signal->leader_pid = pid;
1230 p->signal->tty = current->signal->tty; 1232 tty_kref_put(p->signal->tty);
1233 p->signal->tty = tty_kref_get(current->signal->tty);
1231 set_task_pgrp(p, task_pgrp_nr(current)); 1234 set_task_pgrp(p, task_pgrp_nr(current));
1232 set_task_session(p, task_session_nr(current)); 1235 set_task_session(p, task_session_nr(current));
1233 attach_pid(p, PIDTYPE_PGID, task_pgrp(current)); 1236 attach_pid(p, PIDTYPE_PGID, task_pgrp(current));
diff --git a/kernel/sys.c b/kernel/sys.c
index 038a7bc0901d..234d9454294e 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1060,9 +1060,7 @@ asmlinkage long sys_setsid(void)
1060 group_leader->signal->leader = 1; 1060 group_leader->signal->leader = 1;
1061 __set_special_pids(sid); 1061 __set_special_pids(sid);
1062 1062
1063 spin_lock(&group_leader->sighand->siglock); 1063 proc_clear_tty(group_leader);
1064 group_leader->signal->tty = NULL;
1065 spin_unlock(&group_leader->sighand->siglock);
1066 1064
1067 err = session; 1065 err = session;
1068out: 1066out: