From fa2ecfc5a68d85624bbd84f7d010860776b7e602 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Oct 2012 22:26:31 +0200 Subject: TTY: move devpts kill to pty Now that we have control over tty->driver_data in pty, we can just kill the /dev/pts/ in pty code too. Namely, in ->shutdown hook of tty. For pty, this is called only once, for whichever end is closed last. But we don't care, both driver_data are the inode as it used to be till now. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_io.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers/tty/tty_io.c') diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 2ea176b2280..e835a5b8d08 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1625,7 +1625,6 @@ int tty_release(struct inode *inode, struct file *filp) struct tty_struct *tty = file_tty(filp); struct tty_struct *o_tty; int pty_master, tty_closing, o_tty_closing, do_sleep; - int devpts; int idx; char buf[64]; @@ -1640,7 +1639,6 @@ int tty_release(struct inode *inode, struct file *filp) idx = tty->index; pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY && tty->driver->subtype == PTY_TYPE_MASTER); - devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0; /* Review: parallel close */ o_tty = tty->link; @@ -1799,9 +1797,6 @@ int tty_release(struct inode *inode, struct file *filp) release_tty(tty, idx); mutex_unlock(&tty_mutex); - /* Make this pty number available for reallocation */ - if (devpts) - devpts_kill_index(inode, idx); return 0; } -- cgit v1.2.3-70-g09d2 From 53c5ee2cfb4dadc4f5c24fe671e2fbfc034c875e Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Oct 2012 22:26:39 +0200 Subject: TTY: move ldisc data from tty_struct: simple members Here we start moving all the n_tty related bits from tty_struct to the newly defined n_tty_data struct in n_tty proper. In this patch primitive members and bits are moved. The rest will be done per-partes in the next patches. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 160 ++++++++++++++++++++++++++++++--------------------- drivers/tty/tty_io.c | 1 - include/linux/tty.h | 5 -- 3 files changed, 93 insertions(+), 73 deletions(-) (limited to 'drivers/tty/tty_io.c') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 3d1594e10d0..bd775a7c062 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -74,13 +74,20 @@ #define ECHO_OP_ERASE_TAB 0x82 struct n_tty_data { - char dummy; + unsigned int column; + unsigned long overrun_time; + int num_overrun; + + unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; + unsigned char echo_overrun:1; }; static inline int tty_put_user(struct tty_struct *tty, unsigned char x, unsigned char __user *ptr) { - tty_audit_add_data(tty, &x, 1, tty->icanon); + struct n_tty_data *ldata = tty->disc_data; + + tty_audit_add_data(tty, &x, 1, ldata->icanon); return put_user(x, ptr); } @@ -96,6 +103,7 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x, static void n_tty_set_room(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int left; int old_left; @@ -115,7 +123,7 @@ static void n_tty_set_room(struct tty_struct *tty) * characters will be beeped. */ if (left <= 0) - left = tty->icanon && !tty->canon_data; + left = ldata->icanon && !tty->canon_data; old_left = tty->receive_room; tty->receive_room = left; @@ -183,6 +191,7 @@ static void check_unthrottle(struct tty_struct *tty) static void reset_buffer_flags(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; spin_lock_irqsave(&tty->read_lock, flags); @@ -190,10 +199,10 @@ static void reset_buffer_flags(struct tty_struct *tty) spin_unlock_irqrestore(&tty->read_lock, flags); mutex_lock(&tty->echo_lock); - tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0; + tty->echo_pos = tty->echo_cnt = ldata->echo_overrun = 0; mutex_unlock(&tty->echo_lock); - tty->canon_head = tty->canon_data = tty->erasing = 0; + tty->canon_head = tty->canon_data = ldata->erasing = 0; memset(&tty->read_flags, 0, sizeof tty->read_flags); n_tty_set_room(tty); } @@ -239,11 +248,12 @@ static void n_tty_flush_buffer(struct tty_struct *tty) static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; ssize_t n = 0; spin_lock_irqsave(&tty->read_lock, flags); - if (!tty->icanon) { + if (!ldata->icanon) { n = tty->read_cnt; } else if (tty->canon_data) { n = (tty->canon_head > tty->read_tail) ? @@ -305,6 +315,7 @@ static inline int is_continuation(unsigned char c, struct tty_struct *tty) static int do_output_char(unsigned char c, struct tty_struct *tty, int space) { + struct n_tty_data *ldata = tty->disc_data; int spaces; if (!space) @@ -313,48 +324,48 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) switch (c) { case '\n': if (O_ONLRET(tty)) - tty->column = 0; + ldata->column = 0; if (O_ONLCR(tty)) { if (space < 2) return -1; - tty->canon_column = tty->column = 0; + tty->canon_column = ldata->column = 0; tty->ops->write(tty, "\r\n", 2); return 2; } - tty->canon_column = tty->column; + tty->canon_column = ldata->column; break; case '\r': - if (O_ONOCR(tty) && tty->column == 0) + if (O_ONOCR(tty) && ldata->column == 0) return 0; if (O_OCRNL(tty)) { c = '\n'; if (O_ONLRET(tty)) - tty->canon_column = tty->column = 0; + tty->canon_column = ldata->column = 0; break; } - tty->canon_column = tty->column = 0; + tty->canon_column = ldata->column = 0; break; case '\t': - spaces = 8 - (tty->column & 7); + spaces = 8 - (ldata->column & 7); if (O_TABDLY(tty) == XTABS) { if (space < spaces) return -1; - tty->column += spaces; + ldata->column += spaces; tty->ops->write(tty, " ", spaces); return spaces; } - tty->column += spaces; + ldata->column += spaces; break; case '\b': - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; break; default: if (!iscntrl(c)) { if (O_OLCUC(tty)) c = toupper(c); if (!is_continuation(c, tty)) - tty->column++; + ldata->column++; } break; } @@ -415,6 +426,7 @@ static int process_output(unsigned char c, struct tty_struct *tty) static ssize_t process_output_block(struct tty_struct *tty, const unsigned char *buf, unsigned int nr) { + struct n_tty_data *ldata = tty->disc_data; int space; int i; const unsigned char *cp; @@ -435,30 +447,30 @@ static ssize_t process_output_block(struct tty_struct *tty, switch (c) { case '\n': if (O_ONLRET(tty)) - tty->column = 0; + ldata->column = 0; if (O_ONLCR(tty)) goto break_out; - tty->canon_column = tty->column; + tty->canon_column = ldata->column; break; case '\r': - if (O_ONOCR(tty) && tty->column == 0) + if (O_ONOCR(tty) && ldata->column == 0) goto break_out; if (O_OCRNL(tty)) goto break_out; - tty->canon_column = tty->column = 0; + tty->canon_column = ldata->column = 0; break; case '\t': goto break_out; case '\b': - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; break; default: if (!iscntrl(c)) { if (O_OLCUC(tty)) goto break_out; if (!is_continuation(c, tty)) - tty->column++; + ldata->column++; } break; } @@ -498,6 +510,7 @@ break_out: static void process_echoes(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int space, nr; unsigned char c; unsigned char *cp, *buf_end; @@ -559,22 +572,22 @@ static void process_echoes(struct tty_struct *tty) space -= num_bs; while (num_bs--) { tty_put_char(tty, '\b'); - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; } cp += 3; nr -= 3; break; case ECHO_OP_SET_CANON_COL: - tty->canon_column = tty->column; + tty->canon_column = ldata->column; cp += 2; nr -= 2; break; case ECHO_OP_MOVE_BACK_COL: - if (tty->column > 0) - tty->column--; + if (ldata->column > 0) + ldata->column--; cp += 2; nr -= 2; break; @@ -586,7 +599,7 @@ static void process_echoes(struct tty_struct *tty) break; } tty_put_char(tty, ECHO_OP_START); - tty->column++; + ldata->column++; space--; cp += 2; nr -= 2; @@ -608,7 +621,7 @@ static void process_echoes(struct tty_struct *tty) } tty_put_char(tty, '^'); tty_put_char(tty, op ^ 0100); - tty->column += 2; + ldata->column += 2; space -= 2; cp += 2; nr -= 2; @@ -641,14 +654,14 @@ static void process_echoes(struct tty_struct *tty) if (nr == 0) { tty->echo_pos = 0; tty->echo_cnt = 0; - tty->echo_overrun = 0; + ldata->echo_overrun = 0; } else { int num_processed = tty->echo_cnt - nr; tty->echo_pos += num_processed; tty->echo_pos &= N_TTY_BUF_SIZE - 1; tty->echo_cnt = nr; if (num_processed > 0) - tty->echo_overrun = 0; + ldata->echo_overrun = 0; } mutex_unlock(&tty->echo_lock); @@ -670,6 +683,7 @@ static void process_echoes(struct tty_struct *tty) static void add_echo_byte(unsigned char c, struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int new_byte_pos; if (tty->echo_cnt == N_TTY_BUF_SIZE) { @@ -695,7 +709,7 @@ static void add_echo_byte(unsigned char c, struct tty_struct *tty) } tty->echo_pos &= N_TTY_BUF_SIZE - 1; - tty->echo_overrun = 1; + ldata->echo_overrun = 1; } else { new_byte_pos = tty->echo_pos + tty->echo_cnt; new_byte_pos &= N_TTY_BUF_SIZE - 1; @@ -845,9 +859,10 @@ static void echo_char(unsigned char c, struct tty_struct *tty) static inline void finish_erasing(struct tty_struct *tty) { - if (tty->erasing) { + struct n_tty_data *ldata = tty->disc_data; + if (ldata->erasing) { echo_char_raw('/', tty); - tty->erasing = 0; + ldata->erasing = 0; } } @@ -865,6 +880,7 @@ static inline void finish_erasing(struct tty_struct *tty) static void eraser(unsigned char c, struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; enum { ERASE, WERASE, KILL } kill_type; int head, seen_alnums, cnt; unsigned long flags; @@ -932,9 +948,9 @@ static void eraser(unsigned char c, struct tty_struct *tty) spin_unlock_irqrestore(&tty->read_lock, flags); if (L_ECHO(tty)) { if (L_ECHOPRT(tty)) { - if (!tty->erasing) { + if (!ldata->erasing) { echo_char_raw('\\', tty); - tty->erasing = 1; + ldata->erasing = 1; } /* if cnt > 1, output a multi-byte character */ echo_char(c, tty); @@ -1056,16 +1072,17 @@ static inline void n_tty_receive_break(struct tty_struct *tty) static inline void n_tty_receive_overrun(struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; char buf[64]; - tty->num_overrun++; - if (time_before(tty->overrun_time, jiffies - HZ) || - time_after(tty->overrun_time, jiffies)) { + ldata->num_overrun++; + if (time_after(jiffies, ldata->overrun_time + HZ) || + time_after(ldata->overrun_time, jiffies)) { printk(KERN_WARNING "%s: %d input overrun(s)\n", tty_name(tty, buf), - tty->num_overrun); - tty->overrun_time = jiffies; - tty->num_overrun = 0; + ldata->num_overrun); + ldata->overrun_time = jiffies; + ldata->num_overrun = 0; } } @@ -1105,10 +1122,11 @@ static inline void n_tty_receive_parity_error(struct tty_struct *tty, static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; int parmrk; - if (tty->raw) { + if (ldata->raw) { put_tty_queue(c, tty); return; } @@ -1147,8 +1165,8 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c) * handle specially, do shortcut processing to speed things * up. */ - if (!test_bit(c, tty->process_char_map) || tty->lnext) { - tty->lnext = 0; + if (!test_bit(c, tty->process_char_map) || ldata->lnext) { + ldata->lnext = 0; parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { /* beep if no space */ @@ -1222,7 +1240,7 @@ send_signal: } else if (c == '\n' && I_INLCR(tty)) c = '\r'; - if (tty->icanon) { + if (ldata->icanon) { if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { eraser(c, tty); @@ -1230,7 +1248,7 @@ send_signal: return; } if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { - tty->lnext = 1; + ldata->lnext = 1; if (L_ECHO(tty)) { finish_erasing(tty); if (L_ECHOCTL(tty)) { @@ -1373,13 +1391,14 @@ static void n_tty_write_wakeup(struct tty_struct *tty) static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { + struct n_tty_data *ldata = tty->disc_data; const unsigned char *p; char *f, flags = TTY_NORMAL; int i; char buf[64]; unsigned long cpuflags; - if (tty->real_raw) { + if (ldata->real_raw) { spin_lock_irqsave(&tty->read_lock, cpuflags); i = min(N_TTY_BUF_SIZE - tty->read_cnt, N_TTY_BUF_SIZE - tty->read_head); @@ -1427,7 +1446,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, n_tty_set_room(tty); - if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) || + if ((!ldata->icanon && (tty->read_cnt >= tty->minimum_to_wake)) || L_EXTPROC(tty)) { kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) @@ -1471,6 +1490,7 @@ int is_ignored(int sig) static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) { + struct n_tty_data *ldata = tty->disc_data; int canon_change = 1; if (old) @@ -1479,16 +1499,16 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) memset(&tty->read_flags, 0, sizeof tty->read_flags); tty->canon_head = tty->read_tail; tty->canon_data = 0; - tty->erasing = 0; + ldata->erasing = 0; } if (canon_change && !L_ICANON(tty) && tty->read_cnt) wake_up_interruptible(&tty->read_wait); - tty->icanon = (L_ICANON(tty) != 0); + ldata->icanon = (L_ICANON(tty) != 0); if (test_bit(TTY_HW_COOK_IN, &tty->flags)) { - tty->raw = 1; - tty->real_raw = 1; + ldata->raw = 1; + ldata->real_raw = 1; n_tty_set_room(tty); return; } @@ -1531,16 +1551,16 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) set_bit(SUSP_CHAR(tty), tty->process_char_map); } clear_bit(__DISABLED_CHAR, tty->process_char_map); - tty->raw = 0; - tty->real_raw = 0; + ldata->raw = 0; + ldata->real_raw = 0; } else { - tty->raw = 1; + ldata->raw = 1; if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && (I_IGNPAR(tty) || !I_INPCK(tty)) && (tty->driver->flags & TTY_DRIVER_REAL_RAW)) - tty->real_raw = 1; + ldata->real_raw = 1; else - tty->real_raw = 0; + ldata->real_raw = 0; } n_tty_set_room(tty); /* The termios change make the tty ready for I/O */ @@ -1589,6 +1609,8 @@ static int n_tty_open(struct tty_struct *tty) if (!ldata) goto err; + ldata->overrun_time = jiffies; + /* These are ugly. Currently a malloc failure here can panic */ tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); @@ -1598,7 +1620,7 @@ static int n_tty_open(struct tty_struct *tty) tty->disc_data = ldata; reset_buffer_flags(tty); tty_unthrottle(tty); - tty->column = 0; + ldata->column = 0; n_tty_set_termios(tty, NULL); tty->minimum_to_wake = 1; tty->closing = 0; @@ -1614,8 +1636,10 @@ err: static inline int input_available_p(struct tty_struct *tty, int amt) { + struct n_tty_data *ldata = tty->disc_data; + tty_flush_to_ldisc(tty); - if (tty->icanon && !L_EXTPROC(tty)) { + if (ldata->icanon && !L_EXTPROC(tty)) { if (tty->canon_data) return 1; } else if (tty->read_cnt >= (amt ? amt : 1)) @@ -1646,6 +1670,7 @@ static int copy_from_read_buf(struct tty_struct *tty, size_t *nr) { + struct n_tty_data *ldata = tty->disc_data; int retval; size_t n; unsigned long flags; @@ -1662,12 +1687,12 @@ static int copy_from_read_buf(struct tty_struct *tty, is_eof = n == 1 && tty->read_buf[tty->read_tail] == EOF_CHAR(tty); tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n, - tty->icanon); + ldata->icanon); spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_cnt -= n; /* Turn single EOF into zero-length read */ - if (L_EXTPROC(tty) && tty->icanon && is_eof && !tty->read_cnt) + if (L_EXTPROC(tty) && ldata->icanon && is_eof && !tty->read_cnt) n = 0; spin_unlock_irqrestore(&tty->read_lock, flags); *b += n; @@ -1736,6 +1761,7 @@ static int job_control(struct tty_struct *tty, struct file *file) static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr) { + struct n_tty_data *ldata = tty->disc_data; unsigned char __user *b = buf; DECLARE_WAITQUEUE(wait, current); int c; @@ -1753,7 +1779,7 @@ do_it_again: minimum = time = 0; timeout = MAX_SCHEDULE_TIMEOUT; - if (!tty->icanon) { + if (!ldata->icanon) { time = (HZ / 10) * TIME_CHAR(tty); minimum = MIN_CHAR(tty); if (minimum) { @@ -1846,7 +1872,7 @@ do_it_again: nr--; } - if (tty->icanon && !L_EXTPROC(tty)) { + if (ldata->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ spin_lock_irqsave(&tty->read_lock, flags); while (nr && tty->read_cnt) { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index e835a5b8d08..67b024ca16e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2932,7 +2932,6 @@ void initialize_tty_struct(struct tty_struct *tty, tty_ldisc_init(tty); tty->session = NULL; tty->pgrp = NULL; - tty->overrun_time = jiffies; tty_buffer_init(tty); mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); diff --git a/include/linux/tty.h b/include/linux/tty.h index f02712da5d8..de590cec973 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -270,13 +270,8 @@ struct tty_struct { * historical reasons, this is included in the tty structure. * Mostly locked by the BKL. */ - unsigned int column; - unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; unsigned char closing:1; - unsigned char echo_overrun:1; unsigned short minimum_to_wake; - unsigned long overrun_time; - int num_overrun; unsigned long process_char_map[256/(8*sizeof(unsigned long))]; char *read_buf; int read_head; -- cgit v1.2.3-70-g09d2 From bddc7152f68bc1e0ee1f55a8055e33531f384101 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Oct 2012 22:26:42 +0200 Subject: TTY: move ldisc data from tty_struct: locks atomic_write_lock is not n_tty specific, so move it up in the tty_struct. And since these are the last ones to move, remove also the comment saying there are some ldisc' members. There are none now. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 123 ++++++++++++++++++++++++++++++--------------------- drivers/tty/tty_io.c | 4 -- include/linux/tty.h | 11 +---- 3 files changed, 73 insertions(+), 65 deletions(-) (limited to 'drivers/tty/tty_io.c') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 4794537a50f..0a6fcda9615 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -96,6 +96,11 @@ struct n_tty_data { int canon_data; unsigned long canon_head; unsigned int canon_column; + + struct mutex atomic_read_lock; + struct mutex output_lock; + struct mutex echo_lock; + spinlock_t read_lock; }; static inline int tty_put_user(struct tty_struct *tty, unsigned char x, @@ -171,14 +176,15 @@ static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty) static void put_tty_queue(unsigned char c, struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; unsigned long flags; /* * The problem of stomping on the buffers ends here. * Why didn't anyone see this one coming? --AJK */ - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); put_tty_queue_nolock(c, tty); - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); } /** @@ -212,13 +218,13 @@ static void reset_buffer_flags(struct tty_struct *tty) struct n_tty_data *ldata = tty->disc_data; unsigned long flags; - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); ldata->read_head = ldata->read_tail = ldata->read_cnt = 0; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); - mutex_lock(&tty->echo_lock); + mutex_lock(&ldata->echo_lock); ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0; - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); ldata->canon_head = ldata->canon_data = ldata->erasing = 0; bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); @@ -270,7 +276,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) unsigned long flags; ssize_t n = 0; - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); if (!ldata->icanon) { n = ldata->read_cnt; } else if (ldata->canon_data) { @@ -278,7 +284,7 @@ static ssize_t n_tty_chars_in_buffer(struct tty_struct *tty) ldata->canon_head - ldata->read_tail : ldata->canon_head + (N_TTY_BUF_SIZE - ldata->read_tail); } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); return n; } @@ -408,14 +414,15 @@ static int do_output_char(unsigned char c, struct tty_struct *tty, int space) static int process_output(unsigned char c, struct tty_struct *tty) { + struct n_tty_data *ldata = tty->disc_data; int space, retval; - mutex_lock(&tty->output_lock); + mutex_lock(&ldata->output_lock); space = tty_write_room(tty); retval = do_output_char(c, tty, space); - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->output_lock); if (retval < 0) return -1; else @@ -449,11 +456,11 @@ static ssize_t process_output_block(struct tty_struct *tty, int i; const unsigned char *cp; - mutex_lock(&tty->output_lock); + mutex_lock(&ldata->output_lock); space = tty_write_room(tty); if (!space) { - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->output_lock); return 0; } if (nr > space) @@ -496,7 +503,7 @@ static ssize_t process_output_block(struct tty_struct *tty, break_out: i = tty->ops->write(tty, buf, i); - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->output_lock); return i; } @@ -536,8 +543,8 @@ static void process_echoes(struct tty_struct *tty) if (!ldata->echo_cnt) return; - mutex_lock(&tty->output_lock); - mutex_lock(&tty->echo_lock); + mutex_lock(&ldata->output_lock); + mutex_lock(&ldata->echo_lock); space = tty_write_room(tty); @@ -682,8 +689,8 @@ static void process_echoes(struct tty_struct *tty) ldata->echo_overrun = 0; } - mutex_unlock(&tty->echo_lock); - mutex_unlock(&tty->output_lock); + mutex_unlock(&ldata->echo_lock); + mutex_unlock(&ldata->output_lock); if (tty->ops->flush_chars) tty->ops->flush_chars(tty); @@ -748,12 +755,14 @@ static void add_echo_byte(unsigned char c, struct tty_struct *tty) static void echo_move_back_col(struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); + struct n_tty_data *ldata = tty->disc_data; + + mutex_lock(&ldata->echo_lock); add_echo_byte(ECHO_OP_START, tty); add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty); - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -768,12 +777,14 @@ static void echo_move_back_col(struct tty_struct *tty) static void echo_set_canon_col(struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); + struct n_tty_data *ldata = tty->disc_data; + + mutex_lock(&ldata->echo_lock); add_echo_byte(ECHO_OP_START, tty); add_echo_byte(ECHO_OP_SET_CANON_COL, tty); - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -796,7 +807,9 @@ static void echo_set_canon_col(struct tty_struct *tty) static void echo_erase_tab(unsigned int num_chars, int after_tab, struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); + struct n_tty_data *ldata = tty->disc_data; + + mutex_lock(&ldata->echo_lock); add_echo_byte(ECHO_OP_START, tty); add_echo_byte(ECHO_OP_ERASE_TAB, tty); @@ -810,7 +823,7 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, add_echo_byte(num_chars, tty); - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -828,7 +841,9 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab, static void echo_char_raw(unsigned char c, struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); + struct n_tty_data *ldata = tty->disc_data; + + mutex_lock(&ldata->echo_lock); if (c == ECHO_OP_START) { add_echo_byte(ECHO_OP_START, tty); @@ -837,7 +852,7 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty) add_echo_byte(c, tty); } - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -856,7 +871,9 @@ static void echo_char_raw(unsigned char c, struct tty_struct *tty) static void echo_char(unsigned char c, struct tty_struct *tty) { - mutex_lock(&tty->echo_lock); + struct n_tty_data *ldata = tty->disc_data; + + mutex_lock(&ldata->echo_lock); if (c == ECHO_OP_START) { add_echo_byte(ECHO_OP_START, tty); @@ -867,7 +884,7 @@ static void echo_char(unsigned char c, struct tty_struct *tty) add_echo_byte(c, tty); } - mutex_unlock(&tty->echo_lock); + mutex_unlock(&ldata->echo_lock); } /** @@ -914,19 +931,19 @@ static void eraser(unsigned char c, struct tty_struct *tty) kill_type = WERASE; else { if (!L_ECHO(tty)) { - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & (N_TTY_BUF_SIZE - 1)); ldata->read_head = ldata->canon_head; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); return; } if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) & (N_TTY_BUF_SIZE - 1)); ldata->read_head = ldata->canon_head; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); finish_erasing(tty); echo_char(KILL_CHAR(tty), tty); /* Add a newline if ECHOK is on and ECHOKE is off. */ @@ -960,10 +977,10 @@ static void eraser(unsigned char c, struct tty_struct *tty) break; } cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1); - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); ldata->read_head = head; ldata->read_cnt -= cnt; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (L_ECHO(tty)) { if (L_ECHOPRT(tty)) { if (!ldata->erasing) { @@ -1338,12 +1355,12 @@ send_signal: put_tty_queue(c, tty); handle_newline: - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); set_bit(ldata->read_head, ldata->read_flags); put_tty_queue_nolock(c, tty); ldata->canon_head = ldata->read_head; ldata->canon_data++; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); kill_fasync(&tty->fasync, SIGIO, POLL_IN); if (waitqueue_active(&tty->read_wait)) wake_up_interruptible(&tty->read_wait); @@ -1417,7 +1434,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, unsigned long cpuflags; if (ldata->real_raw) { - spin_lock_irqsave(&tty->read_lock, cpuflags); + spin_lock_irqsave(&ldata->read_lock, cpuflags); i = min(N_TTY_BUF_SIZE - ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_head); i = min(count, i); @@ -1433,7 +1450,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, memcpy(ldata->read_buf + ldata->read_head, cp, i); ldata->read_head = (ldata->read_head + i) & (N_TTY_BUF_SIZE-1); ldata->read_cnt += i; - spin_unlock_irqrestore(&tty->read_lock, cpuflags); + spin_unlock_irqrestore(&ldata->read_lock, cpuflags); } else { for (i = count, p = cp, f = fp; i; i--, p++) { if (f) @@ -1626,6 +1643,10 @@ static int n_tty_open(struct tty_struct *tty) goto err; ldata->overrun_time = jiffies; + mutex_init(&ldata->atomic_read_lock); + mutex_init(&ldata->output_lock); + mutex_init(&ldata->echo_lock); + spin_lock_init(&ldata->read_lock); /* These are ugly. Currently a malloc failure here can panic */ ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); @@ -1677,7 +1698,7 @@ static inline int input_available_p(struct tty_struct *tty, int amt) * buffer, and once to drain the space from the (physical) beginning of * the buffer to head pointer. * - * Called under the tty->atomic_read_lock sem + * Called under the ldata->atomic_read_lock sem * */ @@ -1693,10 +1714,10 @@ static int copy_from_read_buf(struct tty_struct *tty, bool is_eof; retval = 0; - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); n = min(ldata->read_cnt, N_TTY_BUF_SIZE - ldata->read_tail); n = min(*nr, n); - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (n) { retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n); n -= retval; @@ -1704,13 +1725,13 @@ static int copy_from_read_buf(struct tty_struct *tty, ldata->read_buf[ldata->read_tail] == EOF_CHAR(tty); tty_audit_add_data(tty, &ldata->read_buf[ldata->read_tail], n, ldata->icanon); - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); ldata->read_tail = (ldata->read_tail + n) & (N_TTY_BUF_SIZE-1); ldata->read_cnt -= n; /* Turn single EOF into zero-length read */ if (L_EXTPROC(tty) && ldata->icanon && is_eof && !ldata->read_cnt) n = 0; - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); *b += n; *nr -= n; } @@ -1818,10 +1839,10 @@ do_it_again: * Internal serialization of reads. */ if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&tty->atomic_read_lock)) + if (!mutex_trylock(&ldata->atomic_read_lock)) return -EAGAIN; } else { - if (mutex_lock_interruptible(&tty->atomic_read_lock)) + if (mutex_lock_interruptible(&ldata->atomic_read_lock)) return -ERESTARTSYS; } packet = tty->packet; @@ -1890,7 +1911,7 @@ do_it_again: if (ldata->icanon && !L_EXTPROC(tty)) { /* N.B. avoid overrun if nr == 0 */ - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); while (nr && ldata->read_cnt) { int eol; @@ -1908,25 +1929,25 @@ do_it_again: if (--ldata->canon_data < 0) ldata->canon_data = 0; } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (!eol || (c != __DISABLED_CHAR)) { if (tty_put_user(tty, c, b++)) { retval = -EFAULT; b--; - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); break; } nr--; } if (eol) { tty_audit_push(tty); - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); break; } - spin_lock_irqsave(&tty->read_lock, flags); + spin_lock_irqsave(&ldata->read_lock, flags); } - spin_unlock_irqrestore(&tty->read_lock, flags); + spin_unlock_irqrestore(&ldata->read_lock, flags); if (retval) break; } else { @@ -1958,7 +1979,7 @@ do_it_again: if (time) timeout = time; } - mutex_unlock(&tty->atomic_read_lock); + mutex_unlock(&ldata->atomic_read_lock); remove_wait_queue(&tty->read_wait, &wait); if (!waitqueue_active(&tty->read_wait)) diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 67b024ca16e..f90b6217b3b 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -2939,11 +2939,7 @@ void initialize_tty_struct(struct tty_struct *tty, init_waitqueue_head(&tty->write_wait); init_waitqueue_head(&tty->read_wait); INIT_WORK(&tty->hangup_work, do_tty_hangup); - mutex_init(&tty->atomic_read_lock); mutex_init(&tty->atomic_write_lock); - mutex_init(&tty->output_lock); - mutex_init(&tty->echo_lock); - spin_lock_init(&tty->read_lock); spin_lock_init(&tty->ctrl_lock); INIT_LIST_HEAD(&tty->tty_files); INIT_WORK(&tty->SAK_work, do_SAK_work); diff --git a/include/linux/tty.h b/include/linux/tty.h index 226cf20e015..08787ece3fd 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -235,6 +235,7 @@ struct tty_struct { struct mutex ldisc_mutex; struct tty_ldisc *ldisc; + struct mutex atomic_write_lock; struct mutex legacy_mutex; struct mutex termios_mutex; spinlock_t ctrl_lock; @@ -265,20 +266,10 @@ struct tty_struct { #define N_TTY_BUF_SIZE 4096 - /* - * The following is data for the N_TTY line discipline. For - * historical reasons, this is included in the tty structure. - * Mostly locked by the BKL. - */ unsigned char closing:1; unsigned short minimum_to_wake; - struct mutex atomic_read_lock; - struct mutex atomic_write_lock; - struct mutex output_lock; - struct mutex echo_lock; unsigned char *write_buf; int write_cnt; - spinlock_t read_lock; /* If the tty has a pending do_SAK, queue it here - akpm */ struct work_struct SAK_work; struct tty_port *port; -- cgit v1.2.3-70-g09d2 From 967fab6916681e5ab131fdef1226327b02454f19 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Oct 2012 22:26:46 +0200 Subject: TTY: add port -> tty link For that purpose we have to temporarily introduce a second tty back pointer into tty_port. It is because serial layer, and maybe others, still do not use tty_port_tty_set/get. So that we cannot set the tty_port->tty to NULL at will now. Yes, the fix would be to convert whole serial layer and all its users to tty_port_tty_set/get. However we are in the process of removing the need of tty in most of the call sites, so this would lead to a duplicated work. Instead we have now tty_port->itty (internal tty) which will be used only in flush_to_ldisc. For that one it is ensured that itty is valid wherever the work is run. IOW, the work is synchronously cancelled before we set itty to NULL and also before hangup is processed. After we need only tty_port and not tty_struct in most code, this shall be changed to tty_port_tty_set/get and itty removed completely. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 2 ++ drivers/tty/tty_io.c | 3 +++ include/linux/tty.h | 1 + 3 files changed, 6 insertions(+) (limited to 'drivers/tty/tty_io.c') diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 2728afe52ee..c3269086267 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -345,6 +345,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, tty_port_init(ports[1]); o_tty->port = ports[0]; tty->port = ports[1]; + o_tty->port->itty = o_tty; tty_driver_kref_get(driver); tty->count++; @@ -371,6 +372,7 @@ static void pty_unix98_shutdown(struct tty_struct *tty) static void pty_cleanup(struct tty_struct *tty) { + tty->port->itty = NULL; kfree(tty->port); } diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index f90b6217b3b..202008f38ca 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -1417,6 +1417,8 @@ struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", __func__, tty->driver->name); + tty->port->itty = tty; + /* * Structures all installed ... call the ldisc open routines. * If we fail here just call release_tty to clean up. No need @@ -1552,6 +1554,7 @@ static void release_tty(struct tty_struct *tty, int idx) tty->ops->shutdown(tty); tty_free_termios(tty); tty_driver_remove_tty(tty->driver, tty); + tty->port->itty = NULL; if (tty->link) tty_kref_put(tty->link); diff --git a/include/linux/tty.h b/include/linux/tty.h index b4b3c568d24..9be74d649a5 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -189,6 +189,7 @@ struct tty_port_operations { struct tty_port { struct tty_struct *tty; /* Back pointer */ + struct tty_struct *itty; /* internal back ptr */ const struct tty_port_operations *ops; /* Port operations */ spinlock_t lock; /* Lock protecting tty field */ int blocked_open; /* Waiting to open */ -- cgit v1.2.3-70-g09d2 From ecbbfd44a08fa80e0d664814efd4c187721b85f6 Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Thu, 18 Oct 2012 22:26:47 +0200 Subject: TTY: move tty buffers to tty_port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So this is it. The big step why we did all the work over the past kernel releases. Now everything is prepared, so nothing protects us from doing that big step. | | \ \ nnnn/^l | | | | \ / / | | | '-,.__ => \/ ,-` => | '-,.__ | O __.´´) ( .` | O __.´´) ~~~ ~~ `` ~~~ ~~ The buffers are now in the tty_port structure and we can start teaching the buffer helpers (insert char/string, flip etc.) to use tty_port instead of tty_struct all around. Signed-off-by: Jiri Slaby Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_tty.c | 7 +++- drivers/tty/pty.c | 2 +- drivers/tty/tty_buffer.c | 102 ++++++++++++++++++++++++----------------------- drivers/tty/tty_io.c | 2 - drivers/tty/tty_ldisc.c | 10 ++--- drivers/tty/tty_port.c | 2 + include/linux/tty.h | 6 +-- include/linux/tty_flip.h | 2 +- 8 files changed, 70 insertions(+), 63 deletions(-) (limited to 'drivers/tty/tty_io.c') diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 531e539dbfc..60b076cc4e2 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -149,8 +149,11 @@ static void n_tty_set_room(struct tty_struct *tty) tty->receive_room = left; /* Did this open up the receive buffer? We may need to flip */ - if (left && !old_left) - schedule_work(&tty->buf.work); + if (left && !old_left) { + WARN_RATELIMIT(tty->port->itty == NULL, + "scheduling with invalid itty"); + schedule_work(&tty->port->buf.work); + } } static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index c3269086267..4219f040adb 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -93,7 +93,7 @@ static void pty_unthrottle(struct tty_struct *tty) static int pty_space(struct tty_struct *to) { - int n = 8192 - to->buf.memory_used; + int n = 8192 - to->port->buf.memory_used; if (n < 0) return 0; return n; diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index ddd74d41cbb..06725f5cc81 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -27,9 +27,9 @@ * Locking: none */ -void tty_buffer_free_all(struct tty_struct *tty) +void tty_buffer_free_all(struct tty_port *port) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &port->buf; struct tty_buffer *thead; while ((thead = buf->head) != NULL) { @@ -56,11 +56,11 @@ void tty_buffer_free_all(struct tty_struct *tty) * Locking: Caller must hold tty->buf.lock */ -static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) +static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) { struct tty_buffer *p; - if (tty->buf.memory_used + size > 65536) + if (port->buf.memory_used + size > 65536) return NULL; p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); if (p == NULL) @@ -72,7 +72,7 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) p->read = 0; p->char_buf_ptr = (char *)(p->data); p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size; - tty->buf.memory_used += size; + port->buf.memory_used += size; return p; } @@ -87,9 +87,9 @@ static struct tty_buffer *tty_buffer_alloc(struct tty_struct *tty, size_t size) * Locking: Caller must hold tty->buf.lock */ -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) +static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &port->buf; /* Dumb strategy for now - should keep some stats */ buf->memory_used -= b->size; @@ -114,14 +114,14 @@ static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b) * Locking: Caller must hold tty->buf.lock */ -static void __tty_buffer_flush(struct tty_struct *tty) +static void __tty_buffer_flush(struct tty_port *port) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &port->buf; struct tty_buffer *thead; while ((thead = buf->head) != NULL) { buf->head = thead->next; - tty_buffer_free(tty, thead); + tty_buffer_free(port, thead); } buf->tail = NULL; } @@ -140,7 +140,7 @@ static void __tty_buffer_flush(struct tty_struct *tty) void tty_buffer_flush(struct tty_struct *tty) { struct tty_port *port = tty->port; - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &port->buf; unsigned long flags; spin_lock_irqsave(&buf->lock, flags); @@ -155,7 +155,7 @@ void tty_buffer_flush(struct tty_struct *tty) test_bit(TTYP_FLUSHPENDING, &port->iflags) == 0); return; } else - __tty_buffer_flush(tty); + __tty_buffer_flush(port); spin_unlock_irqrestore(&buf->lock, flags); } @@ -171,9 +171,9 @@ void tty_buffer_flush(struct tty_struct *tty) * Locking: Caller must hold tty->buf.lock */ -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) +static struct tty_buffer *tty_buffer_find(struct tty_port *port, size_t size) { - struct tty_buffer **tbh = &tty->buf.free; + struct tty_buffer **tbh = &port->buf.free; while ((*tbh) != NULL) { struct tty_buffer *t = *tbh; if (t->size >= size) { @@ -182,14 +182,14 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) t->used = 0; t->commit = 0; t->read = 0; - tty->buf.memory_used += t->size; + port->buf.memory_used += t->size; return t; } tbh = &((*tbh)->next); } /* Round the buffer size out */ size = (size + 0xFF) & ~0xFF; - return tty_buffer_alloc(tty, size); + return tty_buffer_alloc(port, size); /* Should possibly check if this fails for the largest buffer we have queued and recycle that ? */ } @@ -200,11 +200,11 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size) * * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. - * Locking: Caller must hold tty->buf.lock + * Locking: Caller must hold port->buf.lock */ -static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) +static int __tty_buffer_request_room(struct tty_port *port, size_t size) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &port->buf; struct tty_buffer *b, *n; int left; /* OPTIMISATION: We could keep a per tty "zero" sized buffer to @@ -218,7 +218,7 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) if (left < size) { /* This is the slow path - looking for new buffers to use */ - if ((n = tty_buffer_find(tty, size)) != NULL) { + if ((n = tty_buffer_find(port, size)) != NULL) { if (b != NULL) { b->next = n; b->commit = b->used; @@ -241,16 +241,17 @@ static int __tty_buffer_request_room(struct tty_struct *tty, size_t size) * Make at least size bytes of linear space available for the tty * buffer. If we fail return the size we managed to find. * - * Locking: Takes tty->buf.lock + * Locking: Takes port->buf.lock */ int tty_buffer_request_room(struct tty_struct *tty, size_t size) { + struct tty_port *port = tty->port; unsigned long flags; int length; - spin_lock_irqsave(&tty->buf.lock, flags); - length = __tty_buffer_request_room(tty, size); - spin_unlock_irqrestore(&tty->buf.lock, flags); + spin_lock_irqsave(&port->buf.lock, flags); + length = __tty_buffer_request_room(port, size); + spin_unlock_irqrestore(&port->buf.lock, flags); return length; } EXPORT_SYMBOL_GPL(tty_buffer_request_room); @@ -265,13 +266,13 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room); * Queue a series of bytes to the tty buffering. All the characters * passed are marked with the supplied flag. Returns the number added. * - * Locking: Called functions may take tty->buf.lock + * Locking: Called functions may take port->buf.lock */ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, const unsigned char *chars, char flag, size_t size) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &tty->port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); @@ -280,7 +281,7 @@ int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, flags); - space = __tty_buffer_request_room(tty, goal); + space = __tty_buffer_request_room(tty->port, goal); tb = buf->tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { @@ -311,13 +312,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); * the flags array indicates the status of the character. Returns the * number added. * - * Locking: Called functions may take tty->buf.lock + * Locking: Called functions may take port->buf.lock */ int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &tty->port->buf; int copied = 0; do { int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); @@ -326,7 +327,7 @@ int tty_insert_flip_string_flags(struct tty_struct *tty, struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, __flags); - space = __tty_buffer_request_room(tty, goal); + space = __tty_buffer_request_room(tty->port, goal); tb = buf->tail; /* If there is no space then tb may be NULL */ if (unlikely(space == 0)) { @@ -357,12 +358,12 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); * Note that this function can only be used when the low_latency flag * is unset. Otherwise the workqueue won't be flushed. * - * Locking: Takes tty->buf.lock + * Locking: Takes port->buf.lock */ void tty_schedule_flip(struct tty_struct *tty) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &tty->port->buf; unsigned long flags; spin_lock_irqsave(&buf->lock, flags); @@ -385,19 +386,19 @@ EXPORT_SYMBOL(tty_schedule_flip); * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! * - * Locking: May call functions taking tty->buf.lock + * Locking: May call functions taking port->buf.lock */ int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, - size_t size) + size_t size) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &tty->port->buf; int space; unsigned long flags; struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, flags); - space = __tty_buffer_request_room(tty, size); + space = __tty_buffer_request_room(tty->port, size); tb = buf->tail; if (likely(space)) { @@ -423,19 +424,19 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string); * that need their own block copy routines into the buffer. There is no * guarantee the buffer is a DMA target! * - * Locking: May call functions taking tty->buf.lock + * Locking: May call functions taking port->buf.lock */ int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &tty->port->buf; int space; unsigned long __flags; struct tty_buffer *tb; spin_lock_irqsave(&buf->lock, __flags); - space = __tty_buffer_request_room(tty, size); + space = __tty_buffer_request_room(tty->port, size); tb = buf->tail; if (likely(space)) { @@ -464,13 +465,16 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags); static void flush_to_ldisc(struct work_struct *work) { - struct tty_struct *tty = - container_of(work, struct tty_struct, buf.work); - struct tty_port *port = tty->port; - struct tty_bufhead *buf = &tty->buf; + struct tty_port *port = container_of(work, struct tty_port, buf.work); + struct tty_bufhead *buf = &port->buf; + struct tty_struct *tty; unsigned long flags; struct tty_ldisc *disc; + tty = port->itty; + if (WARN_RATELIMIT(tty == NULL, "tty is NULL")) + return; + disc = tty_ldisc_ref(tty); if (disc == NULL) /* !TTY_LDISC */ return; @@ -489,7 +493,7 @@ static void flush_to_ldisc(struct work_struct *work) if (head->next == NULL) break; buf->head = head->next; - tty_buffer_free(tty, head); + tty_buffer_free(port, head); continue; } /* Ldisc or user is trying to flush the buffers @@ -515,7 +519,7 @@ static void flush_to_ldisc(struct work_struct *work) /* We may have a deferred request to flush the input buffer, if so pull the chain under the lock and empty the queue */ if (test_bit(TTYP_FLUSHPENDING, &port->iflags)) { - __tty_buffer_flush(tty); + __tty_buffer_flush(port); clear_bit(TTYP_FLUSHPENDING, &port->iflags); wake_up(&tty->read_wait); } @@ -535,7 +539,7 @@ static void flush_to_ldisc(struct work_struct *work) void tty_flush_to_ldisc(struct tty_struct *tty) { if (!tty->low_latency) - flush_work(&tty->buf.work); + flush_work(&tty->port->buf.work); } /** @@ -553,7 +557,7 @@ void tty_flush_to_ldisc(struct tty_struct *tty) void tty_flip_buffer_push(struct tty_struct *tty) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &tty->port->buf; unsigned long flags; spin_lock_irqsave(&buf->lock, flags); @@ -578,9 +582,9 @@ EXPORT_SYMBOL(tty_flip_buffer_push); * Locking: none */ -void tty_buffer_init(struct tty_struct *tty) +void tty_buffer_init(struct tty_port *port) { - struct tty_bufhead *buf = &tty->buf; + struct tty_bufhead *buf = &port->buf; spin_lock_init(&buf->lock); buf->head = NULL; diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 202008f38ca..a3eba7f359e 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -186,7 +186,6 @@ void free_tty_struct(struct tty_struct *tty) if (tty->dev) put_device(tty->dev); kfree(tty->write_buf); - tty_buffer_free_all(tty); tty->magic = 0xDEADDEAD; kfree(tty); } @@ -2935,7 +2934,6 @@ void initialize_tty_struct(struct tty_struct *tty, tty_ldisc_init(tty); tty->session = NULL; tty->pgrp = NULL; - tty_buffer_init(tty); mutex_init(&tty->legacy_mutex); mutex_init(&tty->termios_mutex); mutex_init(&tty->ldisc_mutex); diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 47e3968df10..f4e6754525d 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c @@ -512,7 +512,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) static int tty_ldisc_halt(struct tty_struct *tty) { clear_bit(TTY_LDISC, &tty->flags); - return cancel_work_sync(&tty->buf.work); + return cancel_work_sync(&tty->port->buf.work); } /** @@ -525,7 +525,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) { flush_work(&tty->hangup_work); flush_work(&tty->SAK_work); - flush_work(&tty->buf.work); + flush_work(&tty->port->buf.work); } /** @@ -704,9 +704,9 @@ enable: /* Restart the work queue in case no characters kick it off. Safe if already running */ if (work) - schedule_work(&tty->buf.work); + schedule_work(&tty->port->buf.work); if (o_work) - schedule_work(&o_tty->buf.work); + schedule_work(&o_tty->port->buf.work); mutex_unlock(&tty->ldisc_mutex); tty_unlock(tty); return retval; @@ -817,7 +817,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) */ clear_bit(TTY_LDISC, &tty->flags); tty_unlock(tty); - cancel_work_sync(&tty->buf.work); + cancel_work_sync(&tty->port->buf.work); mutex_unlock(&tty->ldisc_mutex); retry: tty_lock(tty); diff --git a/drivers/tty/tty_port.c b/drivers/tty/tty_port.c index d7bdd8d0c23..416b42f7c34 100644 --- a/drivers/tty/tty_port.c +++ b/drivers/tty/tty_port.c @@ -21,6 +21,7 @@ void tty_port_init(struct tty_port *port) { memset(port, 0, sizeof(*port)); + tty_buffer_init(port); init_waitqueue_head(&port->open_wait); init_waitqueue_head(&port->close_wait); init_waitqueue_head(&port->delta_msr_wait); @@ -126,6 +127,7 @@ static void tty_port_destructor(struct kref *kref) struct tty_port *port = container_of(kref, struct tty_port, kref); if (port->xmit_buf) free_page((unsigned long)port->xmit_buf); + tty_buffer_free_all(port); if (port->ops->destruct) port->ops->destruct(port); else diff --git a/include/linux/tty.h b/include/linux/tty.h index 9be74d649a5..d7ff88fb896 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -188,6 +188,7 @@ struct tty_port_operations { }; struct tty_port { + struct tty_bufhead buf; /* Locked internally */ struct tty_struct *tty; /* Back pointer */ struct tty_struct *itty; /* internal back ptr */ const struct tty_port_operations *ops; /* Port operations */ @@ -259,7 +260,6 @@ struct tty_struct { struct tty_struct *link; struct fasync_struct *fasync; - struct tty_bufhead buf; /* Locked internally */ int alt_speed; /* For magic substitution of 38400 bps */ wait_queue_head_t write_wait; wait_queue_head_t read_wait; @@ -388,9 +388,9 @@ extern void disassociate_ctty(int priv); extern void no_tty(void); extern void tty_flip_buffer_push(struct tty_struct *tty); extern void tty_flush_to_ldisc(struct tty_struct *tty); -extern void tty_buffer_free_all(struct tty_struct *tty); +extern void tty_buffer_free_all(struct tty_port *port); extern void tty_buffer_flush(struct tty_struct *tty); -extern void tty_buffer_init(struct tty_struct *tty); +extern void tty_buffer_init(struct tty_port *port); extern speed_t tty_get_baud_rate(struct tty_struct *tty); extern speed_t tty_termios_baud_rate(struct ktermios *termios); extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index 9239d033a0a..2002344ed36 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -11,7 +11,7 @@ void tty_schedule_flip(struct tty_struct *tty); static inline int tty_insert_flip_char(struct tty_struct *tty, unsigned char ch, char flag) { - struct tty_buffer *tb = tty->buf.tail; + struct tty_buffer *tb = tty->port->buf.tail; if (tb && tb->used < tb->size) { tb->flag_buf_ptr[tb->used] = flag; tb->char_buf_ptr[tb->used++] = ch; -- cgit v1.2.3-70-g09d2