diff options
author | Alan Cox <alan@linux.intel.com> | 2012-02-24 07:47:11 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2012-02-24 16:59:34 -0500 |
commit | 247ff8e610cb63c015de19191db9666754c2ed79 (patch) | |
tree | e4d097c10c6211ff05f9d8ec6669c584de9e08ae /drivers/tty/vt | |
parent | ce1000ddca01c81684da844be4676eac50a70c2a (diff) |
vt: lock the accent table
First step to debletcherising the vt console layer - pick a victim and fix
the locking
This is a nice simple object with its own rules so lets pick it out for
treatment. The user of the table already has a lock so we will also use the
same lock for updates.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/vt')
-rw-r--r-- | drivers/tty/vt/keyboard.c | 162 | ||||
-rw-r--r-- | drivers/tty/vt/vt_ioctl.c | 81 |
2 files changed, 165 insertions, 78 deletions
diff --git a/drivers/tty/vt/keyboard.c b/drivers/tty/vt/keyboard.c index a605549ee28f..bdf838dd3e44 100644 --- a/drivers/tty/vt/keyboard.c +++ b/drivers/tty/vt/keyboard.c | |||
@@ -1452,3 +1452,165 @@ int __init kbd_init(void) | |||
1452 | 1452 | ||
1453 | return 0; | 1453 | return 0; |
1454 | } | 1454 | } |
1455 | |||
1456 | /* Ioctl support code */ | ||
1457 | |||
1458 | /** | ||
1459 | * vt_do_diacrit - diacritical table updates | ||
1460 | * @cmd: ioctl request | ||
1461 | * @up: pointer to user data for ioctl | ||
1462 | * @perm: permissions check computed by caller | ||
1463 | * | ||
1464 | * Update the diacritical tables atomically and safely. Lock them | ||
1465 | * against simultaneous keypresses | ||
1466 | */ | ||
1467 | int vt_do_diacrit(unsigned int cmd, void __user *up, int perm) | ||
1468 | { | ||
1469 | struct kbdiacrs __user *a = up; | ||
1470 | unsigned long flags; | ||
1471 | int asize; | ||
1472 | int ret = 0; | ||
1473 | |||
1474 | switch (cmd) { | ||
1475 | case KDGKBDIACR: | ||
1476 | { | ||
1477 | struct kbdiacr *diacr; | ||
1478 | int i; | ||
1479 | |||
1480 | diacr = kmalloc(MAX_DIACR * sizeof(struct kbdiacr), | ||
1481 | GFP_KERNEL); | ||
1482 | if (diacr == NULL) | ||
1483 | return -ENOMEM; | ||
1484 | |||
1485 | /* Lock the diacriticals table, make a copy and then | ||
1486 | copy it after we unlock */ | ||
1487 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1488 | |||
1489 | asize = accent_table_size; | ||
1490 | for (i = 0; i < asize; i++) { | ||
1491 | diacr[i].diacr = conv_uni_to_8bit( | ||
1492 | accent_table[i].diacr); | ||
1493 | diacr[i].base = conv_uni_to_8bit( | ||
1494 | accent_table[i].base); | ||
1495 | diacr[i].result = conv_uni_to_8bit( | ||
1496 | accent_table[i].result); | ||
1497 | } | ||
1498 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1499 | |||
1500 | if (put_user(asize, &a->kb_cnt)) | ||
1501 | ret = -EFAULT; | ||
1502 | else if (copy_to_user(a->kbdiacr, diacr, | ||
1503 | asize * sizeof(struct kbdiacr))) | ||
1504 | ret = -EFAULT; | ||
1505 | kfree(diacr); | ||
1506 | return ret; | ||
1507 | } | ||
1508 | case KDGKBDIACRUC: | ||
1509 | { | ||
1510 | struct kbdiacrsuc __user *a = up; | ||
1511 | void *buf; | ||
1512 | |||
1513 | buf = kmalloc(MAX_DIACR * sizeof(struct kbdiacruc), | ||
1514 | GFP_KERNEL); | ||
1515 | if (buf == NULL) | ||
1516 | return -ENOMEM; | ||
1517 | |||
1518 | /* Lock the diacriticals table, make a copy and then | ||
1519 | copy it after we unlock */ | ||
1520 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1521 | |||
1522 | asize = accent_table_size; | ||
1523 | memcpy(buf, accent_table, asize * sizeof(struct kbdiacruc)); | ||
1524 | |||
1525 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1526 | |||
1527 | if (put_user(asize, &a->kb_cnt)) | ||
1528 | ret = -EFAULT; | ||
1529 | else if (copy_to_user(a->kbdiacruc, buf, | ||
1530 | asize*sizeof(struct kbdiacruc))) | ||
1531 | ret = -EFAULT; | ||
1532 | kfree(buf); | ||
1533 | return ret; | ||
1534 | } | ||
1535 | |||
1536 | case KDSKBDIACR: | ||
1537 | { | ||
1538 | struct kbdiacrs __user *a = up; | ||
1539 | struct kbdiacr *diacr = NULL; | ||
1540 | unsigned int ct; | ||
1541 | int i; | ||
1542 | |||
1543 | if (!perm) | ||
1544 | return -EPERM; | ||
1545 | if (get_user(ct, &a->kb_cnt)) | ||
1546 | return -EFAULT; | ||
1547 | if (ct >= MAX_DIACR) | ||
1548 | return -EINVAL; | ||
1549 | |||
1550 | if (ct) { | ||
1551 | diacr = kmalloc(sizeof(struct kbdiacr) * ct, | ||
1552 | GFP_KERNEL); | ||
1553 | if (diacr == NULL) | ||
1554 | return -ENOMEM; | ||
1555 | |||
1556 | if (copy_from_user(diacr, a->kbdiacr, | ||
1557 | sizeof(struct kbdiacr) * ct)) { | ||
1558 | kfree(diacr); | ||
1559 | return -EFAULT; | ||
1560 | } | ||
1561 | } | ||
1562 | |||
1563 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1564 | accent_table_size = ct; | ||
1565 | for (i = 0; i < ct; i++) { | ||
1566 | accent_table[i].diacr = | ||
1567 | conv_8bit_to_uni(diacr[i].diacr); | ||
1568 | accent_table[i].base = | ||
1569 | conv_8bit_to_uni(diacr[i].base); | ||
1570 | accent_table[i].result = | ||
1571 | conv_8bit_to_uni(diacr[i].result); | ||
1572 | } | ||
1573 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1574 | kfree(diacr); | ||
1575 | return 0; | ||
1576 | } | ||
1577 | |||
1578 | case KDSKBDIACRUC: | ||
1579 | { | ||
1580 | struct kbdiacrsuc __user *a = up; | ||
1581 | unsigned int ct; | ||
1582 | void *buf = NULL; | ||
1583 | |||
1584 | if (!perm) | ||
1585 | return -EPERM; | ||
1586 | |||
1587 | if (get_user(ct, &a->kb_cnt)) | ||
1588 | return -EFAULT; | ||
1589 | |||
1590 | if (ct >= MAX_DIACR) | ||
1591 | return -EINVAL; | ||
1592 | |||
1593 | if (ct) { | ||
1594 | buf = kmalloc(ct * sizeof(struct kbdiacruc), | ||
1595 | GFP_KERNEL); | ||
1596 | if (buf == NULL) | ||
1597 | return -ENOMEM; | ||
1598 | |||
1599 | if (copy_from_user(buf, a->kbdiacruc, | ||
1600 | ct * sizeof(struct kbdiacruc))) { | ||
1601 | kfree(buf); | ||
1602 | return -EFAULT; | ||
1603 | } | ||
1604 | } | ||
1605 | spin_lock_irqsave(&kbd_event_lock, flags); | ||
1606 | if (ct) | ||
1607 | memcpy(accent_table, buf, | ||
1608 | ct * sizeof(struct kbdiacruc)); | ||
1609 | accent_table_size = ct; | ||
1610 | spin_unlock_irqrestore(&kbd_event_lock, flags); | ||
1611 | kfree(buf); | ||
1612 | return 0; | ||
1613 | } | ||
1614 | } | ||
1615 | return ret; | ||
1616 | } | ||
diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index 65447c5f91d7..80af0f9bef5b 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c | |||
@@ -753,89 +753,14 @@ int vt_ioctl(struct tty_struct *tty, | |||
753 | ret = do_kdgkb_ioctl(cmd, up, perm); | 753 | ret = do_kdgkb_ioctl(cmd, up, perm); |
754 | break; | 754 | break; |
755 | 755 | ||
756 | /* Diacritical processing. Handled in keyboard.c as it has | ||
757 | to operate on the keyboard locks and structures */ | ||
756 | case KDGKBDIACR: | 758 | case KDGKBDIACR: |
757 | { | ||
758 | struct kbdiacrs __user *a = up; | ||
759 | struct kbdiacr diacr; | ||
760 | int i; | ||
761 | |||
762 | if (put_user(accent_table_size, &a->kb_cnt)) { | ||
763 | ret = -EFAULT; | ||
764 | break; | ||
765 | } | ||
766 | for (i = 0; i < accent_table_size; i++) { | ||
767 | diacr.diacr = conv_uni_to_8bit(accent_table[i].diacr); | ||
768 | diacr.base = conv_uni_to_8bit(accent_table[i].base); | ||
769 | diacr.result = conv_uni_to_8bit(accent_table[i].result); | ||
770 | if (copy_to_user(a->kbdiacr + i, &diacr, sizeof(struct kbdiacr))) { | ||
771 | ret = -EFAULT; | ||
772 | break; | ||
773 | } | ||
774 | } | ||
775 | break; | ||
776 | } | ||
777 | case KDGKBDIACRUC: | 759 | case KDGKBDIACRUC: |
778 | { | ||
779 | struct kbdiacrsuc __user *a = up; | ||
780 | |||
781 | if (put_user(accent_table_size, &a->kb_cnt)) | ||
782 | ret = -EFAULT; | ||
783 | else if (copy_to_user(a->kbdiacruc, accent_table, | ||
784 | accent_table_size*sizeof(struct kbdiacruc))) | ||
785 | ret = -EFAULT; | ||
786 | break; | ||
787 | } | ||
788 | |||
789 | case KDSKBDIACR: | 760 | case KDSKBDIACR: |
790 | { | ||
791 | struct kbdiacrs __user *a = up; | ||
792 | struct kbdiacr diacr; | ||
793 | unsigned int ct; | ||
794 | int i; | ||
795 | |||
796 | if (!perm) | ||
797 | goto eperm; | ||
798 | if (get_user(ct,&a->kb_cnt)) { | ||
799 | ret = -EFAULT; | ||
800 | break; | ||
801 | } | ||
802 | if (ct >= MAX_DIACR) { | ||
803 | ret = -EINVAL; | ||
804 | break; | ||
805 | } | ||
806 | accent_table_size = ct; | ||
807 | for (i = 0; i < ct; i++) { | ||
808 | if (copy_from_user(&diacr, a->kbdiacr + i, sizeof(struct kbdiacr))) { | ||
809 | ret = -EFAULT; | ||
810 | break; | ||
811 | } | ||
812 | accent_table[i].diacr = conv_8bit_to_uni(diacr.diacr); | ||
813 | accent_table[i].base = conv_8bit_to_uni(diacr.base); | ||
814 | accent_table[i].result = conv_8bit_to_uni(diacr.result); | ||
815 | } | ||
816 | break; | ||
817 | } | ||
818 | |||
819 | case KDSKBDIACRUC: | 761 | case KDSKBDIACRUC: |
820 | { | 762 | ret = vt_do_diacrit(cmd, up, perm); |
821 | struct kbdiacrsuc __user *a = up; | ||
822 | unsigned int ct; | ||
823 | |||
824 | if (!perm) | ||
825 | goto eperm; | ||
826 | if (get_user(ct,&a->kb_cnt)) { | ||
827 | ret = -EFAULT; | ||
828 | break; | ||
829 | } | ||
830 | if (ct >= MAX_DIACR) { | ||
831 | ret = -EINVAL; | ||
832 | break; | ||
833 | } | ||
834 | accent_table_size = ct; | ||
835 | if (copy_from_user(accent_table, a->kbdiacruc, ct*sizeof(struct kbdiacruc))) | ||
836 | ret = -EFAULT; | ||
837 | break; | 763 | break; |
838 | } | ||
839 | 764 | ||
840 | /* the ioctls below read/set the flags usually shown in the leds */ | 765 | /* the ioctls below read/set the flags usually shown in the leds */ |
841 | /* don't use them - they will go away without warning */ | 766 | /* don't use them - they will go away without warning */ |