Flip changes done right

Pavel Machek (pavel@bug.ucw.cz)
Wed, 2 Jun 1999 14:13:19 +0200


Hi!

My previous patch was totally bogus. (I thought I tried it!!!) I spend
two hours fixing it. Ok, here it is, this time it should work. Please
apply,
Pavel

--- clean/include/linux/tty.h Fri May 14 20:42:58 1999
+++ linux/include/linux/tty.h Wed Jun 2 13:45:36 1999
@@ -125,13 +125,14 @@
*/
#define __DISABLED_CHAR '\0'

+/* HACK for old drivers, don't include this constant in new code */
+#define TTY_FLIPBUF_SIZE 512
+
/*
* This is the flip buffer used for the tty driver. The buffer is
- * located in the tty structure, and is used as a high speed interface
- * between the tty driver and the tty line discipline.
+ * kmalloced, and is used as a high speed interface between tty driver
+ * and the line discipline.
*/
-#define TTY_FLIPBUF_SIZE 512
-
struct tty_flip_buffer {
struct tq_struct tqueue;
struct semaphore pty_sem;
@@ -139,9 +140,9 @@
unsigned char *flag_buf_ptr;
int count;
int buf_num;
- unsigned char char_buf[2*TTY_FLIPBUF_SIZE];
- char flag_buf[2*TTY_FLIPBUF_SIZE];
- unsigned char slop[4]; /* N.B. bug overwrites buffer by 1 */
+ int flipbuf_size;
+ unsigned char *char_buf;
+ char *flag_buf;
};
/*
* The pty uses char_buf and flag_buf as a contiguous buffer
--- clean/include/linux/tty_flip.h Wed Sep 10 04:41:41 1997
+++ linux/include/linux/tty_flip.h Sun May 30 21:08:21 1999
@@ -10,7 +10,7 @@
_INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
unsigned char ch, char flag)
{
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ if (tty->flip.count < tty->flip.flipbuf_size) {
tty->flip.count++;
*tty->flip.flag_buf_ptr++ = flag;
*tty->flip.char_buf_ptr++ = ch;
--- clean/include/linux/tty_driver.h Sun Aug 16 22:34:51 1998
+++ linux/include/linux/tty_driver.h Wed Jun 2 13:24:01 1999
@@ -132,6 +132,7 @@
int *refcount; /* for loadable tty drivers */
struct proc_dir_entry *proc_entry; /* /proc fs entry */
struct tty_driver *other; /* only used for the PTY driver */
+ int flip_size; /* requested size of flip buffer */

/*
* Pointer to the tty data structures
@@ -197,10 +198,13 @@
* optimize for this case if this flag is set. (Note that there
* is also a promise, if the above case is true, not to signal
* overruns, either.)
+ *
+ * TTY_DRIVER_SPECIAL_FLIPSIZE --- we want non-512 bytes flip buffer
*/
#define TTY_DRIVER_INSTALLED 0x0001
#define TTY_DRIVER_RESET_TERMIOS 0x0002
#define TTY_DRIVER_REAL_RAW 0x0004
+#define TTY_DRIVER_SPECIAL_FLIPSIZE 0x0008

/* tty driver types */
#define TTY_DRIVER_TYPE_SYSTEM 0x0001
--- clean/drivers/char/tty_io.c Fri May 14 20:42:29 1999
+++ linux/drivers/char/tty_io.c Wed Jun 2 14:11:00 1999
@@ -54,6 +54,9 @@
*
* Added support for a Unix98-style ptmx device.
* -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
+ *
+ * Added support for bigger flipbuf sizes
+ * -- Pavel Machek <pavel@ucw.cz>, June 99
*/

#include <linux/config.h>
@@ -115,7 +118,7 @@
*/
struct tty_struct * redirect = NULL;

-static void initialize_tty_struct(struct tty_struct *tty);
+static int initialize_tty_struct(struct tty_struct *tty, int);

static ssize_t tty_read(struct file *, char *, size_t, loff_t *);
static ssize_t tty_write(struct file *, const char *, size_t, loff_t *);
@@ -786,10 +789,14 @@
tp = o_tp = NULL;
ltp = o_ltp = NULL;

- tty = (struct tty_struct*) get_free_page(GFP_KERNEL);
+ tty = (struct tty_struct*) kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
if(!tty)
goto fail_no_mem;
- initialize_tty_struct(tty);
+
+ if (initialize_tty_struct(tty, driver->flip_size)) {
+ kfree(tty);
+ goto fail_no_mem;
+ }
tty->device = device;
tty->driver = *driver;

@@ -812,10 +819,14 @@
}

if (driver->type == TTY_DRIVER_TYPE_PTY) {
- o_tty = (struct tty_struct *) get_free_page(GFP_KERNEL);
+ o_tty = (struct tty_struct *) kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
if (!o_tty)
goto free_mem_out;
- initialize_tty_struct(o_tty);
+ if (initialize_tty_struct(o_tty, 512)) {
+ kfree(o_tty);
+ o_tty = NULL;
+ goto free_mem_out;
+ }
o_tty->device = (kdev_t) MKDEV(driver->other->major,
driver->other->minor_start + idx);
o_tty->driver = *driver->other;
@@ -931,13 +942,16 @@
free_mem_out:
if (o_tp)
kfree_s(o_tp, sizeof(struct termios));
- if (o_tty)
- free_page((unsigned long) o_tty);
+ if (o_tty) {
+ kfree(o_tty->flip.char_buf);
+ kfree(o_tty);
+ }
if (ltp)
kfree_s(ltp, sizeof(struct termios));
if (tp)
kfree_s(tp, sizeof(struct termios));
- free_page((unsigned long) tty);
+ kfree(tty->flip.char_buf);
+ kfree(tty);

fail_no_mem:
retval = -ENOMEM;
@@ -968,7 +982,8 @@
}
o_tty->magic = 0;
(*o_tty->driver.refcount)--;
- free_page((unsigned long) o_tty);
+ kfree(o_tty->flip.char_buf);
+ kfree(o_tty);
}

tty->driver.table[idx] = NULL;
@@ -979,7 +994,8 @@
}
tty->magic = 0;
(*tty->driver.refcount)--;
- free_page((unsigned long) tty);
+ kfree(tty->flip.char_buf);
+ kfree(tty);
}

/*
@@ -1842,8 +1858,8 @@
return;
}
if (tty->flip.buf_num) {
- cp = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- fp = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+ cp = tty->flip.char_buf + tty->flip.flipbuf_size;
+ fp = tty->flip.flag_buf + tty->flip.flipbuf_size;
tty->flip.buf_num = 0;

save_flags(flags); cli();
@@ -1855,8 +1871,8 @@
tty->flip.buf_num = 1;

save_flags(flags); cli();
- tty->flip.char_buf_ptr = tty->flip.char_buf + TTY_FLIPBUF_SIZE;
- tty->flip.flag_buf_ptr = tty->flip.flag_buf + TTY_FLIPBUF_SIZE;
+ tty->flip.char_buf_ptr = tty->flip.char_buf + tty->flip.flipbuf_size;
+ tty->flip.flag_buf_ptr = tty->flip.flag_buf + tty->flip.flipbuf_size;
}
count = tty->flip.count;
tty->flip.count = 0;
@@ -1920,9 +1936,17 @@
/*
* This subroutine initializes a tty structure.
*/
-static void initialize_tty_struct(struct tty_struct *tty)
+static int initialize_tty_struct(struct tty_struct *tty, int flip_size)
{
memset(tty, 0, sizeof(struct tty_struct));
+
+ /* there was notice about buffer overrun in original code -- that's why I do +4 */
+ tty->flip.char_buf = kmalloc(flip_size*4 +4, GFP_KERNEL);
+ if (!tty->flip.char_buf)
+ return -ENOMEM;
+
+ tty->flip.flag_buf = tty->flip.char_buf + flip_size*2;
+ tty->flip.flipbuf_size = flip_size;
tty->magic = TTY_MAGIC;
tty->ldisc = ldiscs[N_TTY];
tty->pgrp = -1;
@@ -1936,6 +1960,7 @@
tty->tq_hangup.routine = do_tty_hangup;
tty->tq_hangup.data = tty;
sema_init(&tty->atomic_read, 1);
+ return 0;
}

/*
@@ -1956,14 +1981,19 @@
if (driver->flags & TTY_DRIVER_INSTALLED)
return 0;

+ if (!(driver->flags & TTY_DRIVER_SPECIAL_FLIPSIZE))
+ driver->flip_size = 512;
+
error = register_chrdev(driver->major, driver->name, &tty_fops);
- if (error < 0)
+ if (error < 0) {
return error;
+ }
else if(driver->major == 0)
driver->major = error;

if (!driver->put_char)
driver->put_char = tty_default_put_char;
+

driver->prev = 0;
driver->next = tty_drivers;
--- clean/drivers/char/pty.c Fri May 14 20:42:27 1999
+++ linux/drivers/char/pty.c Wed Jun 2 12:08:15 1999
@@ -150,7 +150,7 @@
n = MIN(count, to->ldisc.receive_room(to));
if (!n) break;

- n = MIN(n, PTY_BUF_SIZE);
+ n = MIN(n, tty->flip.flipbuf_size);
n -= copy_from_user(temp_buffer, buf, n);
if (!n) {
if (!c)
--- clean/drivers/char/serial.c Fri May 14 20:42:29 1999
+++ linux/drivers/char/serial.c Wed Jun 2 12:09:51 1999
@@ -385,7 +389,7 @@
icount = &info->state->icount;
do {
ch = serial_inp(info, UART_RX);
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+ if (tty->flip.count >= tty->flip.flipbuf_size)
break;
*tty->flip.char_buf_ptr = ch;
icount->rx++;
@@ -438,7 +442,7 @@
* reported immediately, and doesn't
* affect the current character
*/
- if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+ if (tty->flip.count < tty->flip.flipbuf_size) {
tty->flip.count++;
tty->flip.flag_buf_ptr++;
tty->flip.char_buf_ptr++;

-- 
I'm really pavel@ucw.cz. Look at http://195.113.31.123/~pavel.  Pavel
Hi! I'm a .signature virus! Copy me into your ~/.signature, please!

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/