@syslog_lock was a raw_spin_lock to simplify the transition of removing @logbuf_lock and the safe buffers. With that transition complete, and since all uses of @syslog_lock are within sleepable contexts, @syslog_lock can become a mutex. Note that until now register_console() would disable interrupts using irqsave, which implies that it may be called with interrupts disabled. And indeed, there is one possible call chain on parisc where this happens: handle_interruption(code=1) /* High-priority machine check (HPMC) */ pdc_console_restart() pdc_console_init_force() register_console() However, register_console() calls console_lock(), which might sleep. So it has never been allowed to call register_console() from an atomic context and the above call chain is a bug. Note that the removal of read_syslog_seq_irq() is slightly changing the behavior of SYSLOG_ACTION_READ by testing against a possibly outdated @seq value. However, the value of @seq could have changed after the test, so it is not a new window. A follow-up commit closes this window.
Showing the changes to kernel (1 of 1 file). Show all
Unified · Split
| @@ -356,7 +356,7 @@ enum log_flags { · 355 unmodified lines | |||
| 356 | }; | 356 | }; |
| 357 | 357 | ||
| 358 | /* syslog_lock protects syslog_* variables and write access to clear_seq. */ | 358 | /* syslog_lock protects syslog_* variables and write access to clear_seq. */ |
| 359 | static DEFINE_RAW_SPINLOCK(syslog_lock); | 359 | static DEFINE_MUTEX(syslog_lock); |
| 360 | 360 | ||
| 361 | #ifdef CONFIG_PRINTK | 361 | #ifdef CONFIG_PRINTK |
| 362 | DECLARE_WAIT_QUEUE_HEAD(log_wait); | 362 | DECLARE_WAIT_QUEUE_HEAD(log_wait); |
| @@ -1497,9 +1497,9 @@ static int syslog_print(char __user *buf, int size) · 1134 unmodified lines | |||
| 1497 | size_t n; | 1497 | size_t n; |
| 1498 | size_t skip; | 1498 | size_t skip; |
| 1499 | 1499 | ||
| 1500 | raw_spin_lock_irq(&syslog_lock); | 1500 | mutex_lock(&syslog_lock); |
| 1501 | if (!prb_read_valid(prb, syslog_seq, &r)) { | 1501 | if (!prb_read_valid(prb, syslog_seq, &r)) { |
| 1502 | raw_spin_unlock_irq(&syslog_lock); | 1502 | mutex_unlock(&syslog_lock); |
| 1503 | break; | 1503 | break; |
| 1504 | } | 1504 | } |
| 1505 | if (r.info->seq != syslog_seq) { | 1505 | if (r.info->seq != syslog_seq) { |
| @@ -1528,7 +1528,7 @@ static int syslog_print(char __user *buf, int size) · 22 unmodified lines | |||
| 1528 | syslog_partial += n; | 1528 | syslog_partial += n; |
| 1529 | } else | 1529 | } else |
| 1530 | n = 0; | 1530 | n = 0; |
| 1531 | raw_spin_unlock_irq(&syslog_lock); | 1531 | mutex_unlock(&syslog_lock); |
| 1532 | 1532 | ||
| 1533 | if (!n) | 1533 | if (!n) |
| 1534 | break; | 1534 | break; |
| @@ -1592,9 +1592,9 @@ static int syslog_print_all(char __user *buf, int size, bool clear) · 57 unmodified lines | |||
| 1592 | } | 1592 | } |
| 1593 | 1593 | ||
| 1594 | if (clear) { | 1594 | if (clear) { |
| 1595 | raw_spin_lock_irq(&syslog_lock); | 1595 | mutex_lock(&syslog_lock); |
| 1596 | latched_seq_write(&clear_seq, seq); | 1596 | latched_seq_write(&clear_seq, seq); |
| 1597 | raw_spin_unlock_irq(&syslog_lock); | 1597 | mutex_unlock(&syslog_lock); |
| 1598 | } | 1598 | } |
| 1599 | 1599 | ||
| 1600 | kfree(text); | 1600 | kfree(text); |
| @@ -1603,21 +1603,9 @@ static int syslog_print_all(char __user *buf, int size, bool clear) · 2 unmodified lines | |||
| 1603 | 1603 | ||
| 1604 | static void syslog_clear(void) | 1604 | static void syslog_clear(void) |
| 1605 | { | 1605 | { |
| 1606 | raw_spin_lock_irq(&syslog_lock); | 1606 | mutex_lock(&syslog_lock); |
| 1607 | latched_seq_write(&clear_seq, prb_next_seq(prb)); | 1607 | latched_seq_write(&clear_seq, prb_next_seq(prb)); |
| 1608 | raw_spin_unlock_irq(&syslog_lock); | 1608 | mutex_unlock(&syslog_lock); |
| 1609 | } | ||
| 1610 | |||
| 1611 | /* Return a consistent copy of @syslog_seq. */ | ||
| 1612 | static u64 read_syslog_seq_irq(void) | ||
| 1613 | { | ||
| 1614 | u64 seq; | ||
| 1615 | |||
| 1616 | raw_spin_lock_irq(&syslog_lock); | ||
| 1617 | seq = syslog_seq; | ||
| 1618 | raw_spin_unlock_irq(&syslog_lock); | ||
| 1619 | |||
| 1620 | return seq; | ||
| 1621 | } | 1609 | } |
| 1622 | 1610 | ||
| 1623 | int do_syslog(int type, char __user *buf, int len, int source) | 1611 | int do_syslog(int type, char __user *buf, int len, int source) |
| @@ -1626,6 +1614,7 @@ int do_syslog(int type, char __user *buf, int len, int source) · 2 unmodified lines | |||
| 1626 | bool clear = false; | 1614 | bool clear = false; |
| 1627 | static int saved_console_loglevel = LOGLEVEL_DEFAULT; | 1615 | static int saved_console_loglevel = LOGLEVEL_DEFAULT; |
| 1628 | int error; | 1616 | int error; |
| 1617 | u64 seq; | ||
| 1629 | 1618 | ||
| 1630 | error = check_syslog_permissions(type, source); | 1619 | error = check_syslog_permissions(type, source); |
| 1631 | if (error) | 1620 | if (error) |
| @@ -1644,8 +1633,12 @@ int do_syslog(int type, char __user *buf, int len, int source) · 12 unmodified lines | |||
| 1644 | if (!access_ok(buf, len)) | 1633 | if (!access_ok(buf, len)) |
| 1645 | return -EFAULT; | 1634 | return -EFAULT; |
| 1646 | 1635 | ||
| 1647 | error = wait_event_interruptible(log_wait, | 1636 | /* Get a consistent copy of @syslog_seq. */ |
| 1648 | prb_read_valid(prb, read_syslog_seq_irq(), NULL)); | 1637 | mutex_lock(&syslog_lock); |
| 1638 | seq = syslog_seq; | ||
| 1639 | mutex_unlock(&syslog_lock); | ||
| 1640 | |||
| 1641 | error = wait_event_interruptible(log_wait, prb_read_valid(prb, seq, NULL)); | ||
| 1649 | if (error) | 1642 | if (error) |
| 1650 | return error; | 1643 | return error; |
| 1651 | error = syslog_print(buf, len); | 1644 | error = syslog_print(buf, len); |
| @@ -1693,10 +1686,10 @@ int do_syslog(int type, char __user *buf, int len, int source) · 41 unmodified lines | |||
| 1693 | break; | 1686 | break; |
| 1694 | /* Number of chars in the log buffer */ | 1687 | /* Number of chars in the log buffer */ |
| 1695 | case SYSLOG_ACTION_SIZE_UNREAD: | 1688 | case SYSLOG_ACTION_SIZE_UNREAD: |
| 1696 | raw_spin_lock_irq(&syslog_lock); | 1689 | mutex_lock(&syslog_lock); |
| 1697 | if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) { | 1690 | if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) { |
| 1698 | /* No unread messages. */ | 1691 | /* No unread messages. */ |
| 1699 | raw_spin_unlock_irq(&syslog_lock); | 1692 | mutex_unlock(&syslog_lock); |
| 1700 | return 0; | 1693 | return 0; |
| 1701 | } | 1694 | } |
| 1702 | if (info.seq != syslog_seq) { | 1695 | if (info.seq != syslog_seq) { |
| @@ -1714,7 +1707,6 @@ int do_syslog(int type, char __user *buf, int len, int source) · 11 unmodified lines | |||
| 1714 | } else { | 1707 | } else { |
| 1715 | bool time = syslog_partial ? syslog_time : printk_time; | 1708 | bool time = syslog_partial ? syslog_time : printk_time; |
| 1716 | unsigned int line_count; | 1709 | unsigned int line_count; |
| 1717 | u64 seq; | ||
| 1718 | 1710 | ||
| 1719 | prb_for_each_info(syslog_seq, prb, seq, &info, | 1711 | prb_for_each_info(syslog_seq, prb, seq, &info, |
| 1720 | &line_count) { | 1712 | &line_count) { |
| @@ -1724,7 +1716,7 @@ int do_syslog(int type, char __user *buf, int len, int source) · 3 unmodified lines | |||
| 1724 | } | 1716 | } |
| 1725 | error -= syslog_partial; | 1717 | error -= syslog_partial; |
| 1726 | } | 1718 | } |
| 1727 | raw_spin_unlock_irq(&syslog_lock); | 1719 | mutex_unlock(&syslog_lock); |
| 1728 | break; | 1720 | break; |
| 1729 | /* Size of the log buffer */ | 1721 | /* Size of the log buffer */ |
| 1730 | case SYSLOG_ACTION_SIZE_BUFFER: | 1722 | case SYSLOG_ACTION_SIZE_BUFFER: |
| @@ -2929,7 +2921,6 @@ static int try_enable_new_console(struct console *newcon, bool user_specified) · 1198 unmodified lines | |||
| 2929 | */ | 2921 | */ |
| 2930 | void register_console(struct console *newcon) | 2922 | void register_console(struct console *newcon) |
| 2931 | { | 2923 | { |
| 2932 | unsigned long flags; | ||
| 2933 | struct console *bcon = NULL; | 2924 | struct console *bcon = NULL; |
| 2934 | int err; | 2925 | int err; |
| 2935 | 2926 | ||
| @@ -3034,9 +3025,9 @@ void register_console(struct console *newcon) · 98 unmodified lines | |||
| 3034 | exclusive_console_stop_seq = console_seq; | 3025 | exclusive_console_stop_seq = console_seq; |
| 3035 | 3026 | ||
| 3036 | /* Get a consistent copy of @syslog_seq. */ | 3027 | /* Get a consistent copy of @syslog_seq. */ |
| 3037 | raw_spin_lock_irqsave(&syslog_lock, flags); | 3028 | mutex_lock(&syslog_lock); |
| 3038 | console_seq = syslog_seq; | 3029 | console_seq = syslog_seq; |
| 3039 | raw_spin_unlock_irqrestore(&syslog_lock, flags); | 3030 | mutex_unlock(&syslog_lock); |
| 3040 | } | 3031 | } |
| 3041 | console_unlock(); | 3032 | console_unlock(); |
| 3042 | console_sysfs_notify(); | 3033 | console_sysfs_notify(); |