tty: remove resize window special case
authorAlan Cox <alan@redhat.com>
Fri, 15 Aug 2008 09:39:38 +0000 (10:39 +0100)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 15 Aug 2008 17:34:07 +0000 (10:34 -0700)
This moves it to being a tty operation. That removes special cases and now
also means that resize can be picked up by um and other non vt consoles
which may have a resize operation.

Signed-off-by: Alan Cox <alan@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/char/tty_io.c
drivers/char/vt.c
drivers/char/vt_ioctl.c
include/linux/tty.h
include/linux/tty_driver.h
include/linux/vt_kern.h

index 0e6866f..a27160b 100644 (file)
@@ -2496,45 +2496,25 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
 }
 
 /**
- *     tiocswinsz              -       implement window size set ioctl
- *     @tty; tty
- *     @arg: user buffer for result
+ *     tty_do_resize           -       resize event
+ *     @tty: tty being resized
+ *     @real_tty: real tty (if using a pty/tty pair)
+ *     @rows: rows (character)
+ *     @cols: cols (character)
  *
- *     Copies the user idea of the window size to the kernel. Traditionally
- *     this is just advisory information but for the Linux console it
- *     actually has driver level meaning and triggers a VC resize.
- *
- *     Locking:
- *             Called function use the console_sem is used to ensure we do
- *     not try and resize the console twice at once.
- *             The tty->termios_mutex is used to ensure we don't double
- *     resize and get confused. Lock order - tty->termios_mutex before
- *     console sem
+ *     Update the termios variables and send the neccessary signals to
+ *     peform a terminal resize correctly
  */
 
-static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
-       struct winsize __user *arg)
+int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
+                                       struct winsize *ws)
 {
-       struct winsize tmp_ws;
        struct pid *pgrp, *rpgrp;
        unsigned long flags;
 
-       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
-               return -EFAULT;
-
        mutex_lock(&tty->termios_mutex);
-       if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
+       if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
                goto done;
-
-#ifdef CONFIG_VT
-       if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
-               if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col,
-                                       tmp_ws.ws_row)) {
-                       mutex_unlock(&tty->termios_mutex);
-                       return -ENXIO;
-               }
-       }
-#endif
        /* Get the PID values and reference them so we can
           avoid holding the tty ctrl lock while sending signals */
        spin_lock_irqsave(&tty->ctrl_lock, flags);
@@ -2550,13 +2530,41 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
        put_pid(pgrp);
        put_pid(rpgrp);
 
-       tty->winsize = tmp_ws;
-       real_tty->winsize = tmp_ws;
+       tty->winsize = *ws;
+       real_tty->winsize = *ws;
 done:
        mutex_unlock(&tty->termios_mutex);
        return 0;
 }
 
+/**
+ *     tiocswinsz              -       implement window size set ioctl
+ *     @tty; tty
+ *     @arg: user buffer for result
+ *
+ *     Copies the user idea of the window size to the kernel. Traditionally
+ *     this is just advisory information but for the Linux console it
+ *     actually has driver level meaning and triggers a VC resize.
+ *
+ *     Locking:
+ *             Driver dependant. The default do_resize method takes the
+ *     tty termios mutex and ctrl_lock. The console takes its own lock
+ *     then calls into the default method.
+ */
+
+static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
+       struct winsize __user *arg)
+{
+       struct winsize tmp_ws;
+       if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
+               return -EFAULT;
+
+       if (tty->ops->resize)
+               return tty->ops->resize(tty, real_tty, &tmp_ws);
+       else
+               return tty_do_resize(tty, real_tty, &tmp_ws);
+}
+
 /**
  *     tioccons        -       allow admin to move logical console
  *     @file: the file to become console
index 1bc00c9..60359c3 100644 (file)
@@ -803,7 +803,25 @@ static inline int resize_screen(struct vc_data *vc, int width, int height,
  */
 #define VC_RESIZE_MAXCOL (32767)
 #define VC_RESIZE_MAXROW (32767)
-int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
+
+/**
+ *     vc_do_resize    -       resizing method for the tty
+ *     @tty: tty being resized
+ *     @real_tty: real tty (different to tty if a pty/tty pair)
+ *     @vc: virtual console private data
+ *     @cols: columns
+ *     @lines: lines
+ *
+ *     Resize a virtual console, clipping according to the actual constraints.
+ *     If the caller passes a tty structure then update the termios winsize
+ *     information and perform any neccessary signal handling.
+ *
+ *     Caller must hold the console semaphore. Takes the termios mutex and
+ *     ctrl_lock of the tty IFF a tty is passed.
+ */
+
+static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
+               struct vc_data *vc, unsigned int cols, unsigned int lines)
 {
        unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
        unsigned int old_cols, old_rows, old_row_size, old_screen_size;
@@ -907,24 +925,15 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
        gotoxy(vc, vc->vc_x, vc->vc_y);
        save_cur(vc);
 
-       if (vc->vc_tty) {
-               struct winsize ws, *cws = &vc->vc_tty->winsize;
-               struct pid *pgrp = NULL;
-
+       if (tty) {
+               /* Rewrite the requested winsize data with the actual
+                  resulting sizes */
+               struct winsize ws;
                memset(&ws, 0, sizeof(ws));
                ws.ws_row = vc->vc_rows;
                ws.ws_col = vc->vc_cols;
                ws.ws_ypixel = vc->vc_scan_lines;
-
-               spin_lock_irq(&vc->vc_tty->ctrl_lock);
-               if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col))
-                       pgrp = get_pid(vc->vc_tty->pgrp);
-               spin_unlock_irq(&vc->vc_tty->ctrl_lock);
-               if (pgrp) {
-                       kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1);
-                       put_pid(pgrp);
-               }
-               *cws = ws;
+               tty_do_resize(tty, real_tty, &ws);
        }
 
        if (CON_IS_VISIBLE(vc))
@@ -932,14 +941,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
        return err;
 }
 
-int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
+/**
+ *     vc_resize               -       resize a VT
+ *     @vc: virtual console
+ *     @cols: columns
+ *     @rows: rows
+ *
+ *     Resize a virtual console as seen from the console end of things. We
+ *     use the common vc_do_resize methods to update the structures. The
+ *     caller must hold the console sem to protect console internals and
+ *     vc->vc_tty
+ */
+
+int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows)
+{
+       return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows);
+}
+
+/**
+ *     vt_resize               -       resize a VT
+ *     @tty: tty to resize
+ *     @real_tty: tty if a pty/tty pair
+ *     @ws: winsize attributes
+ *
+ *     Resize a virtual terminal. This is called by the tty layer as we
+ *     register our own handler for resizing. The mutual helper does all
+ *     the actual work.
+ *
+ *     Takes the console sem and the called methods then take the tty
+ *     termios_mutex and the tty ctrl_lock in that order.
+ */
+
+int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty,
+       struct winsize *ws)
 {
-       int rc;
+       struct vc_data *vc = tty->driver_data;
+       int ret;
 
        acquire_console_sem();
-       rc = vc_resize(vc, cols, lines);
+       ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row);
        release_console_sem();
-       return rc;
+       return ret;
 }
 
 void vc_deallocate(unsigned int currcons)
@@ -2907,6 +2949,7 @@ static const struct tty_operations con_ops = {
        .start = con_start,
        .throttle = con_throttle,
        .unthrottle = con_unthrottle,
+       .resize = vt_resize,
 };
 
 int __init vty_init(void)
@@ -4061,7 +4104,6 @@ EXPORT_SYMBOL(default_blu);
 EXPORT_SYMBOL(update_region);
 EXPORT_SYMBOL(redraw_screen);
 EXPORT_SYMBOL(vc_resize);
-EXPORT_SYMBOL(vc_lock_resize);
 EXPORT_SYMBOL(fg_console);
 EXPORT_SYMBOL(console_blank_hook);
 EXPORT_SYMBOL(console_blanked);
index 3211afd..c904e9a 100644 (file)
@@ -947,14 +947,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
                    get_user(cc, &vtsizes->v_cols))
                        ret = -EFAULT;
                else {
+                       acquire_console_sem();
                        for (i = 0; i < MAX_NR_CONSOLES; i++) {
                                vc = vc_cons[i].d;
 
                                if (vc) {
                                        vc->vc_resize_user = 1;
-                                       vc_lock_resize(vc_cons[i].d, cc, ll);
+                                       vc_resize(vc_cons[i].d, cc, ll);
                                }
                        }
+                       release_console_sem();
                }
                break;
        }
index e3579cb..0cbec74 100644 (file)
@@ -331,6 +331,8 @@ extern int tty_write_room(struct tty_struct *tty);
 extern void tty_driver_flush_buffer(struct tty_struct *tty);
 extern void tty_throttle(struct tty_struct *tty);
 extern void tty_unthrottle(struct tty_struct *tty);
+extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
+                                               struct winsize *ws);
 
 extern int is_current_pgrp_orphaned(void);
 extern struct pid *tty_get_pgrp(struct tty_struct *tty);
index e1065ac..16d2794 100644 (file)
  *
  *     Optional: If not provided then the write method is called under
  *     the atomic write lock to keep it serialized with the ldisc.
+ *
+ * int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
+ *                             unsigned int rows, unsigned int cols);
+ *
+ *     Called when a termios request is issued which changes the
+ *     requested terminal geometry.
+ *
+ *     Optional: the default action is to update the termios structure
+ *     without error. This is usually the correct behaviour. Drivers should
+ *     not force errors here if they are not resizable objects (eg a serial
+ *     line). See tty_do_resize() if you need to wrap the standard method
+ *     in your own logic - the usual case.
  */
 
 #include <linux/fs.h>
@@ -206,6 +218,8 @@ struct tty_operations {
        int (*tiocmget)(struct tty_struct *tty, struct file *file);
        int (*tiocmset)(struct tty_struct *tty, struct file *file,
                        unsigned int set, unsigned int clear);
+       int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
+                               struct winsize *ws);
 #ifdef CONFIG_CONSOLE_POLL
        int (*poll_init)(struct tty_driver *driver, int line, char *options);
        int (*poll_get_char)(struct tty_driver *driver, int line);
index 1c78d56..1cbd0a7 100644 (file)
@@ -35,7 +35,6 @@ extern int fg_console, last_console, want_console;
 int vc_allocate(unsigned int console);
 int vc_cons_allocated(unsigned int console);
 int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
-int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines);
 void vc_deallocate(unsigned int console);
 void reset_palette(struct vc_data *vc);
 void do_blank_screen(int entering_gfx);