aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-02-10 04:44:34 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 13:51:24 -0500
commit8b6312f4dcc1efe7975731b6c47dd134282bd9ac (patch)
tree71c94b01bda940c5610d448d0f4a2aa3c7665b4c
parent0a7b35cb18c52d651f6ed9cd59edc979200ab880 (diff)
[PATCH] vt: refactor console SAK processing
This does several things. - It moves looking up of the current foreground console into process context where we can safely take the semaphore that protects this operation. - It uses the new flavor of work queue processing. - This generates a factor of do_SAK, __do_SAK that runs immediately. - This calls __do_SAK with the console semaphore held ensuring nothing else happens to the console while we process the SAK operation. - With the console SAK processing moved into process context this patch removes the xchg operations that I used to attempt to attomically update struct pid, because of the strange locking used in the SAK processing. With SAK using the normal console semaphore nothing special is needed. Cc: Oleg Nesterov <oleg@tv-sign.ru> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/char/keyboard.c12
-rw-r--r--drivers/char/sysrq.c6
-rw-r--r--drivers/char/tty_io.c13
-rw-r--r--drivers/char/vt_ioctl.c28
-rw-r--r--include/linux/console_struct.h3
-rw-r--r--include/linux/tty.h1
6 files changed, 45 insertions, 18 deletions
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index 7a6c1c0b7a95..c654a3e0c697 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -595,15 +595,9 @@ static void fn_spawn_con(struct vc_data *vc)
595 595
596static void fn_SAK(struct vc_data *vc) 596static void fn_SAK(struct vc_data *vc)
597{ 597{
598 struct tty_struct *tty = vc->vc_tty; 598 struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
599 599 PREPARE_WORK(SAK_work, vc_SAK);
600 /* 600 schedule_work(SAK_work);
601 * SAK should also work in all raw modes and reset
602 * them properly.
603 */
604 if (tty)
605 do_SAK(tty);
606 reset_vc(vc);
607} 601}
608 602
609static void fn_null(struct vc_data *vc) 603static void fn_null(struct vc_data *vc)
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 7fd3cd5ddf21..3757610b7835 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -88,9 +88,9 @@ static struct sysrq_key_op sysrq_loglevel_op = {
88#ifdef CONFIG_VT 88#ifdef CONFIG_VT
89static void sysrq_handle_SAK(int key, struct tty_struct *tty) 89static void sysrq_handle_SAK(int key, struct tty_struct *tty)
90{ 90{
91 if (tty) 91 struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
92 do_SAK(tty); 92 PREPARE_WORK(SAK_work, vc_SAK);
93 reset_vc(vc_cons[fg_console].d); 93 schedule_work(SAK_work);
94} 94}
95static struct sysrq_key_op sysrq_SAK_op = { 95static struct sysrq_key_op sysrq_SAK_op = {
96 .handler = sysrq_handle_SAK, 96 .handler = sysrq_handle_SAK,
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 47a6eacb10bc..c57b1f434652 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -3324,10 +3324,8 @@ int tty_ioctl(struct inode * inode, struct file * file,
3324 * Nasty bug: do_SAK is being called in interrupt context. This can 3324 * Nasty bug: do_SAK is being called in interrupt context. This can
3325 * deadlock. We punt it up to process context. AKPM - 16Mar2001 3325 * deadlock. We punt it up to process context. AKPM - 16Mar2001
3326 */ 3326 */
3327static void __do_SAK(struct work_struct *work) 3327void __do_SAK(struct tty_struct *tty)
3328{ 3328{
3329 struct tty_struct *tty =
3330 container_of(work, struct tty_struct, SAK_work);
3331#ifdef TTY_SOFT_SAK 3329#ifdef TTY_SOFT_SAK
3332 tty_hangup(tty); 3330 tty_hangup(tty);
3333#else 3331#else
@@ -3394,6 +3392,13 @@ static void __do_SAK(struct work_struct *work)
3394#endif 3392#endif
3395} 3393}
3396 3394
3395static void do_SAK_work(struct work_struct *work)
3396{
3397 struct tty_struct *tty =
3398 container_of(work, struct tty_struct, SAK_work);
3399 __do_SAK(tty);
3400}
3401
3397/* 3402/*
3398 * The tq handling here is a little racy - tty->SAK_work may already be queued. 3403 * The tq handling here is a little racy - tty->SAK_work may already be queued.
3399 * Fortunately we don't need to worry, because if ->SAK_work is already queued, 3404 * Fortunately we don't need to worry, because if ->SAK_work is already queued,
@@ -3404,7 +3409,7 @@ void do_SAK(struct tty_struct *tty)
3404{ 3409{
3405 if (!tty) 3410 if (!tty)
3406 return; 3411 return;
3407 PREPARE_WORK(&tty->SAK_work, __do_SAK); 3412 PREPARE_WORK(&tty->SAK_work, do_SAK_work);
3408 schedule_work(&tty->SAK_work); 3413 schedule_work(&tty->SAK_work);
3409} 3414}
3410 3415
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index dc8368ebb1ac..3a5d301e783b 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -672,7 +672,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
672 vc->vt_mode = tmp; 672 vc->vt_mode = tmp;
673 /* the frsig is ignored, so we set it to 0 */ 673 /* the frsig is ignored, so we set it to 0 */
674 vc->vt_mode.frsig = 0; 674 vc->vt_mode.frsig = 0;
675 put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current)))); 675 put_pid(vc->vt_pid);
676 vc->vt_pid = get_pid(task_pid(current));
676 /* no switch is required -- saw@shade.msu.ru */ 677 /* no switch is required -- saw@shade.msu.ru */
677 vc->vt_newvt = -1; 678 vc->vt_newvt = -1;
678 release_console_sem(); 679 release_console_sem();
@@ -1063,12 +1064,35 @@ void reset_vc(struct vc_data *vc)
1063 vc->vt_mode.relsig = 0; 1064 vc->vt_mode.relsig = 0;
1064 vc->vt_mode.acqsig = 0; 1065 vc->vt_mode.acqsig = 0;
1065 vc->vt_mode.frsig = 0; 1066 vc->vt_mode.frsig = 0;
1066 put_pid(xchg(&vc->vt_pid, NULL)); 1067 put_pid(vc->vt_pid);
1068 vc->vt_pid = NULL;
1067 vc->vt_newvt = -1; 1069 vc->vt_newvt = -1;
1068 if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */ 1070 if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
1069 reset_palette(vc); 1071 reset_palette(vc);
1070} 1072}
1071 1073
1074void vc_SAK(struct work_struct *work)
1075{
1076 struct vc *vc_con =
1077 container_of(work, struct vc, SAK_work);
1078 struct vc_data *vc;
1079 struct tty_struct *tty;
1080
1081 acquire_console_sem();
1082 vc = vc_con->d;
1083 if (vc) {
1084 tty = vc->vc_tty;
1085 /*
1086 * SAK should also work in all raw modes and reset
1087 * them properly.
1088 */
1089 if (tty)
1090 __do_SAK(tty);
1091 reset_vc(vc);
1092 }
1093 release_console_sem();
1094}
1095
1072/* 1096/*
1073 * Performs the back end of a vt switch 1097 * Performs the back end of a vt switch
1074 */ 1098 */
diff --git a/include/linux/console_struct.h b/include/linux/console_struct.h
index ed6c0fee1ac7..a86162b26c0d 100644
--- a/include/linux/console_struct.h
+++ b/include/linux/console_struct.h
@@ -11,6 +11,7 @@
11 11
12#include <linux/wait.h> 12#include <linux/wait.h>
13#include <linux/vt.h> 13#include <linux/vt.h>
14#include <linux/workqueue.h>
14 15
15struct vt_struct; 16struct vt_struct;
16 17
@@ -103,6 +104,7 @@ struct vc_data {
103 104
104struct vc { 105struct vc {
105 struct vc_data *d; 106 struct vc_data *d;
107 struct work_struct SAK_work;
106 108
107 /* might add scrmem, vt_struct, kbd at some time, 109 /* might add scrmem, vt_struct, kbd at some time,
108 to have everything in one place - the disadvantage 110 to have everything in one place - the disadvantage
@@ -110,6 +112,7 @@ struct vc {
110}; 112};
111 113
112extern struct vc vc_cons [MAX_NR_CONSOLES]; 114extern struct vc vc_cons [MAX_NR_CONSOLES];
115extern void vc_SAK(struct work_struct *work);
113 116
114#define CUR_DEF 0 117#define CUR_DEF 0
115#define CUR_NONE 1 118#define CUR_NONE 1
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 65cbcf22c31e..0161a8c6dbf6 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -291,6 +291,7 @@ extern void tty_vhangup(struct tty_struct * tty);
291extern void tty_unhangup(struct file *filp); 291extern void tty_unhangup(struct file *filp);
292extern int tty_hung_up_p(struct file * filp); 292extern int tty_hung_up_p(struct file * filp);
293extern void do_SAK(struct tty_struct *tty); 293extern void do_SAK(struct tty_struct *tty);
294extern void __do_SAK(struct tty_struct *tty);
294extern void disassociate_ctty(int priv); 295extern void disassociate_ctty(int priv);
295extern void tty_flip_buffer_push(struct tty_struct *tty); 296extern void tty_flip_buffer_push(struct tty_struct *tty);
296extern speed_t tty_get_baud_rate(struct tty_struct *tty); 297extern speed_t tty_get_baud_rate(struct tty_struct *tty);