Commit 5d1a33fa authored by Alan Cox's avatar Alan Cox Committed by Greg Kroah-Hartman

vt: push the tty_lock down into the map handling

When we do this it becomes clear the lock we should be holding is the vc
lock, and in fact many of our other helpers are properly invoked this way.

We don't at this point guarantee not to race the keyboard code but the results
of that appear harmless and that was true before we started as well.

We now have no users of tty_lock in the console driver...
Signed-off-by: default avatarAlan Cox <alan@linux.intel.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 10af77c1
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/tty.h> #include <linux/tty.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/console.h>
#include <linux/consolemap.h> #include <linux/consolemap.h>
#include <linux/vt_kern.h> #include <linux/vt_kern.h>
...@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg) ...@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
if (!access_ok(VERIFY_READ, arg, E_TABSZ)) if (!access_ok(VERIFY_READ, arg, E_TABSZ))
return -EFAULT; return -EFAULT;
console_lock();
for (i=0; i<E_TABSZ ; i++) { for (i=0; i<E_TABSZ ; i++) {
unsigned char uc; unsigned char uc;
__get_user(uc, arg+i); __get_user(uc, arg+i);
...@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg) ...@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
} }
update_user_maps(); update_user_maps();
console_unlock();
return 0; return 0;
} }
...@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg) ...@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
return -EFAULT; return -EFAULT;
console_lock();
for (i=0; i<E_TABSZ ; i++) for (i=0; i<E_TABSZ ; i++)
{ {
ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
__put_user((ch & ~0xff) ? 0 : ch, arg+i); __put_user((ch & ~0xff) ? 0 : ch, arg+i);
} }
console_unlock();
return 0; return 0;
} }
...@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg) ...@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT; return -EFAULT;
console_lock();
for (i=0; i<E_TABSZ ; i++) { for (i=0; i<E_TABSZ ; i++) {
unsigned short us; unsigned short us;
__get_user(us, arg+i); __get_user(us, arg+i);
...@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg) ...@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
} }
update_user_maps(); update_user_maps();
console_unlock();
return 0; return 0;
} }
...@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg) ...@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
return -EFAULT; return -EFAULT;
console_lock();
for (i=0; i<E_TABSZ ; i++) for (i=0; i<E_TABSZ ; i++)
__put_user(p[i], arg+i); __put_user(p[i], arg+i);
console_unlock();
return 0; return 0;
} }
...@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p) ...@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
} }
} }
/* Caller must hold the console lock */
void con_free_unimap(struct vc_data *vc) void con_free_unimap(struct vc_data *vc)
{ {
struct uni_pagedir *p; struct uni_pagedir *p;
...@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos) ...@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
return 0; return 0;
} }
/* ui is a leftover from using a hashtable, but might be used again */ /* ui is a leftover from using a hashtable, but might be used again
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) Caller must hold the lock */
static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{ {
struct uni_pagedir *p, *q; struct uni_pagedir *p, *q;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p && p->readonly) return -EIO; if (p && p->readonly)
return -EIO;
if (!p || --p->refcount) { if (!p || --p->refcount) {
q = kzalloc(sizeof(*p), GFP_KERNEL); q = kzalloc(sizeof(*p), GFP_KERNEL);
if (!q) { if (!q) {
if (p) p->refcount++; if (p)
p->refcount++;
return -ENOMEM; return -ENOMEM;
} }
q->refcount=1; q->refcount=1;
...@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) ...@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
return 0; return 0;
} }
int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
{
int ret;
console_lock();
ret = con_do_clear_unimap(vc, ui);
console_unlock();
return ret;
}
int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
{ {
int err = 0, err1, i; int err = 0, err1, i;
struct uni_pagedir *p, *q; struct uni_pagedir *p, *q;
console_lock();
/* Save original vc_unipagdir_loc in case we allocate a new one */ /* Save original vc_unipagdir_loc in case we allocate a new one */
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p->readonly) return -EIO; if (p->readonly) {
console_unlock();
return -EIO;
}
if (!ct) return 0; if (!ct) {
console_unlock();
return 0;
}
if (p->refcount > 1) { if (p->refcount > 1) {
int j, k; int j, k;
u16 **p1, *p2, l; u16 **p1, *p2, l;
err1 = con_clear_unimap(vc, NULL); err1 = con_do_clear_unimap(vc, NULL);
if (err1) return err1; if (err1) {
console_unlock();
return err1;
}
/* /*
* Since refcount was > 1, con_clear_unimap() allocated a * Since refcount was > 1, con_clear_unimap() allocated a
...@@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) ...@@ -558,7 +592,8 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
*vc->vc_uni_pagedir_loc = (unsigned long)p; *vc->vc_uni_pagedir_loc = (unsigned long)p;
con_release_unimap(q); con_release_unimap(q);
kfree(q); kfree(q);
return err1; console_unlock();
return err1;
} }
} }
} else { } else {
...@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) ...@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
/* /*
* Merge with fontmaps of any other virtual consoles. * Merge with fontmaps of any other virtual consoles.
*/ */
if (con_unify_unimap(vc, p)) if (con_unify_unimap(vc, p)) {
console_unlock();
return err; return err;
}
for (i = 0; i <= 3; i++) for (i = 0; i <= 3; i++)
set_inverse_transl(vc, p, i); /* Update inverse translations */ set_inverse_transl(vc, p, i); /* Update inverse translations */
set_inverse_trans_unicode(vc, p); set_inverse_trans_unicode(vc, p);
console_unlock();
return err; return err;
} }
/* Loads the unimap for the hardware font, as defined in uni_hash.tbl. /**
The representation used was the most compact I could come up * con_set_default_unimap - set default unicode map
with. This routine is executed at sys_setup time, and when the * @vc: the console we are updating
PIO_FONTRESET ioctl is called. */ *
* Loads the unimap for the hardware font, as defined in uni_hash.tbl.
* The representation used was the most compact I could come up
* with. This routine is executed at video setup, and when the
* PIO_FONTRESET ioctl is called.
*
* The caller must hold the console lock
*/
int con_set_default_unimap(struct vc_data *vc) int con_set_default_unimap(struct vc_data *vc)
{ {
int i, j, err = 0, err1; int i, j, err = 0, err1;
...@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc) ...@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p == dflt) if (p == dflt)
return 0; return 0;
dflt->refcount++; dflt->refcount++;
*vc->vc_uni_pagedir_loc = (unsigned long)dflt; *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
if (p && !--p->refcount) { if (p && !--p->refcount) {
...@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc) ...@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
/* The default font is always 256 characters */ /* The default font is always 256 characters */
err = con_clear_unimap(vc, NULL); err = con_do_clear_unimap(vc, NULL);
if (err) return err; if (err)
return err;
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
q = dfont_unitable; q = dfont_unitable;
...@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc) ...@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
} }
EXPORT_SYMBOL(con_set_default_unimap); EXPORT_SYMBOL(con_set_default_unimap);
/**
* con_copy_unimap - copy unimap between two vts
* @dst_vc: target
* @src_vt: source
*
* The caller must hold the console lock when invoking this method
*/
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
{ {
struct uni_pagedir *q; struct uni_pagedir *q;
...@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) ...@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
*dst_vc->vc_uni_pagedir_loc = (long)q; *dst_vc->vc_uni_pagedir_loc = (long)q;
return 0; return 0;
} }
EXPORT_SYMBOL(con_copy_unimap);
/**
* con_get_unimap - get the unicode map
* @vc: the console to read from
*
* Read the console unicode data for this console. Called from the ioctl
* handlers.
*/
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
{ {
int i, j, k, ect; int i, j, k, ect;
u16 **p1, *p2; u16 **p1, *p2;
struct uni_pagedir *p; struct uni_pagedir *p;
console_lock();
ect = 0; ect = 0;
if (*vc->vc_uni_pagedir_loc) { if (*vc->vc_uni_pagedir_loc) {
p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
...@@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni ...@@ -694,22 +757,19 @@ int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct uni
} }
} }
__put_user(ect, uct); __put_user(ect, uct);
console_unlock();
return ((ect <= ct) ? 0 : -ENOMEM); return ((ect <= ct) ? 0 : -ENOMEM);
} }
void con_protect_unimap(struct vc_data *vc, int rdonly)
{
struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
if (p)
p->readonly = rdonly;
}
/* /*
* Always use USER_MAP. These functions are used by the keyboard, * Always use USER_MAP. These functions are used by the keyboard,
* which shouldn't be affected by G0/G1 switching, etc. * which shouldn't be affected by G0/G1 switching, etc.
* If the user map still contains default values, i.e. the * If the user map still contains default values, i.e. the
* direct-to-font mapping, then assume user is using Latin1. * direct-to-font mapping, then assume user is using Latin1.
*
* FIXME: at some point we need to decide if we want to lock the table
* update element itself via the keyboard_event_lock for consistency with the
* keyboard driver as well as the consoles
*/ */
/* may be called during an interrupt */ /* may be called during an interrupt */
u32 conv_8bit_to_uni(unsigned char c) u32 conv_8bit_to_uni(unsigned char c)
...@@ -777,4 +837,3 @@ console_map_init(void) ...@@ -777,4 +837,3 @@ console_map_init(void)
con_set_default_unimap(vc_cons[i].d); con_set_default_unimap(vc_cons[i].d);
} }
EXPORT_SYMBOL(con_copy_unimap);
...@@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty, ...@@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,
ret = con_font_op(vc_cons[fg_console].d, &op); ret = con_font_op(vc_cons[fg_console].d, &op);
if (ret) if (ret)
break; break;
console_lock();
con_set_default_unimap(vc_cons[fg_console].d); con_set_default_unimap(vc_cons[fg_console].d);
console_unlock();
break; break;
} }
#endif #endif
...@@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty, ...@@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,
case PIO_SCRNMAP: case PIO_SCRNMAP:
if (!perm) if (!perm)
ret = -EPERM; ret = -EPERM;
else { else
tty_lock();
ret = con_set_trans_old(up); ret = con_set_trans_old(up);
tty_unlock();
}
break; break;
case GIO_SCRNMAP: case GIO_SCRNMAP:
tty_lock();
ret = con_get_trans_old(up); ret = con_get_trans_old(up);
tty_unlock();
break; break;
case PIO_UNISCRNMAP: case PIO_UNISCRNMAP:
if (!perm) if (!perm)
ret = -EPERM; ret = -EPERM;
else { else
tty_lock();
ret = con_set_trans_new(up); ret = con_set_trans_new(up);
tty_unlock();
}
break; break;
case GIO_UNISCRNMAP: case GIO_UNISCRNMAP:
tty_lock();
ret = con_get_trans_new(up); ret = con_get_trans_new(up);
tty_unlock();
break; break;
case PIO_UNIMAPCLR: case PIO_UNIMAPCLR:
...@@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty, ...@@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,
ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
if (ret) if (ret)
ret = -EFAULT; ret = -EFAULT;
else { else
tty_lock();
con_clear_unimap(vc, &ui); con_clear_unimap(vc, &ui);
tty_unlock();
}
break; break;
} }
case PIO_UNIMAP: case PIO_UNIMAP:
case GIO_UNIMAP: case GIO_UNIMAP:
tty_lock();
ret = do_unimap_ioctl(cmd, up, perm, vc); ret = do_unimap_ioctl(cmd, up, perm, vc);
tty_unlock();
break; break;
case VT_LOCKSWITCH: case VT_LOCKSWITCH:
...@@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty, ...@@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,
case PIO_UNIMAP: case PIO_UNIMAP:
case GIO_UNIMAP: case GIO_UNIMAP:
tty_lock();
ret = compat_unimap_ioctl(cmd, up, perm, vc); ret = compat_unimap_ioctl(cmd, up, perm, vc);
tty_unlock();
break; break;
/* /*
......
...@@ -70,7 +70,6 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); ...@@ -70,7 +70,6 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
int con_set_default_unimap(struct vc_data *vc); int con_set_default_unimap(struct vc_data *vc);
void con_free_unimap(struct vc_data *vc); void con_free_unimap(struct vc_data *vc);
void con_protect_unimap(struct vc_data *vc, int rdonly);
int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
#define vc_translate(vc, c) ((vc)->vc_translate[(c) | \ #define vc_translate(vc, c) ((vc)->vc_translate[(c) | \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment