summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-02-10 01:44:34 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-11 10:51:24 -0800
commit8b6312f4dcc1efe7975731b6c47dd134282bd9ac (patch)
tree71c94b01bda940c5610d448d0f4a2aa3c7665b4c /drivers
parent0a7b35cb18c52d651f6ed9cd59edc979200ab880 (diff)
downloadlwn-8b6312f4dcc1efe7975731b6c47dd134282bd9ac.tar.gz
lwn-8b6312f4dcc1efe7975731b6c47dd134282bd9ac.zip
[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>
Diffstat (limited to 'drivers')
-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
4 files changed, 41 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)
static void fn_SAK(struct vc_data *vc)
{
- struct tty_struct *tty = vc->vc_tty;
-
- /*
- * SAK should also work in all raw modes and reset
- * them properly.
- */
- if (tty)
- do_SAK(tty);
- reset_vc(vc);
+ struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+ PREPARE_WORK(SAK_work, vc_SAK);
+ schedule_work(SAK_work);
}
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 = {
#ifdef CONFIG_VT
static void sysrq_handle_SAK(int key, struct tty_struct *tty)
{
- if (tty)
- do_SAK(tty);
- reset_vc(vc_cons[fg_console].d);
+ struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
+ PREPARE_WORK(SAK_work, vc_SAK);
+ schedule_work(SAK_work);
}
static struct sysrq_key_op sysrq_SAK_op = {
.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,
* Nasty bug: do_SAK is being called in interrupt context. This can
* deadlock. We punt it up to process context. AKPM - 16Mar2001
*/
-static void __do_SAK(struct work_struct *work)
+void __do_SAK(struct tty_struct *tty)
{
- struct tty_struct *tty =
- container_of(work, struct tty_struct, SAK_work);
#ifdef TTY_SOFT_SAK
tty_hangup(tty);
#else
@@ -3394,6 +3392,13 @@ static void __do_SAK(struct work_struct *work)
#endif
}
+static void do_SAK_work(struct work_struct *work)
+{
+ struct tty_struct *tty =
+ container_of(work, struct tty_struct, SAK_work);
+ __do_SAK(tty);
+}
+
/*
* The tq handling here is a little racy - tty->SAK_work may already be queued.
* 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)
{
if (!tty)
return;
- PREPARE_WORK(&tty->SAK_work, __do_SAK);
+ PREPARE_WORK(&tty->SAK_work, do_SAK_work);
schedule_work(&tty->SAK_work);
}
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,
vc->vt_mode = tmp;
/* the frsig is ignored, so we set it to 0 */
vc->vt_mode.frsig = 0;
- put_pid(xchg(&vc->vt_pid, get_pid(task_pid(current))));
+ put_pid(vc->vt_pid);
+ vc->vt_pid = get_pid(task_pid(current));
/* no switch is required -- saw@shade.msu.ru */
vc->vt_newvt = -1;
release_console_sem();
@@ -1063,12 +1064,35 @@ void reset_vc(struct vc_data *vc)
vc->vt_mode.relsig = 0;
vc->vt_mode.acqsig = 0;
vc->vt_mode.frsig = 0;
- put_pid(xchg(&vc->vt_pid, NULL));
+ put_pid(vc->vt_pid);
+ vc->vt_pid = NULL;
vc->vt_newvt = -1;
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
reset_palette(vc);
}
+void vc_SAK(struct work_struct *work)
+{
+ struct vc *vc_con =
+ container_of(work, struct vc, SAK_work);
+ struct vc_data *vc;
+ struct tty_struct *tty;
+
+ acquire_console_sem();
+ vc = vc_con->d;
+ if (vc) {
+ tty = vc->vc_tty;
+ /*
+ * SAK should also work in all raw modes and reset
+ * them properly.
+ */
+ if (tty)
+ __do_SAK(tty);
+ reset_vc(vc);
+ }
+ release_console_sem();
+}
+
/*
* Performs the back end of a vt switch
*/