|
@@ -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))
|