[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>
This commit is contained in:
parent
0a7b35cb18
commit
8b6312f4dc
6 changed files with 45 additions and 18 deletions
|
@ -595,15 +595,9 @@ static void fn_spawn_con(struct vc_data *vc)
|
||||||
|
|
||||||
static void fn_SAK(struct vc_data *vc)
|
static void fn_SAK(struct vc_data *vc)
|
||||||
{
|
{
|
||||||
struct tty_struct *tty = vc->vc_tty;
|
struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
|
||||||
|
PREPARE_WORK(SAK_work, vc_SAK);
|
||||||
/*
|
schedule_work(SAK_work);
|
||||||
* SAK should also work in all raw modes and reset
|
|
||||||
* them properly.
|
|
||||||
*/
|
|
||||||
if (tty)
|
|
||||||
do_SAK(tty);
|
|
||||||
reset_vc(vc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fn_null(struct vc_data *vc)
|
static void fn_null(struct vc_data *vc)
|
||||||
|
|
|
@ -88,9 +88,9 @@ static struct sysrq_key_op sysrq_loglevel_op = {
|
||||||
#ifdef CONFIG_VT
|
#ifdef CONFIG_VT
|
||||||
static void sysrq_handle_SAK(int key, struct tty_struct *tty)
|
static void sysrq_handle_SAK(int key, struct tty_struct *tty)
|
||||||
{
|
{
|
||||||
if (tty)
|
struct work_struct *SAK_work = &vc_cons[fg_console].SAK_work;
|
||||||
do_SAK(tty);
|
PREPARE_WORK(SAK_work, vc_SAK);
|
||||||
reset_vc(vc_cons[fg_console].d);
|
schedule_work(SAK_work);
|
||||||
}
|
}
|
||||||
static struct sysrq_key_op sysrq_SAK_op = {
|
static struct sysrq_key_op sysrq_SAK_op = {
|
||||||
.handler = sysrq_handle_SAK,
|
.handler = sysrq_handle_SAK,
|
||||||
|
|
|
@ -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
|
* Nasty bug: do_SAK is being called in interrupt context. This can
|
||||||
* deadlock. We punt it up to process context. AKPM - 16Mar2001
|
* 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
|
#ifdef TTY_SOFT_SAK
|
||||||
tty_hangup(tty);
|
tty_hangup(tty);
|
||||||
#else
|
#else
|
||||||
|
@ -3394,6 +3392,13 @@ static void __do_SAK(struct work_struct *work)
|
||||||
#endif
|
#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.
|
* 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,
|
* 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)
|
if (!tty)
|
||||||
return;
|
return;
|
||||||
PREPARE_WORK(&tty->SAK_work, __do_SAK);
|
PREPARE_WORK(&tty->SAK_work, do_SAK_work);
|
||||||
schedule_work(&tty->SAK_work);
|
schedule_work(&tty->SAK_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -672,7 +672,8 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
|
||||||
vc->vt_mode = tmp;
|
vc->vt_mode = tmp;
|
||||||
/* the frsig is ignored, so we set it to 0 */
|
/* the frsig is ignored, so we set it to 0 */
|
||||||
vc->vt_mode.frsig = 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 */
|
/* no switch is required -- saw@shade.msu.ru */
|
||||||
vc->vt_newvt = -1;
|
vc->vt_newvt = -1;
|
||||||
release_console_sem();
|
release_console_sem();
|
||||||
|
@ -1063,12 +1064,35 @@ void reset_vc(struct vc_data *vc)
|
||||||
vc->vt_mode.relsig = 0;
|
vc->vt_mode.relsig = 0;
|
||||||
vc->vt_mode.acqsig = 0;
|
vc->vt_mode.acqsig = 0;
|
||||||
vc->vt_mode.frsig = 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;
|
vc->vt_newvt = -1;
|
||||||
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
|
if (!in_interrupt()) /* Via keyboard.c:SAK() - akpm */
|
||||||
reset_palette(vc);
|
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
|
* Performs the back end of a vt switch
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <linux/wait.h>
|
#include <linux/wait.h>
|
||||||
#include <linux/vt.h>
|
#include <linux/vt.h>
|
||||||
|
#include <linux/workqueue.h>
|
||||||
|
|
||||||
struct vt_struct;
|
struct vt_struct;
|
||||||
|
|
||||||
|
@ -103,6 +104,7 @@ struct vc_data {
|
||||||
|
|
||||||
struct vc {
|
struct vc {
|
||||||
struct vc_data *d;
|
struct vc_data *d;
|
||||||
|
struct work_struct SAK_work;
|
||||||
|
|
||||||
/* might add scrmem, vt_struct, kbd at some time,
|
/* might add scrmem, vt_struct, kbd at some time,
|
||||||
to have everything in one place - the disadvantage
|
to have everything in one place - the disadvantage
|
||||||
|
@ -110,6 +112,7 @@ struct vc {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct vc vc_cons [MAX_NR_CONSOLES];
|
extern struct vc vc_cons [MAX_NR_CONSOLES];
|
||||||
|
extern void vc_SAK(struct work_struct *work);
|
||||||
|
|
||||||
#define CUR_DEF 0
|
#define CUR_DEF 0
|
||||||
#define CUR_NONE 1
|
#define CUR_NONE 1
|
||||||
|
|
|
@ -291,6 +291,7 @@ extern void tty_vhangup(struct tty_struct * tty);
|
||||||
extern void tty_unhangup(struct file *filp);
|
extern void tty_unhangup(struct file *filp);
|
||||||
extern int tty_hung_up_p(struct file * filp);
|
extern int tty_hung_up_p(struct file * filp);
|
||||||
extern void do_SAK(struct tty_struct *tty);
|
extern void do_SAK(struct tty_struct *tty);
|
||||||
|
extern void __do_SAK(struct tty_struct *tty);
|
||||||
extern void disassociate_ctty(int priv);
|
extern void disassociate_ctty(int priv);
|
||||||
extern void tty_flip_buffer_push(struct tty_struct *tty);
|
extern void tty_flip_buffer_push(struct tty_struct *tty);
|
||||||
extern speed_t tty_get_baud_rate(struct tty_struct *tty);
|
extern speed_t tty_get_baud_rate(struct tty_struct *tty);
|
||||||
|
|
Loading…
Add table
Reference in a new issue