diff options
Diffstat (limited to 'drivers/tty/n_tty.c')
| -rw-r--r-- | drivers/tty/n_tty.c | 752 | 
1 files changed, 403 insertions, 349 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c index 8c0b7b42319..60b076cc4e2 100644 --- a/drivers/tty/n_tty.c +++ b/drivers/tty/n_tty.c @@ -73,10 +73,42 @@  #define ECHO_OP_SET_CANON_COL 0x81  #define ECHO_OP_ERASE_TAB 0x82 +struct n_tty_data { +	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; + +	DECLARE_BITMAP(process_char_map, 256); +	DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE); + +	char *read_buf; +	int read_head; +	int read_tail; +	int read_cnt; + +	unsigned char *echo_buf; +	unsigned int echo_pos; +	unsigned int echo_cnt; + +	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,  			       unsigned char __user *ptr)  { -	tty_audit_add_data(tty, &x, 1); +	struct n_tty_data *ldata = tty->disc_data; + +	tty_audit_add_data(tty, &x, 1, ldata->icanon);  	return put_user(x, ptr);  } @@ -92,17 +124,18 @@ 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; -	/* tty->read_cnt is not read locked ? */ +	/* ldata->read_cnt is not read locked ? */  	if (I_PARMRK(tty)) {  		/* Multiply read_cnt by 3, since each byte might take up to  		 * three times as many spaces when PARMRK is set (depending on  		 * its flags, e.g. parity error). */ -		left = N_TTY_BUF_SIZE - tty->read_cnt * 3 - 1; +		left = N_TTY_BUF_SIZE - ldata->read_cnt * 3 - 1;  	} else -		left = N_TTY_BUF_SIZE - tty->read_cnt - 1; +		left = N_TTY_BUF_SIZE - ldata->read_cnt - 1;  	/*  	 * If we are doing input canonicalization, and there are no @@ -111,44 +144,47 @@ 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 && !ldata->canon_data;  	old_left = tty->receive_room;  	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 tty_struct *tty) +static void put_tty_queue_nolock(unsigned char c, struct n_tty_data *ldata)  { -	if (tty->read_cnt < N_TTY_BUF_SIZE) { -		tty->read_buf[tty->read_head] = c; -		tty->read_head = (tty->read_head + 1) & (N_TTY_BUF_SIZE-1); -		tty->read_cnt++; +	if (ldata->read_cnt < N_TTY_BUF_SIZE) { +		ldata->read_buf[ldata->read_head] = c; +		ldata->read_head = (ldata->read_head + 1) & (N_TTY_BUF_SIZE-1); +		ldata->read_cnt++;  	}  }  /**   *	put_tty_queue		-	add character to tty   *	@c: character - *	@tty: tty device + *	@ldata: n_tty data   *   *	Add a character to the tty read_buf queue. This is done under the   *	read_lock to serialize character addition and also to protect us   *	against parallel reads or flushes   */ -static void put_tty_queue(unsigned char c, struct tty_struct *tty) +static void put_tty_queue(unsigned char c, struct n_tty_data *ldata)  {  	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); -	put_tty_queue_nolock(c, tty); -	spin_unlock_irqrestore(&tty->read_lock, flags); +	spin_lock_irqsave(&ldata->read_lock, flags); +	put_tty_queue_nolock(c, ldata); +	spin_unlock_irqrestore(&ldata->read_lock, flags);  }  /** @@ -179,18 +215,19 @@ 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); -	tty->read_head = tty->read_tail = tty->read_cnt = 0; -	spin_unlock_irqrestore(&tty->read_lock, flags); +	spin_lock_irqsave(&ldata->read_lock, flags); +	ldata->read_head = ldata->read_tail = ldata->read_cnt = 0; +	spin_unlock_irqrestore(&ldata->read_lock, flags); -	mutex_lock(&tty->echo_lock); -	tty->echo_pos = tty->echo_cnt = tty->echo_overrun = 0; -	mutex_unlock(&tty->echo_lock); +	mutex_lock(&ldata->echo_lock); +	ldata->echo_pos = ldata->echo_cnt = ldata->echo_overrun = 0; +	mutex_unlock(&ldata->echo_lock); -	tty->canon_head = tty->canon_data = tty->erasing = 0; -	memset(&tty->read_flags, 0, sizeof tty->read_flags); +	ldata->canon_head = ldata->canon_data = ldata->erasing = 0; +	bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE);  	n_tty_set_room(tty);  } @@ -235,18 +272,19 @@ 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) { -		n = tty->read_cnt; -	} else if (tty->canon_data) { -		n = (tty->canon_head > tty->read_tail) ? -			tty->canon_head - tty->read_tail : -			tty->canon_head + (N_TTY_BUF_SIZE - tty->read_tail); +	spin_lock_irqsave(&ldata->read_lock, flags); +	if (!ldata->icanon) { +		n = ldata->read_cnt; +	} else if (ldata->canon_data) { +		n = (ldata->canon_head > ldata->read_tail) ? +			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;  } @@ -301,6 +339,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) @@ -309,48 +348,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; +			ldata->canon_column = ldata->column = 0;  			tty->ops->write(tty, "\r\n", 2);  			return 2;  		} -		tty->canon_column = tty->column; +		ldata->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; +				ldata->canon_column = ldata->column = 0;  			break;  		} -		tty->canon_column = tty->column = 0; +		ldata->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;  	} @@ -375,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 @@ -411,15 +451,16 @@ 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; -	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) @@ -431,30 +472,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; +			ldata->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; +			ldata->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;  		} @@ -462,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;  } @@ -494,21 +535,22 @@ 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; -	if (!tty->echo_cnt) +	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); -	buf_end = tty->echo_buf + N_TTY_BUF_SIZE; -	cp = tty->echo_buf + tty->echo_pos; -	nr = tty->echo_cnt; +	buf_end = ldata->echo_buf + N_TTY_BUF_SIZE; +	cp = ldata->echo_buf + ldata->echo_pos; +	nr = ldata->echo_cnt;  	while (nr > 0) {  		c = *cp;  		if (c == ECHO_OP_START) { @@ -545,7 +587,7 @@ static void process_echoes(struct tty_struct *tty)  				 * Otherwise, tab spacing is normal.  				 */  				if (!(num_chars & 0x80)) -					num_chars += tty->canon_column; +					num_chars += ldata->canon_column;  				num_bs = 8 - (num_chars & 7);  				if (num_bs > space) { @@ -555,22 +597,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; +				ldata->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; @@ -582,7 +624,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; @@ -604,7 +646,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; @@ -635,20 +677,20 @@ 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_pos = 0; +		ldata->echo_cnt = 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; +		int num_processed = ldata->echo_cnt - nr; +		ldata->echo_pos += num_processed; +		ldata->echo_pos &= N_TTY_BUF_SIZE - 1; +		ldata->echo_cnt = nr;  		if (num_processed > 0) -			tty->echo_overrun = 0; +			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); @@ -657,72 +699,70 @@ static void process_echoes(struct tty_struct *tty)  /**   *	add_echo_byte	-	add a byte to the echo buffer   *	@c: unicode byte to echo - *	@tty: terminal device + *	@ldata: n_tty data   *   *	Add a character or operation byte to the echo buffer.   *   *	Should be called under the echo lock to protect the echo buffer.   */ -static void add_echo_byte(unsigned char c, struct tty_struct *tty) +static void add_echo_byte(unsigned char c, struct n_tty_data *ldata)  {  	int	new_byte_pos; -	if (tty->echo_cnt == N_TTY_BUF_SIZE) { +	if (ldata->echo_cnt == N_TTY_BUF_SIZE) {  		/* Circular buffer is already at capacity */ -		new_byte_pos = tty->echo_pos; +		new_byte_pos = ldata->echo_pos;  		/*  		 * Since the buffer start position needs to be advanced,  		 * be sure to step by a whole operation byte group.  		 */ -		if (tty->echo_buf[tty->echo_pos] == ECHO_OP_START) { -			if (tty->echo_buf[(tty->echo_pos + 1) & +		if (ldata->echo_buf[ldata->echo_pos] == ECHO_OP_START) { +			if (ldata->echo_buf[(ldata->echo_pos + 1) &  					  (N_TTY_BUF_SIZE - 1)] ==  						ECHO_OP_ERASE_TAB) { -				tty->echo_pos += 3; -				tty->echo_cnt -= 2; +				ldata->echo_pos += 3; +				ldata->echo_cnt -= 2;  			} else { -				tty->echo_pos += 2; -				tty->echo_cnt -= 1; +				ldata->echo_pos += 2; +				ldata->echo_cnt -= 1;  			}  		} else { -			tty->echo_pos++; +			ldata->echo_pos++;  		} -		tty->echo_pos &= N_TTY_BUF_SIZE - 1; +		ldata->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 = ldata->echo_pos + ldata->echo_cnt;  		new_byte_pos &= N_TTY_BUF_SIZE - 1; -		tty->echo_cnt++; +		ldata->echo_cnt++;  	} -	tty->echo_buf[new_byte_pos] = c; +	ldata->echo_buf[new_byte_pos] = c;  }  /**   *	echo_move_back_col	-	add operation to move back a column - *	@tty: terminal device + *	@ldata: n_tty data   *   *	Add an operation to the echo buffer to move back one column.   *   *	Locking: echo_lock to protect the echo buffer   */ -static void echo_move_back_col(struct tty_struct *tty) +static void echo_move_back_col(struct n_tty_data *ldata)  { -	mutex_lock(&tty->echo_lock); - -	add_echo_byte(ECHO_OP_START, tty); -	add_echo_byte(ECHO_OP_MOVE_BACK_COL, tty); - -	mutex_unlock(&tty->echo_lock); +	mutex_lock(&ldata->echo_lock); +	add_echo_byte(ECHO_OP_START, ldata); +	add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata); +	mutex_unlock(&ldata->echo_lock);  }  /**   *	echo_set_canon_col	-	add operation to set the canon column - *	@tty: terminal device + *	@ldata: n_tty data   *   *	Add an operation to the echo buffer to set the canon column   *	to the current column. @@ -730,21 +770,19 @@ static void echo_move_back_col(struct tty_struct *tty)   *	Locking: echo_lock to protect the echo buffer   */ -static void echo_set_canon_col(struct tty_struct *tty) +static void echo_set_canon_col(struct n_tty_data *ldata)  { -	mutex_lock(&tty->echo_lock); - -	add_echo_byte(ECHO_OP_START, tty); -	add_echo_byte(ECHO_OP_SET_CANON_COL, tty); - -	mutex_unlock(&tty->echo_lock); +	mutex_lock(&ldata->echo_lock); +	add_echo_byte(ECHO_OP_START, ldata); +	add_echo_byte(ECHO_OP_SET_CANON_COL, ldata); +	mutex_unlock(&ldata->echo_lock);  }  /**   *	echo_erase_tab	-	add operation to erase a tab   *	@num_chars: number of character columns already used   *	@after_tab: true if num_chars starts after a previous tab - *	@tty: terminal device + *	@ldata: n_tty data   *   *	Add an operation to the echo buffer to erase a tab.   * @@ -758,12 +796,12 @@ 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) +			   struct n_tty_data *ldata)  { -	mutex_lock(&tty->echo_lock); +	mutex_lock(&ldata->echo_lock); -	add_echo_byte(ECHO_OP_START, tty); -	add_echo_byte(ECHO_OP_ERASE_TAB, tty); +	add_echo_byte(ECHO_OP_START, ldata); +	add_echo_byte(ECHO_OP_ERASE_TAB, ldata);  	/* We only need to know this modulo 8 (tab spacing) */  	num_chars &= 7; @@ -772,9 +810,9 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,  	if (after_tab)  		num_chars |= 0x80; -	add_echo_byte(num_chars, tty); +	add_echo_byte(num_chars, ldata); -	mutex_unlock(&tty->echo_lock); +	mutex_unlock(&ldata->echo_lock);  }  /** @@ -790,18 +828,16 @@ static void echo_erase_tab(unsigned int num_chars, int after_tab,   *	Locking: echo_lock to protect the echo buffer   */ -static void echo_char_raw(unsigned char c, struct tty_struct *tty) +static void echo_char_raw(unsigned char c, struct n_tty_data *ldata)  { -	mutex_lock(&tty->echo_lock); - +	mutex_lock(&ldata->echo_lock);  	if (c == ECHO_OP_START) { -		add_echo_byte(ECHO_OP_START, tty); -		add_echo_byte(ECHO_OP_START, tty); +		add_echo_byte(ECHO_OP_START, ldata); +		add_echo_byte(ECHO_OP_START, ldata);  	} else { -		add_echo_byte(c, tty); +		add_echo_byte(c, ldata);  	} - -	mutex_unlock(&tty->echo_lock); +	mutex_unlock(&ldata->echo_lock);  }  /** @@ -820,30 +856,32 @@ 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); -		add_echo_byte(ECHO_OP_START, tty); +		add_echo_byte(ECHO_OP_START, ldata); +		add_echo_byte(ECHO_OP_START, ldata);  	} else {  		if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') -			add_echo_byte(ECHO_OP_START, tty); -		add_echo_byte(c, tty); +			add_echo_byte(ECHO_OP_START, ldata); +		add_echo_byte(c, ldata);  	} -	mutex_unlock(&tty->echo_lock); +	mutex_unlock(&ldata->echo_lock);  }  /**   *	finish_erasing		-	complete erase - *	@tty: tty doing the erase + *	@ldata: n_tty data   */ -static inline void finish_erasing(struct tty_struct *tty) +static inline void finish_erasing(struct n_tty_data *ldata)  { -	if (tty->erasing) { -		echo_char_raw('/', tty); -		tty->erasing = 0; +	if (ldata->erasing) { +		echo_char_raw('/', ldata); +		ldata->erasing = 0;  	}  } @@ -861,12 +899,13 @@ 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;  	/* FIXME: locking needed ? */ -	if (tty->read_head == tty->canon_head) { +	if (ldata->read_head == ldata->canon_head) {  		/* process_output('\a', tty); */ /* what do you think? */  		return;  	} @@ -876,24 +915,24 @@ 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); -			tty->read_cnt -= ((tty->read_head - tty->canon_head) & +			spin_lock_irqsave(&ldata->read_lock, flags); +			ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &  					  (N_TTY_BUF_SIZE - 1)); -			tty->read_head = tty->canon_head; -			spin_unlock_irqrestore(&tty->read_lock, flags); +			ldata->read_head = ldata->canon_head; +			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); -			tty->read_cnt -= ((tty->read_head - tty->canon_head) & +			spin_lock_irqsave(&ldata->read_lock, flags); +			ldata->read_cnt -= ((ldata->read_head - ldata->canon_head) &  					  (N_TTY_BUF_SIZE - 1)); -			tty->read_head = tty->canon_head; -			spin_unlock_irqrestore(&tty->read_lock, flags); -			finish_erasing(tty); +			ldata->read_head = ldata->canon_head; +			spin_unlock_irqrestore(&ldata->read_lock, flags); +			finish_erasing(ldata);  			echo_char(KILL_CHAR(tty), tty);  			/* Add a newline if ECHOK is on and ECHOKE is off. */  			if (L_ECHOK(tty)) -				echo_char_raw('\n', tty); +				echo_char_raw('\n', ldata);  			return;  		}  		kill_type = KILL; @@ -901,14 +940,14 @@ static void eraser(unsigned char c, struct tty_struct *tty)  	seen_alnums = 0;  	/* FIXME: Locking ?? */ -	while (tty->read_head != tty->canon_head) { -		head = tty->read_head; +	while (ldata->read_head != ldata->canon_head) { +		head = ldata->read_head;  		/* erase a single possibly multibyte character */  		do {  			head = (head - 1) & (N_TTY_BUF_SIZE-1); -			c = tty->read_buf[head]; -		} while (is_continuation(c, tty) && head != tty->canon_head); +			c = ldata->read_buf[head]; +		} while (is_continuation(c, tty) && head != ldata->canon_head);  		/* do not partially erase */  		if (is_continuation(c, tty)) @@ -921,30 +960,31 @@ static void eraser(unsigned char c, struct tty_struct *tty)  			else if (seen_alnums)  				break;  		} -		cnt = (tty->read_head - head) & (N_TTY_BUF_SIZE-1); -		spin_lock_irqsave(&tty->read_lock, flags); -		tty->read_head = head; -		tty->read_cnt -= cnt; -		spin_unlock_irqrestore(&tty->read_lock, flags); +		cnt = (ldata->read_head - head) & (N_TTY_BUF_SIZE-1); +		spin_lock_irqsave(&ldata->read_lock, flags); +		ldata->read_head = head; +		ldata->read_cnt -= cnt; +		spin_unlock_irqrestore(&ldata->read_lock, flags);  		if (L_ECHO(tty)) {  			if (L_ECHOPRT(tty)) { -				if (!tty->erasing) { -					echo_char_raw('\\', tty); -					tty->erasing = 1; +				if (!ldata->erasing) { +					echo_char_raw('\\', ldata); +					ldata->erasing = 1;  				}  				/* if cnt > 1, output a multi-byte character */  				echo_char(c, tty);  				while (--cnt > 0) {  					head = (head+1) & (N_TTY_BUF_SIZE-1); -					echo_char_raw(tty->read_buf[head], tty); -					echo_move_back_col(tty); +					echo_char_raw(ldata->read_buf[head], +							ldata); +					echo_move_back_col(ldata);  				}  			} else if (kill_type == ERASE && !L_ECHOE(tty)) {  				echo_char(ERASE_CHAR(tty), tty);  			} else if (c == '\t') {  				unsigned int num_chars = 0;  				int after_tab = 0; -				unsigned long tail = tty->read_head; +				unsigned long tail = ldata->read_head;  				/*  				 * Count the columns used for characters @@ -953,9 +993,9 @@ static void eraser(unsigned char c, struct tty_struct *tty)  				 * This info is used to go back the correct  				 * number of columns.  				 */ -				while (tail != tty->canon_head) { +				while (tail != ldata->canon_head) {  					tail = (tail-1) & (N_TTY_BUF_SIZE-1); -					c = tty->read_buf[tail]; +					c = ldata->read_buf[tail];  					if (c == '\t') {  						after_tab = 1;  						break; @@ -966,25 +1006,25 @@ static void eraser(unsigned char c, struct tty_struct *tty)  						num_chars++;  					}  				} -				echo_erase_tab(num_chars, after_tab, tty); +				echo_erase_tab(num_chars, after_tab, ldata);  			} else {  				if (iscntrl(c) && L_ECHOCTL(tty)) { -					echo_char_raw('\b', tty); -					echo_char_raw(' ', tty); -					echo_char_raw('\b', tty); +					echo_char_raw('\b', ldata); +					echo_char_raw(' ', ldata); +					echo_char_raw('\b', ldata);  				}  				if (!iscntrl(c) || L_ECHOCTL(tty)) { -					echo_char_raw('\b', tty); -					echo_char_raw(' ', tty); -					echo_char_raw('\b', tty); +					echo_char_raw('\b', ldata); +					echo_char_raw(' ', ldata); +					echo_char_raw('\b', ldata);  				}  			}  		}  		if (kill_type == ERASE)  			break;  	} -	if (tty->read_head == tty->canon_head && L_ECHO(tty)) -		finish_erasing(tty); +	if (ldata->read_head == ldata->canon_head && L_ECHO(tty)) +		finish_erasing(ldata);  }  /** @@ -1023,6 +1063,8 @@ static inline void isig(int sig, struct tty_struct *tty, int flush)  static inline void n_tty_receive_break(struct tty_struct *tty)  { +	struct n_tty_data *ldata = tty->disc_data; +  	if (I_IGNBRK(tty))  		return;  	if (I_BRKINT(tty)) { @@ -1030,10 +1072,10 @@ static inline void n_tty_receive_break(struct tty_struct *tty)  		return;  	}  	if (I_PARMRK(tty)) { -		put_tty_queue('\377', tty); -		put_tty_queue('\0', tty); +		put_tty_queue('\377', ldata); +		put_tty_queue('\0', ldata);  	} -	put_tty_queue('\0', tty); +	put_tty_queue('\0', ldata);  	wake_up_interruptible(&tty->read_wait);  } @@ -1052,16 +1094,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;  	}  } @@ -1076,16 +1119,18 @@ static inline void n_tty_receive_overrun(struct tty_struct *tty)  static inline void n_tty_receive_parity_error(struct tty_struct *tty,  					      unsigned char c)  { +	struct n_tty_data *ldata = tty->disc_data; +  	if (I_IGNPAR(tty))  		return;  	if (I_PARMRK(tty)) { -		put_tty_queue('\377', tty); -		put_tty_queue('\0', tty); -		put_tty_queue(c, tty); +		put_tty_queue('\377', ldata); +		put_tty_queue('\0', ldata); +		put_tty_queue(c, ldata);  	} else	if (I_INPCK(tty)) -		put_tty_queue('\0', tty); +		put_tty_queue('\0', ldata);  	else -		put_tty_queue(c, tty); +		put_tty_queue(c, ldata);  	wake_up_interruptible(&tty->read_wait);  } @@ -1101,11 +1146,12 @@ 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) { -		put_tty_queue(c, tty); +	if (ldata->raw) { +		put_tty_queue(c, ldata);  		return;  	} @@ -1115,7 +1161,7 @@ static inline void n_tty_receive_char(struct tty_struct *tty, unsigned char c)  		c = tolower(c);  	if (L_EXTPROC(tty)) { -		put_tty_queue(c, tty); +		put_tty_queue(c, ldata);  		return;  	} @@ -1143,26 +1189,26 @@ 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, ldata->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)) { +		if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {  			/* beep if no space */  			if (L_ECHO(tty))  				process_output('\a', tty);  			return;  		}  		if (L_ECHO(tty)) { -			finish_erasing(tty); +			finish_erasing(ldata);  			/* Record the column of first canon char. */ -			if (tty->canon_head == tty->read_head) -				echo_set_canon_col(tty); +			if (ldata->canon_head == ldata->read_head) +				echo_set_canon_col(ldata);  			echo_char(c, tty);  			process_echoes(tty);  		}  		if (parmrk) -			put_tty_queue(c, tty); -		put_tty_queue(c, tty); +			put_tty_queue(c, ldata); +		put_tty_queue(c, ldata);  		return;  	} @@ -1218,7 +1264,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); @@ -1226,12 +1272,12 @@ send_signal:  			return;  		}  		if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { -			tty->lnext = 1; +			ldata->lnext = 1;  			if (L_ECHO(tty)) { -				finish_erasing(tty); +				finish_erasing(ldata);  				if (L_ECHOCTL(tty)) { -					echo_char_raw('^', tty); -					echo_char_raw('\b', tty); +					echo_char_raw('^', ldata); +					echo_char_raw('\b', ldata);  					process_echoes(tty);  				}  			} @@ -1239,34 +1285,34 @@ send_signal:  		}  		if (c == REPRINT_CHAR(tty) && L_ECHO(tty) &&  		    L_IEXTEN(tty)) { -			unsigned long tail = tty->canon_head; +			unsigned long tail = ldata->canon_head; -			finish_erasing(tty); +			finish_erasing(ldata);  			echo_char(c, tty); -			echo_char_raw('\n', tty); -			while (tail != tty->read_head) { -				echo_char(tty->read_buf[tail], tty); +			echo_char_raw('\n', ldata); +			while (tail != ldata->read_head) { +				echo_char(ldata->read_buf[tail], tty);  				tail = (tail+1) & (N_TTY_BUF_SIZE-1);  			}  			process_echoes(tty);  			return;  		}  		if (c == '\n') { -			if (tty->read_cnt >= N_TTY_BUF_SIZE) { +			if (ldata->read_cnt >= N_TTY_BUF_SIZE) {  				if (L_ECHO(tty))  					process_output('\a', tty);  				return;  			}  			if (L_ECHO(tty) || L_ECHONL(tty)) { -				echo_char_raw('\n', tty); +				echo_char_raw('\n', ldata);  				process_echoes(tty);  			}  			goto handle_newline;  		}  		if (c == EOF_CHAR(tty)) { -			if (tty->read_cnt >= N_TTY_BUF_SIZE) +			if (ldata->read_cnt >= N_TTY_BUF_SIZE)  				return; -			if (tty->canon_head != tty->read_head) +			if (ldata->canon_head != ldata->read_head)  				set_bit(TTY_PUSH, &tty->flags);  			c = __DISABLED_CHAR;  			goto handle_newline; @@ -1275,7 +1321,7 @@ send_signal:  		    (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) {  			parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty))  				 ? 1 : 0; -			if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) { +			if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk)) {  				if (L_ECHO(tty))  					process_output('\a', tty);  				return; @@ -1285,8 +1331,8 @@ send_signal:  			 */  			if (L_ECHO(tty)) {  				/* Record the column of first canon char. */ -				if (tty->canon_head == tty->read_head) -					echo_set_canon_col(tty); +				if (ldata->canon_head == ldata->read_head) +					echo_set_canon_col(ldata);  				echo_char(c, tty);  				process_echoes(tty);  			} @@ -1295,15 +1341,15 @@ send_signal:  			 * EOL_CHAR and EOL2_CHAR?  			 */  			if (parmrk) -				put_tty_queue(c, tty); +				put_tty_queue(c, ldata);  handle_newline: -			spin_lock_irqsave(&tty->read_lock, flags); -			set_bit(tty->read_head, tty->read_flags); -			put_tty_queue_nolock(c, tty); -			tty->canon_head = tty->read_head; -			tty->canon_data++; -			spin_unlock_irqrestore(&tty->read_lock, flags); +			spin_lock_irqsave(&ldata->read_lock, flags); +			set_bit(ldata->read_head, ldata->read_flags); +			put_tty_queue_nolock(c, ldata); +			ldata->canon_head = ldata->read_head; +			ldata->canon_data++; +			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); @@ -1312,29 +1358,29 @@ handle_newline:  	}  	parmrk = (c == (unsigned char) '\377' && I_PARMRK(tty)) ? 1 : 0; -	if (tty->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) { +	if (ldata->read_cnt >= (N_TTY_BUF_SIZE - parmrk - 1)) {  		/* beep if no space */  		if (L_ECHO(tty))  			process_output('\a', tty);  		return;  	}  	if (L_ECHO(tty)) { -		finish_erasing(tty); +		finish_erasing(ldata);  		if (c == '\n') -			echo_char_raw('\n', tty); +			echo_char_raw('\n', ldata);  		else {  			/* Record the column of first canon char. */ -			if (tty->canon_head == tty->read_head) -				echo_set_canon_col(tty); +			if (ldata->canon_head == ldata->read_head) +				echo_set_canon_col(ldata);  			echo_char(c, tty);  		}  		process_echoes(tty);  	}  	if (parmrk) -		put_tty_queue(c, tty); +		put_tty_queue(c, ldata); -	put_tty_queue(c, tty); +	put_tty_queue(c, ldata);  } @@ -1369,33 +1415,31 @@ 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->read_buf) -		return; - -	if (tty->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); +	if (ldata->real_raw) { +		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); -		memcpy(tty->read_buf + tty->read_head, cp, i); -		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); -		tty->read_cnt += i; +		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;  		cp += i;  		count -= i; -		i = min(N_TTY_BUF_SIZE - tty->read_cnt, -			N_TTY_BUF_SIZE - tty->read_head); +		i = min(N_TTY_BUF_SIZE - ldata->read_cnt, +			N_TTY_BUF_SIZE - ldata->read_head);  		i = min(count, i); -		memcpy(tty->read_buf + tty->read_head, cp, i); -		tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1); -		tty->read_cnt += i; -		spin_unlock_irqrestore(&tty->read_lock, cpuflags); +		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(&ldata->read_lock, cpuflags);  	} else {  		for (i = count, p = cp, f = fp; i; i--, p++) {  			if (f) @@ -1426,7 +1470,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 && (ldata->read_cnt >= tty->minimum_to_wake)) ||  		L_EXTPROC(tty)) {  		kill_fasync(&tty->fasync, SIGIO, POLL_IN);  		if (waitqueue_active(&tty->read_wait)) @@ -1470,25 +1514,25 @@ 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; -	BUG_ON(!tty);  	if (old)  		canon_change = (old->c_lflag ^ tty->termios.c_lflag) & ICANON;  	if (canon_change) { -		memset(&tty->read_flags, 0, sizeof tty->read_flags); -		tty->canon_head = tty->read_tail; -		tty->canon_data = 0; -		tty->erasing = 0; +		bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); +		ldata->canon_head = ldata->read_tail; +		ldata->canon_data = 0; +		ldata->erasing = 0;  	} -	if (canon_change && !L_ICANON(tty) && tty->read_cnt) +	if (canon_change && !L_ICANON(tty) && ldata->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;  	} @@ -1496,51 +1540,51 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)  	    I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) ||  	    I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) ||  	    I_PARMRK(tty)) { -		memset(tty->process_char_map, 0, 256/8); +		bitmap_zero(ldata->process_char_map, 256);  		if (I_IGNCR(tty) || I_ICRNL(tty)) -			set_bit('\r', tty->process_char_map); +			set_bit('\r', ldata->process_char_map);  		if (I_INLCR(tty)) -			set_bit('\n', tty->process_char_map); +			set_bit('\n', ldata->process_char_map);  		if (L_ICANON(tty)) { -			set_bit(ERASE_CHAR(tty), tty->process_char_map); -			set_bit(KILL_CHAR(tty), tty->process_char_map); -			set_bit(EOF_CHAR(tty), tty->process_char_map); -			set_bit('\n', tty->process_char_map); -			set_bit(EOL_CHAR(tty), tty->process_char_map); +			set_bit(ERASE_CHAR(tty), ldata->process_char_map); +			set_bit(KILL_CHAR(tty), ldata->process_char_map); +			set_bit(EOF_CHAR(tty), ldata->process_char_map); +			set_bit('\n', ldata->process_char_map); +			set_bit(EOL_CHAR(tty), ldata->process_char_map);  			if (L_IEXTEN(tty)) {  				set_bit(WERASE_CHAR(tty), -					tty->process_char_map); +					ldata->process_char_map);  				set_bit(LNEXT_CHAR(tty), -					tty->process_char_map); +					ldata->process_char_map);  				set_bit(EOL2_CHAR(tty), -					tty->process_char_map); +					ldata->process_char_map);  				if (L_ECHO(tty))  					set_bit(REPRINT_CHAR(tty), -						tty->process_char_map); +						ldata->process_char_map);  			}  		}  		if (I_IXON(tty)) { -			set_bit(START_CHAR(tty), tty->process_char_map); -			set_bit(STOP_CHAR(tty), tty->process_char_map); +			set_bit(START_CHAR(tty), ldata->process_char_map); +			set_bit(STOP_CHAR(tty), ldata->process_char_map);  		}  		if (L_ISIG(tty)) { -			set_bit(INTR_CHAR(tty), tty->process_char_map); -			set_bit(QUIT_CHAR(tty), tty->process_char_map); -			set_bit(SUSP_CHAR(tty), tty->process_char_map); +			set_bit(INTR_CHAR(tty), ldata->process_char_map); +			set_bit(QUIT_CHAR(tty), ldata->process_char_map); +			set_bit(SUSP_CHAR(tty), ldata->process_char_map);  		} -		clear_bit(__DISABLED_CHAR, tty->process_char_map); -		tty->raw = 0; -		tty->real_raw = 0; +		clear_bit(__DISABLED_CHAR, ldata->process_char_map); +		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 */ @@ -1560,15 +1604,13 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)  static void n_tty_close(struct tty_struct *tty)  { +	struct n_tty_data *ldata = tty->disc_data; +  	n_tty_flush_buffer(tty); -	if (tty->read_buf) { -		kfree(tty->read_buf); -		tty->read_buf = NULL; -	} -	if (tty->echo_buf) { -		kfree(tty->echo_buf); -		tty->echo_buf = NULL; -	} +	kfree(ldata->read_buf); +	kfree(ldata->echo_buf); +	kfree(ldata); +	tty->disc_data = NULL;  }  /** @@ -1583,37 +1625,50 @@ static void n_tty_close(struct tty_struct *tty)  static int n_tty_open(struct tty_struct *tty)  { -	if (!tty) -		return -EINVAL; +	struct n_tty_data *ldata; + +	ldata = kzalloc(sizeof(*ldata), GFP_KERNEL); +	if (!ldata) +		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 */ -	if (!tty->read_buf) { -		tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); -		if (!tty->read_buf) -			return -ENOMEM; -	} -	if (!tty->echo_buf) { -		tty->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); +	ldata->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); +	ldata->echo_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL); +	if (!ldata->read_buf || !ldata->echo_buf) +		goto err_free_bufs; -		if (!tty->echo_buf) -			return -ENOMEM; -	} +	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; +  	return 0; +err_free_bufs: +	kfree(ldata->read_buf); +	kfree(ldata->echo_buf); +	kfree(ldata); +err: +	return -ENOMEM;  }  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 (tty->canon_data) +	if (ldata->icanon && !L_EXTPROC(tty)) { +		if (ldata->canon_data)  			return 1; -	} else if (tty->read_cnt >= (amt ? amt : 1)) +	} else if (ldata->read_cnt >= (amt ? amt : 1))  		return 1;  	return 0; @@ -1632,7 +1687,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   *   */ @@ -1641,29 +1696,31 @@ 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;  	bool is_eof;  	retval = 0; -	spin_lock_irqsave(&tty->read_lock, flags); -	n = min(tty->read_cnt, N_TTY_BUF_SIZE - tty->read_tail); +	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, &tty->read_buf[tty->read_tail], n); +		retval = copy_to_user(*b, &ldata->read_buf[ldata->read_tail], n);  		n -= retval;  		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); -		spin_lock_irqsave(&tty->read_lock, flags); -		tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); -		tty->read_cnt -= n; +			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(&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) && tty->icanon && is_eof && !tty->read_cnt) +		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;  	} @@ -1730,6 +1787,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; @@ -1741,17 +1799,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,  	int packet;  do_it_again: - -	if (WARN_ON(!tty->read_buf)) -		return -EAGAIN; -  	c = job_control(tty, file);  	if (c < 0)  		return c;  	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) { @@ -1774,10 +1828,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; @@ -1830,7 +1884,6 @@ do_it_again:  			/* FIXME: does n_tty_set_room need locking ? */  			n_tty_set_room(tty);  			timeout = schedule_timeout(timeout); -			BUG_ON(!tty->read_buf);  			continue;  		}  		__set_current_state(TASK_RUNNING); @@ -1845,45 +1898,45 @@ 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) { +			spin_lock_irqsave(&ldata->read_lock, flags); +			while (nr && ldata->read_cnt) {  				int eol; -				eol = test_and_clear_bit(tty->read_tail, -						tty->read_flags); -				c = tty->read_buf[tty->read_tail]; -				tty->read_tail = ((tty->read_tail+1) & +				eol = test_and_clear_bit(ldata->read_tail, +						ldata->read_flags); +				c = ldata->read_buf[ldata->read_tail]; +				ldata->read_tail = ((ldata->read_tail+1) &  						  (N_TTY_BUF_SIZE-1)); -				tty->read_cnt--; +				ldata->read_cnt--;  				if (eol) {  					/* this test should be redundant:  					 * we shouldn't be reading data if  					 * canon_data is 0  					 */ -					if (--tty->canon_data < 0) -						tty->canon_data = 0; +					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 { @@ -1915,7 +1968,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)) @@ -2076,19 +2129,19 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,  	return mask;  } -static unsigned long inq_canon(struct tty_struct *tty) +static unsigned long inq_canon(struct n_tty_data *ldata)  {  	int nr, head, tail; -	if (!tty->canon_data) +	if (!ldata->canon_data)  		return 0; -	head = tty->canon_head; -	tail = tty->read_tail; +	head = ldata->canon_head; +	tail = ldata->read_tail;  	nr = (head - tail) & (N_TTY_BUF_SIZE-1);  	/* Skip EOF-chars.. */  	while (head != tail) { -		if (test_bit(tail, tty->read_flags) && -		    tty->read_buf[tail] == __DISABLED_CHAR) +		if (test_bit(tail, ldata->read_flags) && +		    ldata->read_buf[tail] == __DISABLED_CHAR)  			nr--;  		tail = (tail+1) & (N_TTY_BUF_SIZE-1);  	} @@ -2098,6 +2151,7 @@ static unsigned long inq_canon(struct tty_struct *tty)  static int n_tty_ioctl(struct tty_struct *tty, struct file *file,  		       unsigned int cmd, unsigned long arg)  { +	struct n_tty_data *ldata = tty->disc_data;  	int retval;  	switch (cmd) { @@ -2105,9 +2159,9 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,  		return put_user(tty_chars_in_buffer(tty), (int __user *) arg);  	case TIOCINQ:  		/* FIXME: Locking */ -		retval = tty->read_cnt; +		retval = ldata->read_cnt;  		if (L_ICANON(tty)) -			retval = inq_canon(tty); +			retval = inq_canon(ldata);  		return put_user(retval, (unsigned int __user *) arg);  	default:  		return n_tty_ioctl_helper(tty, file, cmd, arg);  |