diff options
author | Eric W. Biederman <ebiederm@xmission.com> | 2007-02-10 04:44:34 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-02-11 13:51:24 -0500 |
commit | 8b6312f4dcc1efe7975731b6c47dd134282bd9ac (patch) | |
tree | 71c94b01bda940c5610d448d0f4a2aa3c7665b4c | |
parent | 0a7b35cb18c52d651f6ed9cd59edc979200ab880 (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.c | 12 | ||||
-rw-r--r-- | drivers/char/sysrq.c | 6 | ||||
-rw-r--r-- | drivers/char/tty_io.c | 13 | ||||
-rw-r--r-- | drivers/char/vt_ioctl.c | 28 | ||||
-rw-r--r-- | include/linux/console_struct.h | 3 | ||||
-rw-r--r-- | include/linux/tty.h | 1 |
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 | ||
596 | static void fn_SAK(struct vc_data *vc) | 596 | static 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 | ||
609 | static void fn_null(struct vc_data *vc) | 603 | static 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 |
89 | static void sysrq_handle_SAK(int key, struct tty_struct *tty) | 89 | static 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 | } |
95 | static struct sysrq_key_op sysrq_SAK_op = { | 95 | static 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 | */ |
3327 | static void __do_SAK(struct work_struct *work) | 3327 | void __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 | ||
3395 | static 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 | ||
1074 | void 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 | ||
15 | struct vt_struct; | 16 | struct vt_struct; |
16 | 17 | ||
@@ -103,6 +104,7 @@ struct vc_data { | |||
103 | 104 | ||
104 | struct vc { | 105 | struct 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 | ||
112 | extern struct vc vc_cons [MAX_NR_CONSOLES]; | 114 | extern struct vc vc_cons [MAX_NR_CONSOLES]; |
115 | extern 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); | |||
291 | extern void tty_unhangup(struct file *filp); | 291 | extern void tty_unhangup(struct file *filp); |
292 | extern int tty_hung_up_p(struct file * filp); | 292 | extern int tty_hung_up_p(struct file * filp); |
293 | extern void do_SAK(struct tty_struct *tty); | 293 | extern void do_SAK(struct tty_struct *tty); |
294 | extern void __do_SAK(struct tty_struct *tty); | ||
294 | extern void disassociate_ctty(int priv); | 295 | extern void disassociate_ctty(int priv); |
295 | extern void tty_flip_buffer_push(struct tty_struct *tty); | 296 | extern void tty_flip_buffer_push(struct tty_struct *tty); |
296 | extern speed_t tty_get_baud_rate(struct tty_struct *tty); | 297 | extern speed_t tty_get_baud_rate(struct tty_struct *tty); |