Commit 8c9a9dd0 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

tty: remove resize window special case

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: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 21d3bdb1
...@@ -2496,45 +2496,25 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) ...@@ -2496,45 +2496,25 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg)
} }
/** /**
* tiocswinsz - implement window size set ioctl * tty_do_resize - resize event
* @tty; tty * @tty: tty being resized
* @arg: user buffer for result * @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 * Update the termios variables and send the neccessary signals to
* this is just advisory information but for the Linux console it * peform a terminal resize correctly
* 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
*/ */
static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize __user *arg) struct winsize *ws)
{ {
struct winsize tmp_ws;
struct pid *pgrp, *rpgrp; struct pid *pgrp, *rpgrp;
unsigned long flags; unsigned long flags;
if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
return -EFAULT;
mutex_lock(&tty->termios_mutex); mutex_lock(&tty->termios_mutex);
if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) if (!memcmp(ws, &tty->winsize, sizeof(*ws)))
goto done; 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 /* Get the PID values and reference them so we can
avoid holding the tty ctrl lock while sending signals */ avoid holding the tty ctrl lock while sending signals */
spin_lock_irqsave(&tty->ctrl_lock, flags); spin_lock_irqsave(&tty->ctrl_lock, flags);
...@@ -2550,13 +2530,41 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, ...@@ -2550,13 +2530,41 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
put_pid(pgrp); put_pid(pgrp);
put_pid(rpgrp); put_pid(rpgrp);
tty->winsize = tmp_ws; tty->winsize = *ws;
real_tty->winsize = tmp_ws; real_tty->winsize = *ws;
done: done:
mutex_unlock(&tty->termios_mutex); mutex_unlock(&tty->termios_mutex);
return 0; 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 * tioccons - allow admin to move logical console
* @file: the file to become console * @file: the file to become console
......
...@@ -803,7 +803,25 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, ...@@ -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_MAXCOL (32767)
#define VC_RESIZE_MAXROW (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 long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0;
unsigned int old_cols, old_rows, old_row_size, old_screen_size; 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) ...@@ -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); gotoxy(vc, vc->vc_x, vc->vc_y);
save_cur(vc); save_cur(vc);
if (vc->vc_tty) { if (tty) {
struct winsize ws, *cws = &vc->vc_tty->winsize; /* Rewrite the requested winsize data with the actual
struct pid *pgrp = NULL; resulting sizes */
struct winsize ws;
memset(&ws, 0, sizeof(ws)); memset(&ws, 0, sizeof(ws));
ws.ws_row = vc->vc_rows; ws.ws_row = vc->vc_rows;
ws.ws_col = vc->vc_cols; ws.ws_col = vc->vc_cols;
ws.ws_ypixel = vc->vc_scan_lines; ws.ws_ypixel = vc->vc_scan_lines;
tty_do_resize(tty, real_tty, &ws);
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;
} }
if (CON_IS_VISIBLE(vc)) if (CON_IS_VISIBLE(vc))
...@@ -932,14 +941,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) ...@@ -932,14 +941,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines)
return err; 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(); 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(); release_console_sem();
return rc; return ret;
} }
void vc_deallocate(unsigned int currcons) void vc_deallocate(unsigned int currcons)
...@@ -2907,6 +2949,7 @@ static const struct tty_operations con_ops = { ...@@ -2907,6 +2949,7 @@ static const struct tty_operations con_ops = {
.start = con_start, .start = con_start,
.throttle = con_throttle, .throttle = con_throttle,
.unthrottle = con_unthrottle, .unthrottle = con_unthrottle,
.resize = vt_resize,
}; };
int __init vty_init(void) int __init vty_init(void)
...@@ -4061,7 +4104,6 @@ EXPORT_SYMBOL(default_blu); ...@@ -4061,7 +4104,6 @@ EXPORT_SYMBOL(default_blu);
EXPORT_SYMBOL(update_region); EXPORT_SYMBOL(update_region);
EXPORT_SYMBOL(redraw_screen); EXPORT_SYMBOL(redraw_screen);
EXPORT_SYMBOL(vc_resize); EXPORT_SYMBOL(vc_resize);
EXPORT_SYMBOL(vc_lock_resize);
EXPORT_SYMBOL(fg_console); EXPORT_SYMBOL(fg_console);
EXPORT_SYMBOL(console_blank_hook); EXPORT_SYMBOL(console_blank_hook);
EXPORT_SYMBOL(console_blanked); EXPORT_SYMBOL(console_blanked);
......
...@@ -947,14 +947,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, ...@@ -947,14 +947,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
get_user(cc, &vtsizes->v_cols)) get_user(cc, &vtsizes->v_cols))
ret = -EFAULT; ret = -EFAULT;
else { else {
acquire_console_sem();
for (i = 0; i < MAX_NR_CONSOLES; i++) { for (i = 0; i < MAX_NR_CONSOLES; i++) {
vc = vc_cons[i].d; vc = vc_cons[i].d;
if (vc) { if (vc) {
vc->vc_resize_user = 1; 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; break;
} }
......
...@@ -331,6 +331,8 @@ extern int tty_write_room(struct tty_struct *tty); ...@@ -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_driver_flush_buffer(struct tty_struct *tty);
extern void tty_throttle(struct tty_struct *tty); extern void tty_throttle(struct tty_struct *tty);
extern void tty_unthrottle(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 int is_current_pgrp_orphaned(void);
extern struct pid *tty_get_pgrp(struct tty_struct *tty); extern struct pid *tty_get_pgrp(struct tty_struct *tty);
......
...@@ -168,6 +168,18 @@ ...@@ -168,6 +168,18 @@
* *
* Optional: If not provided then the write method is called under * Optional: If not provided then the write method is called under
* the atomic write lock to keep it serialized with the ldisc. * 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> #include <linux/fs.h>
...@@ -206,6 +218,8 @@ struct tty_operations { ...@@ -206,6 +218,8 @@ struct tty_operations {
int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmget)(struct tty_struct *tty, struct file *file);
int (*tiocmset)(struct tty_struct *tty, struct file *file, int (*tiocmset)(struct tty_struct *tty, struct file *file,
unsigned int set, unsigned int clear); unsigned int set, unsigned int clear);
int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty,
struct winsize *ws);
#ifdef CONFIG_CONSOLE_POLL #ifdef CONFIG_CONSOLE_POLL
int (*poll_init)(struct tty_driver *driver, int line, char *options); int (*poll_init)(struct tty_driver *driver, int line, char *options);
int (*poll_get_char)(struct tty_driver *driver, int line); int (*poll_get_char)(struct tty_driver *driver, int line);
......
...@@ -35,7 +35,6 @@ extern int fg_console, last_console, want_console; ...@@ -35,7 +35,6 @@ extern int fg_console, last_console, want_console;
int vc_allocate(unsigned int console); int vc_allocate(unsigned int console);
int vc_cons_allocated(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_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 vc_deallocate(unsigned int console);
void reset_palette(struct vc_data *vc); void reset_palette(struct vc_data *vc);
void do_blank_screen(int entering_gfx); void do_blank_screen(int entering_gfx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment