@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.
Unified · Split
| @@ -356,7 +356,7 @@ enum log_flags { · 355 unmodified lines | ||
| 356 | 356 | }; |
| 357 | 357 | |
| 358 | 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 | 361 | #ifdef CONFIG_PRINTK |
| 362 | 362 | DECLARE_WAIT_QUEUE_HEAD(log_wait); |
| @@ -1497,9 +1497,9 @@ static int syslog_print(char __user *buf, int size) · 1134 unmodified lines | ||
| 1497 | 1497 | size_t n; |
| 1498 | 1498 | size_t skip; |
| 1499 | 1499 | |
| 1500 | − raw_spin_lock_irq(&syslog_lock); | |
| 1500 | + mutex_lock(&syslog_lock); | |
| 1501 | 1501 | if (!prb_read_valid(prb, syslog_seq, &r)) { |
| 1502 | − raw_spin_unlock_irq(&syslog_lock); | |
| 1502 | + mutex_unlock(&syslog_lock); | |
| 1503 | 1503 | break; |
| 1504 | 1504 | } |
| 1505 | 1505 | if (r.info->seq != syslog_seq) { |
| @@ -1528,7 +1528,7 @@ static int syslog_print(char __user *buf, int size) · 22 unmodified lines | ||
| 1528 | 1528 | syslog_partial += n; |
| 1529 | 1529 | } else |
| 1530 | 1530 | n = 0; |
| 1531 | − raw_spin_unlock_irq(&syslog_lock); | |
| 1531 | + mutex_unlock(&syslog_lock); | |
| 1532 | 1532 | |
| 1533 | 1533 | if (!n) |
| 1534 | 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 | 1594 | if (clear) { |
| 1595 | − raw_spin_lock_irq(&syslog_lock); | |
| 1595 | + mutex_lock(&syslog_lock); | |
| 1596 | 1596 | latched_seq_write(&clear_seq, seq); |
| 1597 | − raw_spin_unlock_irq(&syslog_lock); | |
| 1597 | + mutex_unlock(&syslog_lock); | |
| 1598 | 1598 | } |
| 1599 | 1599 | |
| 1600 | 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 | 1604 | static void syslog_clear(void) |
| 1605 | 1605 | { |
| 1606 | − raw_spin_lock_irq(&syslog_lock); | |
| 1606 | + mutex_lock(&syslog_lock); | |
| 1607 | 1607 | latched_seq_write(&clear_seq, prb_next_seq(prb)); |
| 1608 | − raw_spin_unlock_irq(&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; | |
| 1608 | + mutex_unlock(&syslog_lock); | |
| 1621 | 1609 | } |
| 1622 | 1610 | |
| 1623 | 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 | 1614 | bool clear = false; |
| 1627 | 1615 | static int saved_console_loglevel = LOGLEVEL_DEFAULT; |
| 1628 | 1616 | int error; |
| 1617 | + u64 seq; | |
| 1629 | 1618 | |
| 1630 | 1619 | error = check_syslog_permissions(type, source); |
| 1631 | 1620 | if (error) |
| @@ -1644,8 +1633,12 @@ int do_syslog(int type, char __user *buf, int len, int source) · 12 unmodified lines | ||
| 1644 | 1633 | if (!access_ok(buf, len)) |
| 1645 | 1634 | return -EFAULT; |
| 1646 | 1635 | |
| 1647 | − error = wait_event_interruptible(log_wait, | |
| 1648 | − prb_read_valid(prb, read_syslog_seq_irq(), NULL)); | |
| 1636 | + /* Get a consistent copy of @syslog_seq. */ | |
| 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 | 1642 | if (error) |
| 1650 | 1643 | return error; |
| 1651 | 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 | 1686 | break; |
| 1694 | 1687 | /* Number of chars in the log buffer */ |
| 1695 | 1688 | case SYSLOG_ACTION_SIZE_UNREAD: |
| 1696 | − raw_spin_lock_irq(&syslog_lock); | |
| 1689 | + mutex_lock(&syslog_lock); | |
| 1697 | 1690 | if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) { |
| 1698 | 1691 | /* No unread messages. */ |
| 1699 | − raw_spin_unlock_irq(&syslog_lock); | |
| 1692 | + mutex_unlock(&syslog_lock); | |
| 1700 | 1693 | return 0; |
| 1701 | 1694 | } |
| 1702 | 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 | 1707 | } else { |
| 1715 | 1708 | bool time = syslog_partial ? syslog_time : printk_time; |
| 1716 | 1709 | unsigned int line_count; |
| 1717 | − u64 seq; | |
| 1718 | 1710 | |
| 1719 | 1711 | prb_for_each_info(syslog_seq, prb, seq, &info, |
| 1720 | 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 | 1717 | error -= syslog_partial; |
| 1726 | 1718 | } |
| 1727 | − raw_spin_unlock_irq(&syslog_lock); | |
| 1719 | + mutex_unlock(&syslog_lock); | |
| 1728 | 1720 | break; |
| 1729 | 1721 | /* Size of the log buffer */ |
| 1730 | 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 | 2922 | void register_console(struct console *newcon) |
| 2931 | 2923 | { |
| 2932 | − unsigned long flags; | |
| 2933 | 2924 | struct console *bcon = NULL; |
| 2934 | 2925 | int err; |
| 2935 | 2926 | |
| @@ -3034,9 +3025,9 @@ void register_console(struct console *newcon) · 98 unmodified lines | ||
| 3034 | 3025 | exclusive_console_stop_seq = console_seq; |
| 3035 | 3026 | |
| 3036 | 3027 | /* Get a consistent copy of @syslog_seq. */ |
| 3037 | − raw_spin_lock_irqsave(&syslog_lock, flags); | |
| 3028 | + mutex_lock(&syslog_lock); | |
| 3038 | 3029 | console_seq = syslog_seq; |
| 3039 | − raw_spin_unlock_irqrestore(&syslog_lock, flags); | |
| 3030 | + mutex_unlock(&syslog_lock); | |
| 3040 | 3031 | } |
| 3041 | 3032 | console_unlock(); |
| 3042 | 3033 | console_sysfs_notify(); |