mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-06-21 14:11:20 +00:00
TTY: pty, fix pty counting
tty_operations->remove is normally called like: queue_release_one_tty ->tty_shutdown ->tty_driver_remove_tty ->tty_operations->remove However tty_shutdown() is called from queue_release_one_tty() only if tty_operations->shutdown is NULL. But for pty, it is not. pty_unix98_shutdown() is used there as ->shutdown. So tty_operations->remove of pty (i.e. pty_unix98_remove()) is never called. This results in invalid pty_count. I.e. what can be seen in /proc/sys/kernel/pty/nr. I see this was already reported at: https://lkml.org/lkml/2009/11/5/370 But it was not fixed since then. This patch is kind of a hackish way. The problem lies in ->install. We allocate there another tty (so-called tty->link). So ->install is called once, but ->remove twice, for both tty and tty->link. The fix here is to count both tty and tty->link and divide the count by 2 for user. And to have ->remove called, let's make tty_driver_remove_tty() global and call that from pty_unix98_shutdown() (tty_operations->shutdown). While at it, let's document that when ->shutdown is defined, tty_shutdown() is not called. Signed-off-by: Jiri Slaby <jslaby@suse.cz> Cc: Alan Cox <alan@linux.intel.com> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: stable <stable@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
dbb3b1ca56
commit
24d406a6bf
4 changed files with 21 additions and 4 deletions
|
@ -446,8 +446,19 @@ static inline void legacy_pty_init(void) { }
|
||||||
int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
int pty_limit = NR_UNIX98_PTY_DEFAULT;
|
||||||
static int pty_limit_min;
|
static int pty_limit_min;
|
||||||
static int pty_limit_max = NR_UNIX98_PTY_MAX;
|
static int pty_limit_max = NR_UNIX98_PTY_MAX;
|
||||||
|
static int tty_count;
|
||||||
static int pty_count;
|
static int pty_count;
|
||||||
|
|
||||||
|
static inline void pty_inc_count(void)
|
||||||
|
{
|
||||||
|
pty_count = (++tty_count) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void pty_dec_count(void)
|
||||||
|
{
|
||||||
|
pty_count = (--tty_count) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
static struct cdev ptmx_cdev;
|
static struct cdev ptmx_cdev;
|
||||||
|
|
||||||
static struct ctl_table pty_table[] = {
|
static struct ctl_table pty_table[] = {
|
||||||
|
@ -542,6 +553,7 @@ static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver,
|
||||||
|
|
||||||
static void pty_unix98_shutdown(struct tty_struct *tty)
|
static void pty_unix98_shutdown(struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
|
tty_driver_remove_tty(tty->driver, tty);
|
||||||
/* We have our own method as we don't use the tty index */
|
/* We have our own method as we don't use the tty index */
|
||||||
kfree(tty->termios);
|
kfree(tty->termios);
|
||||||
}
|
}
|
||||||
|
@ -588,7 +600,8 @@ static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
*/
|
*/
|
||||||
tty_driver_kref_get(driver);
|
tty_driver_kref_get(driver);
|
||||||
tty->count++;
|
tty->count++;
|
||||||
pty_count++;
|
pty_inc_count(); /* tty */
|
||||||
|
pty_inc_count(); /* tty->link */
|
||||||
return 0;
|
return 0;
|
||||||
err_free_mem:
|
err_free_mem:
|
||||||
deinitialize_tty_struct(o_tty);
|
deinitialize_tty_struct(o_tty);
|
||||||
|
@ -602,7 +615,7 @@ err_free_tty:
|
||||||
|
|
||||||
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
pty_count--;
|
pty_dec_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct tty_operations ptm_unix98_ops = {
|
static const struct tty_operations ptm_unix98_ops = {
|
||||||
|
|
|
@ -1295,8 +1295,7 @@ static int tty_driver_install_tty(struct tty_driver *driver,
|
||||||
*
|
*
|
||||||
* Locking: tty_mutex for now
|
* Locking: tty_mutex for now
|
||||||
*/
|
*/
|
||||||
static void tty_driver_remove_tty(struct tty_driver *driver,
|
void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty)
|
||||||
struct tty_struct *tty)
|
|
||||||
{
|
{
|
||||||
if (driver->ops->remove)
|
if (driver->ops->remove)
|
||||||
driver->ops->remove(driver, tty);
|
driver->ops->remove(driver, tty);
|
||||||
|
|
|
@ -421,6 +421,8 @@ extern void tty_driver_flush_buffer(struct tty_struct *tty);
|
||||||
extern void tty_throttle(struct tty_struct *tty);
|
extern void tty_throttle(struct tty_struct *tty);
|
||||||
extern void tty_unthrottle(struct tty_struct *tty);
|
extern void tty_unthrottle(struct tty_struct *tty);
|
||||||
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
|
extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws);
|
||||||
|
extern void tty_driver_remove_tty(struct tty_driver *driver,
|
||||||
|
struct tty_struct *tty);
|
||||||
extern void tty_shutdown(struct tty_struct *tty);
|
extern void tty_shutdown(struct tty_struct *tty);
|
||||||
extern void tty_free_termios(struct tty_struct *tty);
|
extern void tty_free_termios(struct tty_struct *tty);
|
||||||
extern int is_current_pgrp_orphaned(void);
|
extern int is_current_pgrp_orphaned(void);
|
||||||
|
|
|
@ -47,6 +47,9 @@
|
||||||
*
|
*
|
||||||
* This routine is called synchronously when a particular tty device
|
* This routine is called synchronously when a particular tty device
|
||||||
* is closed for the last time freeing up the resources.
|
* is closed for the last time freeing up the resources.
|
||||||
|
* Note that tty_shutdown() is not called if ops->shutdown is defined.
|
||||||
|
* This means one is responsible to take care of calling ops->remove (e.g.
|
||||||
|
* via tty_driver_remove_tty) and releasing tty->termios.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* void (*cleanup)(struct tty_struct * tty);
|
* void (*cleanup)(struct tty_struct * tty);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue