History

printk: convert @syslog_lock to mutex

@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.

John Ogness committed 5 years ago

Commit b371cbb1 parent 85e3e7f1 file · +20 −29Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/printk/printk.c+20−29
@@ -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. */
359static DEFINE_RAW_SPINLOCK(syslog_lock);359static DEFINE_MUTEX(syslog_lock);
360 360
361#ifdef CONFIG_PRINTK361#ifdef CONFIG_PRINTK
362DECLARE_WAIT_QUEUE_HEAD(log_wait);362DECLARE_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 } else1529 } 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
1604static void syslog_clear(void)1604static 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. */
1612static 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
1623int do_syslog(int type, char __user *buf, int len, int source)1611int 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 */
2930void register_console(struct console *newcon)2922void 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();

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t