diff options
| -rw-r--r-- | drivers/char/tty_io.c | 72 | ||||
| -rw-r--r-- | drivers/char/vt.c | 82 | ||||
| -rw-r--r-- | drivers/char/vt_ioctl.c | 4 | ||||
| -rw-r--r-- | include/linux/tty.h | 2 | ||||
| -rw-r--r-- | include/linux/tty_driver.h | 14 | ||||
| -rw-r--r-- | include/linux/vt_kern.h | 1 |
6 files changed, 121 insertions, 54 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index 0e6866fe0f96..a27160ba21d7 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
| @@ -2496,45 +2496,25 @@ static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) | |||
| 2496 | } | 2496 | } |
| 2497 | 2497 | ||
| 2498 | /** | 2498 | /** |
| 2499 | * tiocswinsz - implement window size set ioctl | 2499 | * tty_do_resize - resize event |
| 2500 | * @tty; tty | 2500 | * @tty: tty being resized |
| 2501 | * @arg: user buffer for result | 2501 | * @real_tty: real tty (if using a pty/tty pair) |
| 2502 | * @rows: rows (character) | ||
| 2503 | * @cols: cols (character) | ||
| 2502 | * | 2504 | * |
| 2503 | * Copies the user idea of the window size to the kernel. Traditionally | 2505 | * Update the termios variables and send the neccessary signals to |
| 2504 | * this is just advisory information but for the Linux console it | 2506 | * peform a terminal resize correctly |
| 2505 | * actually has driver level meaning and triggers a VC resize. | ||
| 2506 | * | ||
| 2507 | * Locking: | ||
| 2508 | * Called function use the console_sem is used to ensure we do | ||
| 2509 | * not try and resize the console twice at once. | ||
| 2510 | * The tty->termios_mutex is used to ensure we don't double | ||
| 2511 | * resize and get confused. Lock order - tty->termios_mutex before | ||
| 2512 | * console sem | ||
| 2513 | */ | 2507 | */ |
| 2514 | 2508 | ||
| 2515 | static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, | 2509 | int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, |
| 2516 | struct winsize __user *arg) | 2510 | struct winsize *ws) |
| 2517 | { | 2511 | { |
| 2518 | struct winsize tmp_ws; | ||
| 2519 | struct pid *pgrp, *rpgrp; | 2512 | struct pid *pgrp, *rpgrp; |
| 2520 | unsigned long flags; | 2513 | unsigned long flags; |
| 2521 | 2514 | ||
| 2522 | if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) | ||
| 2523 | return -EFAULT; | ||
| 2524 | |||
| 2525 | mutex_lock(&tty->termios_mutex); | 2515 | mutex_lock(&tty->termios_mutex); |
| 2526 | if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg))) | 2516 | if (!memcmp(ws, &tty->winsize, sizeof(*ws))) |
| 2527 | goto done; | 2517 | goto done; |
| 2528 | |||
| 2529 | #ifdef CONFIG_VT | ||
| 2530 | if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) { | ||
| 2531 | if (vc_lock_resize(tty->driver_data, tmp_ws.ws_col, | ||
| 2532 | tmp_ws.ws_row)) { | ||
| 2533 | mutex_unlock(&tty->termios_mutex); | ||
| 2534 | return -ENXIO; | ||
| 2535 | } | ||
| 2536 | } | ||
| 2537 | #endif | ||
| 2538 | /* Get the PID values and reference them so we can | 2518 | /* Get the PID values and reference them so we can |
| 2539 | avoid holding the tty ctrl lock while sending signals */ | 2519 | avoid holding the tty ctrl lock while sending signals */ |
| 2540 | spin_lock_irqsave(&tty->ctrl_lock, flags); | 2520 | spin_lock_irqsave(&tty->ctrl_lock, flags); |
| @@ -2550,14 +2530,42 @@ static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, | |||
| 2550 | put_pid(pgrp); | 2530 | put_pid(pgrp); |
| 2551 | put_pid(rpgrp); | 2531 | put_pid(rpgrp); |
| 2552 | 2532 | ||
| 2553 | tty->winsize = tmp_ws; | 2533 | tty->winsize = *ws; |
| 2554 | real_tty->winsize = tmp_ws; | 2534 | real_tty->winsize = *ws; |
| 2555 | done: | 2535 | done: |
| 2556 | mutex_unlock(&tty->termios_mutex); | 2536 | mutex_unlock(&tty->termios_mutex); |
| 2557 | return 0; | 2537 | return 0; |
| 2558 | } | 2538 | } |
| 2559 | 2539 | ||
| 2560 | /** | 2540 | /** |
| 2541 | * tiocswinsz - implement window size set ioctl | ||
| 2542 | * @tty; tty | ||
| 2543 | * @arg: user buffer for result | ||
| 2544 | * | ||
| 2545 | * Copies the user idea of the window size to the kernel. Traditionally | ||
| 2546 | * this is just advisory information but for the Linux console it | ||
| 2547 | * actually has driver level meaning and triggers a VC resize. | ||
| 2548 | * | ||
| 2549 | * Locking: | ||
| 2550 | * Driver dependant. The default do_resize method takes the | ||
| 2551 | * tty termios mutex and ctrl_lock. The console takes its own lock | ||
| 2552 | * then calls into the default method. | ||
| 2553 | */ | ||
| 2554 | |||
| 2555 | static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty, | ||
| 2556 | struct winsize __user *arg) | ||
| 2557 | { | ||
| 2558 | struct winsize tmp_ws; | ||
| 2559 | if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) | ||
| 2560 | return -EFAULT; | ||
| 2561 | |||
| 2562 | if (tty->ops->resize) | ||
| 2563 | return tty->ops->resize(tty, real_tty, &tmp_ws); | ||
| 2564 | else | ||
| 2565 | return tty_do_resize(tty, real_tty, &tmp_ws); | ||
| 2566 | } | ||
| 2567 | |||
| 2568 | /** | ||
| 2561 | * tioccons - allow admin to move logical console | 2569 | * tioccons - allow admin to move logical console |
| 2562 | * @file: the file to become console | 2570 | * @file: the file to become console |
| 2563 | * | 2571 | * |
diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 1bc00c9d860d..60359c360912 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c | |||
| @@ -803,7 +803,25 @@ static inline int resize_screen(struct vc_data *vc, int width, int height, | |||
| 803 | */ | 803 | */ |
| 804 | #define VC_RESIZE_MAXCOL (32767) | 804 | #define VC_RESIZE_MAXCOL (32767) |
| 805 | #define VC_RESIZE_MAXROW (32767) | 805 | #define VC_RESIZE_MAXROW (32767) |
| 806 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | 806 | |
| 807 | /** | ||
| 808 | * vc_do_resize - resizing method for the tty | ||
| 809 | * @tty: tty being resized | ||
| 810 | * @real_tty: real tty (different to tty if a pty/tty pair) | ||
| 811 | * @vc: virtual console private data | ||
| 812 | * @cols: columns | ||
| 813 | * @lines: lines | ||
| 814 | * | ||
| 815 | * Resize a virtual console, clipping according to the actual constraints. | ||
| 816 | * If the caller passes a tty structure then update the termios winsize | ||
| 817 | * information and perform any neccessary signal handling. | ||
| 818 | * | ||
| 819 | * Caller must hold the console semaphore. Takes the termios mutex and | ||
| 820 | * ctrl_lock of the tty IFF a tty is passed. | ||
| 821 | */ | ||
| 822 | |||
| 823 | static int vc_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, | ||
| 824 | struct vc_data *vc, unsigned int cols, unsigned int lines) | ||
| 807 | { | 825 | { |
| 808 | unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; | 826 | unsigned long old_origin, new_origin, new_scr_end, rlth, rrem, err = 0; |
| 809 | unsigned int old_cols, old_rows, old_row_size, old_screen_size; | 827 | 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 | gotoxy(vc, vc->vc_x, vc->vc_y); | 925 | gotoxy(vc, vc->vc_x, vc->vc_y); |
| 908 | save_cur(vc); | 926 | save_cur(vc); |
| 909 | 927 | ||
| 910 | if (vc->vc_tty) { | 928 | if (tty) { |
| 911 | struct winsize ws, *cws = &vc->vc_tty->winsize; | 929 | /* Rewrite the requested winsize data with the actual |
| 912 | struct pid *pgrp = NULL; | 930 | resulting sizes */ |
| 913 | 931 | struct winsize ws; | |
| 914 | memset(&ws, 0, sizeof(ws)); | 932 | memset(&ws, 0, sizeof(ws)); |
| 915 | ws.ws_row = vc->vc_rows; | 933 | ws.ws_row = vc->vc_rows; |
| 916 | ws.ws_col = vc->vc_cols; | 934 | ws.ws_col = vc->vc_cols; |
| 917 | ws.ws_ypixel = vc->vc_scan_lines; | 935 | ws.ws_ypixel = vc->vc_scan_lines; |
| 918 | 936 | tty_do_resize(tty, real_tty, &ws); | |
| 919 | spin_lock_irq(&vc->vc_tty->ctrl_lock); | ||
| 920 | if ((ws.ws_row != cws->ws_row || ws.ws_col != cws->ws_col)) | ||
| 921 | pgrp = get_pid(vc->vc_tty->pgrp); | ||
| 922 | spin_unlock_irq(&vc->vc_tty->ctrl_lock); | ||
| 923 | if (pgrp) { | ||
| 924 | kill_pgrp(vc->vc_tty->pgrp, SIGWINCH, 1); | ||
| 925 | put_pid(pgrp); | ||
| 926 | } | ||
| 927 | *cws = ws; | ||
| 928 | } | 937 | } |
| 929 | 938 | ||
| 930 | if (CON_IS_VISIBLE(vc)) | 939 | if (CON_IS_VISIBLE(vc)) |
| @@ -932,14 +941,47 @@ int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | |||
| 932 | return err; | 941 | return err; |
| 933 | } | 942 | } |
| 934 | 943 | ||
| 935 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines) | 944 | /** |
| 945 | * vc_resize - resize a VT | ||
| 946 | * @vc: virtual console | ||
| 947 | * @cols: columns | ||
| 948 | * @rows: rows | ||
| 949 | * | ||
| 950 | * Resize a virtual console as seen from the console end of things. We | ||
| 951 | * use the common vc_do_resize methods to update the structures. The | ||
| 952 | * caller must hold the console sem to protect console internals and | ||
| 953 | * vc->vc_tty | ||
| 954 | */ | ||
| 955 | |||
| 956 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int rows) | ||
| 957 | { | ||
| 958 | return vc_do_resize(vc->vc_tty, vc->vc_tty, vc, cols, rows); | ||
| 959 | } | ||
| 960 | |||
| 961 | /** | ||
| 962 | * vt_resize - resize a VT | ||
| 963 | * @tty: tty to resize | ||
| 964 | * @real_tty: tty if a pty/tty pair | ||
| 965 | * @ws: winsize attributes | ||
| 966 | * | ||
| 967 | * Resize a virtual terminal. This is called by the tty layer as we | ||
| 968 | * register our own handler for resizing. The mutual helper does all | ||
| 969 | * the actual work. | ||
| 970 | * | ||
| 971 | * Takes the console sem and the called methods then take the tty | ||
| 972 | * termios_mutex and the tty ctrl_lock in that order. | ||
| 973 | */ | ||
| 974 | |||
| 975 | int vt_resize(struct tty_struct *tty, struct tty_struct *real_tty, | ||
| 976 | struct winsize *ws) | ||
| 936 | { | 977 | { |
| 937 | int rc; | 978 | struct vc_data *vc = tty->driver_data; |
| 979 | int ret; | ||
| 938 | 980 | ||
| 939 | acquire_console_sem(); | 981 | acquire_console_sem(); |
| 940 | rc = vc_resize(vc, cols, lines); | 982 | ret = vc_do_resize(tty, real_tty, vc, ws->ws_col, ws->ws_row); |
| 941 | release_console_sem(); | 983 | release_console_sem(); |
| 942 | return rc; | 984 | return ret; |
| 943 | } | 985 | } |
| 944 | 986 | ||
| 945 | void vc_deallocate(unsigned int currcons) | 987 | void vc_deallocate(unsigned int currcons) |
| @@ -2907,6 +2949,7 @@ static const struct tty_operations con_ops = { | |||
| 2907 | .start = con_start, | 2949 | .start = con_start, |
| 2908 | .throttle = con_throttle, | 2950 | .throttle = con_throttle, |
| 2909 | .unthrottle = con_unthrottle, | 2951 | .unthrottle = con_unthrottle, |
| 2952 | .resize = vt_resize, | ||
| 2910 | }; | 2953 | }; |
| 2911 | 2954 | ||
| 2912 | int __init vty_init(void) | 2955 | int __init vty_init(void) |
| @@ -4061,7 +4104,6 @@ EXPORT_SYMBOL(default_blu); | |||
| 4061 | EXPORT_SYMBOL(update_region); | 4104 | EXPORT_SYMBOL(update_region); |
| 4062 | EXPORT_SYMBOL(redraw_screen); | 4105 | EXPORT_SYMBOL(redraw_screen); |
| 4063 | EXPORT_SYMBOL(vc_resize); | 4106 | EXPORT_SYMBOL(vc_resize); |
| 4064 | EXPORT_SYMBOL(vc_lock_resize); | ||
| 4065 | EXPORT_SYMBOL(fg_console); | 4107 | EXPORT_SYMBOL(fg_console); |
| 4066 | EXPORT_SYMBOL(console_blank_hook); | 4108 | EXPORT_SYMBOL(console_blank_hook); |
| 4067 | EXPORT_SYMBOL(console_blanked); | 4109 | EXPORT_SYMBOL(console_blanked); |
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c index 3211afd9d57e..c904e9ad4a71 100644 --- a/drivers/char/vt_ioctl.c +++ b/drivers/char/vt_ioctl.c | |||
| @@ -947,14 +947,16 @@ int vt_ioctl(struct tty_struct *tty, struct file * file, | |||
| 947 | get_user(cc, &vtsizes->v_cols)) | 947 | get_user(cc, &vtsizes->v_cols)) |
| 948 | ret = -EFAULT; | 948 | ret = -EFAULT; |
| 949 | else { | 949 | else { |
| 950 | acquire_console_sem(); | ||
| 950 | for (i = 0; i < MAX_NR_CONSOLES; i++) { | 951 | for (i = 0; i < MAX_NR_CONSOLES; i++) { |
| 951 | vc = vc_cons[i].d; | 952 | vc = vc_cons[i].d; |
| 952 | 953 | ||
| 953 | if (vc) { | 954 | if (vc) { |
| 954 | vc->vc_resize_user = 1; | 955 | vc->vc_resize_user = 1; |
| 955 | vc_lock_resize(vc_cons[i].d, cc, ll); | 956 | vc_resize(vc_cons[i].d, cc, ll); |
| 956 | } | 957 | } |
| 957 | } | 958 | } |
| 959 | release_console_sem(); | ||
| 958 | } | 960 | } |
| 959 | break; | 961 | break; |
| 960 | } | 962 | } |
diff --git a/include/linux/tty.h b/include/linux/tty.h index e3579cb086e0..0cbec74ec086 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
| @@ -331,6 +331,8 @@ extern int tty_write_room(struct tty_struct *tty); | |||
| 331 | extern void tty_driver_flush_buffer(struct tty_struct *tty); | 331 | extern void tty_driver_flush_buffer(struct tty_struct *tty); |
| 332 | extern void tty_throttle(struct tty_struct *tty); | 332 | extern void tty_throttle(struct tty_struct *tty); |
| 333 | extern void tty_unthrottle(struct tty_struct *tty); | 333 | extern void tty_unthrottle(struct tty_struct *tty); |
| 334 | extern int tty_do_resize(struct tty_struct *tty, struct tty_struct *real_tty, | ||
| 335 | struct winsize *ws); | ||
| 334 | 336 | ||
| 335 | extern int is_current_pgrp_orphaned(void); | 337 | extern int is_current_pgrp_orphaned(void); |
| 336 | extern struct pid *tty_get_pgrp(struct tty_struct *tty); | 338 | extern struct pid *tty_get_pgrp(struct tty_struct *tty); |
diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index e1065ac0d922..16d27944c321 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h | |||
| @@ -168,6 +168,18 @@ | |||
| 168 | * | 168 | * |
| 169 | * Optional: If not provided then the write method is called under | 169 | * Optional: If not provided then the write method is called under |
| 170 | * the atomic write lock to keep it serialized with the ldisc. | 170 | * the atomic write lock to keep it serialized with the ldisc. |
| 171 | * | ||
| 172 | * int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, | ||
| 173 | * unsigned int rows, unsigned int cols); | ||
| 174 | * | ||
| 175 | * Called when a termios request is issued which changes the | ||
| 176 | * requested terminal geometry. | ||
| 177 | * | ||
| 178 | * Optional: the default action is to update the termios structure | ||
| 179 | * without error. This is usually the correct behaviour. Drivers should | ||
| 180 | * not force errors here if they are not resizable objects (eg a serial | ||
| 181 | * line). See tty_do_resize() if you need to wrap the standard method | ||
| 182 | * in your own logic - the usual case. | ||
| 171 | */ | 183 | */ |
| 172 | 184 | ||
| 173 | #include <linux/fs.h> | 185 | #include <linux/fs.h> |
| @@ -206,6 +218,8 @@ struct tty_operations { | |||
| 206 | int (*tiocmget)(struct tty_struct *tty, struct file *file); | 218 | int (*tiocmget)(struct tty_struct *tty, struct file *file); |
| 207 | int (*tiocmset)(struct tty_struct *tty, struct file *file, | 219 | int (*tiocmset)(struct tty_struct *tty, struct file *file, |
| 208 | unsigned int set, unsigned int clear); | 220 | unsigned int set, unsigned int clear); |
| 221 | int (*resize)(struct tty_struct *tty, struct tty_struct *real_tty, | ||
| 222 | struct winsize *ws); | ||
| 209 | #ifdef CONFIG_CONSOLE_POLL | 223 | #ifdef CONFIG_CONSOLE_POLL |
| 210 | int (*poll_init)(struct tty_driver *driver, int line, char *options); | 224 | int (*poll_init)(struct tty_driver *driver, int line, char *options); |
| 211 | int (*poll_get_char)(struct tty_driver *driver, int line); | 225 | int (*poll_get_char)(struct tty_driver *driver, int line); |
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h index 1c78d56c57e5..1cbd0a7db4e6 100644 --- a/include/linux/vt_kern.h +++ b/include/linux/vt_kern.h | |||
| @@ -35,7 +35,6 @@ extern int fg_console, last_console, want_console; | |||
| 35 | int vc_allocate(unsigned int console); | 35 | int vc_allocate(unsigned int console); |
| 36 | int vc_cons_allocated(unsigned int console); | 36 | int vc_cons_allocated(unsigned int console); |
| 37 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); | 37 | int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); |
| 38 | int vc_lock_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); | ||
| 39 | void vc_deallocate(unsigned int console); | 38 | void vc_deallocate(unsigned int console); |
| 40 | void reset_palette(struct vc_data *vc); | 39 | void reset_palette(struct vc_data *vc); |
| 41 | void do_blank_screen(int entering_gfx); | 40 | void do_blank_screen(int entering_gfx); |
