aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2012-04-24 06:06:06 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-04-24 19:14:14 -0400
commit5d1a33fa5573702394a4d09a9872f3f930c06d58 (patch)
tree1e1ad3fd38f2bd1ac0f375ac18e9471af2861ee2
parent10af77c193681398e5dbe830db181d86047fcd41 (diff)
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: Alan Cox <alan@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/tty/vt/consolemap.c123
-rw-r--r--drivers/tty/vt/vt_ioctl.c25
-rw-r--r--include/linux/vt_kern.h1
3 files changed, 96 insertions, 53 deletions
diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c
index 8308fc7cdc26..2aaa0c228409 100644
--- a/drivers/tty/vt/consolemap.c
+++ b/drivers/tty/vt/consolemap.c
@@ -19,6 +19,7 @@
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/tty.h> 20#include <linux/tty.h>
21#include <asm/uaccess.h> 21#include <asm/uaccess.h>
22#include <linux/console.h>
22#include <linux/consolemap.h> 23#include <linux/consolemap.h>
23#include <linux/vt_kern.h> 24#include <linux/vt_kern.h>
24 25
@@ -312,6 +313,7 @@ int con_set_trans_old(unsigned char __user * arg)
312 if (!access_ok(VERIFY_READ, arg, E_TABSZ)) 313 if (!access_ok(VERIFY_READ, arg, E_TABSZ))
313 return -EFAULT; 314 return -EFAULT;
314 315
316 console_lock();
315 for (i=0; i<E_TABSZ ; i++) { 317 for (i=0; i<E_TABSZ ; i++) {
316 unsigned char uc; 318 unsigned char uc;
317 __get_user(uc, arg+i); 319 __get_user(uc, arg+i);
@@ -319,6 +321,7 @@ int con_set_trans_old(unsigned char __user * arg)
319 } 321 }
320 322
321 update_user_maps(); 323 update_user_maps();
324 console_unlock();
322 return 0; 325 return 0;
323} 326}
324 327
@@ -330,11 +333,13 @@ int con_get_trans_old(unsigned char __user * arg)
330 if (!access_ok(VERIFY_WRITE, arg, E_TABSZ)) 333 if (!access_ok(VERIFY_WRITE, arg, E_TABSZ))
331 return -EFAULT; 334 return -EFAULT;
332 335
336 console_lock();
333 for (i=0; i<E_TABSZ ; i++) 337 for (i=0; i<E_TABSZ ; i++)
334 { 338 {
335 ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]); 339 ch = conv_uni_to_pc(vc_cons[fg_console].d, p[i]);
336 __put_user((ch & ~0xff) ? 0 : ch, arg+i); 340 __put_user((ch & ~0xff) ? 0 : ch, arg+i);
337 } 341 }
342 console_unlock();
338 return 0; 343 return 0;
339} 344}
340 345
@@ -346,6 +351,7 @@ int con_set_trans_new(ushort __user * arg)
346 if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short))) 351 if (!access_ok(VERIFY_READ, arg, E_TABSZ*sizeof(unsigned short)))
347 return -EFAULT; 352 return -EFAULT;
348 353
354 console_lock();
349 for (i=0; i<E_TABSZ ; i++) { 355 for (i=0; i<E_TABSZ ; i++) {
350 unsigned short us; 356 unsigned short us;
351 __get_user(us, arg+i); 357 __get_user(us, arg+i);
@@ -353,6 +359,7 @@ int con_set_trans_new(ushort __user * arg)
353 } 359 }
354 360
355 update_user_maps(); 361 update_user_maps();
362 console_unlock();
356 return 0; 363 return 0;
357} 364}
358 365
@@ -364,8 +371,10 @@ int con_get_trans_new(ushort __user * arg)
364 if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short))) 371 if (!access_ok(VERIFY_WRITE, arg, E_TABSZ*sizeof(unsigned short)))
365 return -EFAULT; 372 return -EFAULT;
366 373
374 console_lock();
367 for (i=0; i<E_TABSZ ; i++) 375 for (i=0; i<E_TABSZ ; i++)
368 __put_user(p[i], arg+i); 376 __put_user(p[i], arg+i);
377 console_unlock();
369 378
370 return 0; 379 return 0;
371} 380}
@@ -407,6 +416,7 @@ static void con_release_unimap(struct uni_pagedir *p)
407 } 416 }
408} 417}
409 418
419/* Caller must hold the console lock */
410void con_free_unimap(struct vc_data *vc) 420void con_free_unimap(struct vc_data *vc)
411{ 421{
412 struct uni_pagedir *p; 422 struct uni_pagedir *p;
@@ -487,17 +497,21 @@ con_insert_unipair(struct uni_pagedir *p, u_short unicode, u_short fontpos)
487 return 0; 497 return 0;
488} 498}
489 499
490/* ui is a leftover from using a hashtable, but might be used again */ 500/* ui is a leftover from using a hashtable, but might be used again
491int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui) 501 Caller must hold the lock */
502static int con_do_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
492{ 503{
493 struct uni_pagedir *p, *q; 504 struct uni_pagedir *p, *q;
494 505
495 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 506 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
496 if (p && p->readonly) return -EIO; 507 if (p && p->readonly)
508 return -EIO;
509
497 if (!p || --p->refcount) { 510 if (!p || --p->refcount) {
498 q = kzalloc(sizeof(*p), GFP_KERNEL); 511 q = kzalloc(sizeof(*p), GFP_KERNEL);
499 if (!q) { 512 if (!q) {
500 if (p) p->refcount++; 513 if (p)
514 p->refcount++;
501 return -ENOMEM; 515 return -ENOMEM;
502 } 516 }
503 q->refcount=1; 517 q->refcount=1;
@@ -511,23 +525,43 @@ int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
511 return 0; 525 return 0;
512} 526}
513 527
528int con_clear_unimap(struct vc_data *vc, struct unimapinit *ui)
529{
530 int ret;
531 console_lock();
532 ret = con_do_clear_unimap(vc, ui);
533 console_unlock();
534 return ret;
535}
536
514int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) 537int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
515{ 538{
516 int err = 0, err1, i; 539 int err = 0, err1, i;
517 struct uni_pagedir *p, *q; 540 struct uni_pagedir *p, *q;
518 541
542 console_lock();
543
519 /* Save original vc_unipagdir_loc in case we allocate a new one */ 544 /* Save original vc_unipagdir_loc in case we allocate a new one */
520 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 545 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
521 if (p->readonly) return -EIO; 546 if (p->readonly) {
547 console_unlock();
548 return -EIO;
549 }
522 550
523 if (!ct) return 0; 551 if (!ct) {
552 console_unlock();
553 return 0;
554 }
524 555
525 if (p->refcount > 1) { 556 if (p->refcount > 1) {
526 int j, k; 557 int j, k;
527 u16 **p1, *p2, l; 558 u16 **p1, *p2, l;
528 559
529 err1 = con_clear_unimap(vc, NULL); 560 err1 = con_do_clear_unimap(vc, NULL);
530 if (err1) return err1; 561 if (err1) {
562 console_unlock();
563 return err1;
564 }
531 565
532 /* 566 /*
533 * Since refcount was > 1, con_clear_unimap() allocated a 567 * 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 *vc->vc_uni_pagedir_loc = (unsigned long)p; 592 *vc->vc_uni_pagedir_loc = (unsigned long)p;
559 con_release_unimap(q); 593 con_release_unimap(q);
560 kfree(q); 594 kfree(q);
561 return err1; 595 console_unlock();
596 return err1;
562 } 597 }
563 } 598 }
564 } else { 599 } else {
@@ -592,21 +627,30 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list)
592 /* 627 /*
593 * Merge with fontmaps of any other virtual consoles. 628 * Merge with fontmaps of any other virtual consoles.
594 */ 629 */
595 if (con_unify_unimap(vc, p)) 630 if (con_unify_unimap(vc, p)) {
631 console_unlock();
596 return err; 632 return err;
633 }
597 634
598 for (i = 0; i <= 3; i++) 635 for (i = 0; i <= 3; i++)
599 set_inverse_transl(vc, p, i); /* Update inverse translations */ 636 set_inverse_transl(vc, p, i); /* Update inverse translations */
600 set_inverse_trans_unicode(vc, p); 637 set_inverse_trans_unicode(vc, p);
601 638
639 console_unlock();
602 return err; 640 return err;
603} 641}
604 642
605/* Loads the unimap for the hardware font, as defined in uni_hash.tbl. 643/**
606 The representation used was the most compact I could come up 644 * con_set_default_unimap - set default unicode map
607 with. This routine is executed at sys_setup time, and when the 645 * @vc: the console we are updating
608 PIO_FONTRESET ioctl is called. */ 646 *
609 647 * Loads the unimap for the hardware font, as defined in uni_hash.tbl.
648 * The representation used was the most compact I could come up
649 * with. This routine is executed at video setup, and when the
650 * PIO_FONTRESET ioctl is called.
651 *
652 * The caller must hold the console lock
653 */
610int con_set_default_unimap(struct vc_data *vc) 654int con_set_default_unimap(struct vc_data *vc)
611{ 655{
612 int i, j, err = 0, err1; 656 int i, j, err = 0, err1;
@@ -617,6 +661,7 @@ int con_set_default_unimap(struct vc_data *vc)
617 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 661 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
618 if (p == dflt) 662 if (p == dflt)
619 return 0; 663 return 0;
664
620 dflt->refcount++; 665 dflt->refcount++;
621 *vc->vc_uni_pagedir_loc = (unsigned long)dflt; 666 *vc->vc_uni_pagedir_loc = (unsigned long)dflt;
622 if (p && !--p->refcount) { 667 if (p && !--p->refcount) {
@@ -628,8 +673,9 @@ int con_set_default_unimap(struct vc_data *vc)
628 673
629 /* The default font is always 256 characters */ 674 /* The default font is always 256 characters */
630 675
631 err = con_clear_unimap(vc, NULL); 676 err = con_do_clear_unimap(vc, NULL);
632 if (err) return err; 677 if (err)
678 return err;
633 679
634 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 680 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
635 q = dfont_unitable; 681 q = dfont_unitable;
@@ -654,6 +700,13 @@ int con_set_default_unimap(struct vc_data *vc)
654} 700}
655EXPORT_SYMBOL(con_set_default_unimap); 701EXPORT_SYMBOL(con_set_default_unimap);
656 702
703/**
704 * con_copy_unimap - copy unimap between two vts
705 * @dst_vc: target
706 * @src_vt: source
707 *
708 * The caller must hold the console lock when invoking this method
709 */
657int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) 710int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
658{ 711{
659 struct uni_pagedir *q; 712 struct uni_pagedir *q;
@@ -668,13 +721,23 @@ int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc)
668 *dst_vc->vc_uni_pagedir_loc = (long)q; 721 *dst_vc->vc_uni_pagedir_loc = (long)q;
669 return 0; 722 return 0;
670} 723}
724EXPORT_SYMBOL(con_copy_unimap);
671 725
726/**
727 * con_get_unimap - get the unicode map
728 * @vc: the console to read from
729 *
730 * Read the console unicode data for this console. Called from the ioctl
731 * handlers.
732 */
672int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list) 733int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list)
673{ 734{
674 int i, j, k, ect; 735 int i, j, k, ect;
675 u16 **p1, *p2; 736 u16 **p1, *p2;
676 struct uni_pagedir *p; 737 struct uni_pagedir *p;
677 738
739 console_lock();
740
678 ect = 0; 741 ect = 0;
679 if (*vc->vc_uni_pagedir_loc) { 742 if (*vc->vc_uni_pagedir_loc) {
680 p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc; 743 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 } 757 }
695 } 758 }
696 __put_user(ect, uct); 759 __put_user(ect, uct);
760 console_unlock();
697 return ((ect <= ct) ? 0 : -ENOMEM); 761 return ((ect <= ct) ? 0 : -ENOMEM);
698} 762}
699 763
700void con_protect_unimap(struct vc_data *vc, int rdonly)
701{
702 struct uni_pagedir *p = (struct uni_pagedir *)*vc->vc_uni_pagedir_loc;
703
704 if (p)
705 p->readonly = rdonly;
706}
707
708/* 764/*
709 * Always use USER_MAP. These functions are used by the keyboard, 765 * Always use USER_MAP. These functions are used by the keyboard,
710 * which shouldn't be affected by G0/G1 switching, etc. 766 * which shouldn't be affected by G0/G1 switching, etc.
711 * If the user map still contains default values, i.e. the 767 * If the user map still contains default values, i.e. the
712 * direct-to-font mapping, then assume user is using Latin1. 768 * direct-to-font mapping, then assume user is using Latin1.
769 *
770 * FIXME: at some point we need to decide if we want to lock the table
771 * update element itself via the keyboard_event_lock for consistency with the
772 * keyboard driver as well as the consoles
713 */ 773 */
714/* may be called during an interrupt */ 774/* may be called during an interrupt */
715u32 conv_8bit_to_uni(unsigned char c) 775u32 conv_8bit_to_uni(unsigned char c)
@@ -777,4 +837,3 @@ console_map_init(void)
777 con_set_default_unimap(vc_cons[i].d); 837 con_set_default_unimap(vc_cons[i].d);
778} 838}
779 839
780EXPORT_SYMBOL(con_copy_unimap);
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c
index ede2ef18d2fb..64618547be11 100644
--- a/drivers/tty/vt/vt_ioctl.c
+++ b/drivers/tty/vt/vt_ioctl.c
@@ -910,7 +910,9 @@ int vt_ioctl(struct tty_struct *tty,
910 ret = con_font_op(vc_cons[fg_console].d, &op); 910 ret = con_font_op(vc_cons[fg_console].d, &op);
911 if (ret) 911 if (ret)
912 break; 912 break;
913 console_lock();
913 con_set_default_unimap(vc_cons[fg_console].d); 914 con_set_default_unimap(vc_cons[fg_console].d);
915 console_unlock();
914 break; 916 break;
915 } 917 }
916#endif 918#endif
@@ -934,33 +936,23 @@ int vt_ioctl(struct tty_struct *tty,
934 case PIO_SCRNMAP: 936 case PIO_SCRNMAP:
935 if (!perm) 937 if (!perm)
936 ret = -EPERM; 938 ret = -EPERM;
937 else { 939 else
938 tty_lock();
939 ret = con_set_trans_old(up); 940 ret = con_set_trans_old(up);
940 tty_unlock();
941 }
942 break; 941 break;
943 942
944 case GIO_SCRNMAP: 943 case GIO_SCRNMAP:
945 tty_lock();
946 ret = con_get_trans_old(up); 944 ret = con_get_trans_old(up);
947 tty_unlock();
948 break; 945 break;
949 946
950 case PIO_UNISCRNMAP: 947 case PIO_UNISCRNMAP:
951 if (!perm) 948 if (!perm)
952 ret = -EPERM; 949 ret = -EPERM;
953 else { 950 else
954 tty_lock();
955 ret = con_set_trans_new(up); 951 ret = con_set_trans_new(up);
956 tty_unlock();
957 }
958 break; 952 break;
959 953
960 case GIO_UNISCRNMAP: 954 case GIO_UNISCRNMAP:
961 tty_lock();
962 ret = con_get_trans_new(up); 955 ret = con_get_trans_new(up);
963 tty_unlock();
964 break; 956 break;
965 957
966 case PIO_UNIMAPCLR: 958 case PIO_UNIMAPCLR:
@@ -970,19 +962,14 @@ int vt_ioctl(struct tty_struct *tty,
970 ret = copy_from_user(&ui, up, sizeof(struct unimapinit)); 962 ret = copy_from_user(&ui, up, sizeof(struct unimapinit));
971 if (ret) 963 if (ret)
972 ret = -EFAULT; 964 ret = -EFAULT;
973 else { 965 else
974 tty_lock();
975 con_clear_unimap(vc, &ui); 966 con_clear_unimap(vc, &ui);
976 tty_unlock();
977 }
978 break; 967 break;
979 } 968 }
980 969
981 case PIO_UNIMAP: 970 case PIO_UNIMAP:
982 case GIO_UNIMAP: 971 case GIO_UNIMAP:
983 tty_lock();
984 ret = do_unimap_ioctl(cmd, up, perm, vc); 972 ret = do_unimap_ioctl(cmd, up, perm, vc);
985 tty_unlock();
986 break; 973 break;
987 974
988 case VT_LOCKSWITCH: 975 case VT_LOCKSWITCH:
@@ -1196,9 +1183,7 @@ long vt_compat_ioctl(struct tty_struct *tty,
1196 1183
1197 case PIO_UNIMAP: 1184 case PIO_UNIMAP:
1198 case GIO_UNIMAP: 1185 case GIO_UNIMAP:
1199 tty_lock();
1200 ret = compat_unimap_ioctl(cmd, up, perm, vc); 1186 ret = compat_unimap_ioctl(cmd, up, perm, vc);
1201 tty_unlock();
1202 break; 1187 break;
1203 1188
1204 /* 1189 /*
diff --git a/include/linux/vt_kern.h b/include/linux/vt_kern.h
index e33d77f15bda..50ae7d0c279e 100644
--- a/include/linux/vt_kern.h
+++ b/include/linux/vt_kern.h
@@ -70,7 +70,6 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list);
70int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); 70int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list);
71int con_set_default_unimap(struct vc_data *vc); 71int con_set_default_unimap(struct vc_data *vc);
72void con_free_unimap(struct vc_data *vc); 72void con_free_unimap(struct vc_data *vc);
73void con_protect_unimap(struct vc_data *vc, int rdonly);
74int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); 73int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc);
75 74
76#define vc_translate(vc, c) ((vc)->vc_translate[(c) | \ 75#define vc_translate(vc, c) ((vc)->vc_translate[(c) | \