Skip to content

Commit b371cbb

Browse files
jognesspmladek
authored andcommitted
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. Signed-off-by: John Ogness <[email protected]> Reviewed-by: Petr Mladek <[email protected]> Signed-off-by: Petr Mladek <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 85e3e7f commit b371cbb

File tree

1 file changed

+20
-29
lines changed

1 file changed

+20
-29
lines changed

kernel/printk/printk.c

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ enum log_flags {
356356
};
357357

358358
/* syslog_lock protects syslog_* variables and write access to clear_seq. */
359-
static DEFINE_RAW_SPINLOCK(syslog_lock);
359+
static DEFINE_MUTEX(syslog_lock);
360360

361361
#ifdef CONFIG_PRINTK
362362
DECLARE_WAIT_QUEUE_HEAD(log_wait);
@@ -1497,9 +1497,9 @@ static int syslog_print(char __user *buf, int size)
14971497
size_t n;
14981498
size_t skip;
14991499

1500-
raw_spin_lock_irq(&syslog_lock);
1500+
mutex_lock(&syslog_lock);
15011501
if (!prb_read_valid(prb, syslog_seq, &r)) {
1502-
raw_spin_unlock_irq(&syslog_lock);
1502+
mutex_unlock(&syslog_lock);
15031503
break;
15041504
}
15051505
if (r.info->seq != syslog_seq) {
@@ -1528,7 +1528,7 @@ static int syslog_print(char __user *buf, int size)
15281528
syslog_partial += n;
15291529
} else
15301530
n = 0;
1531-
raw_spin_unlock_irq(&syslog_lock);
1531+
mutex_unlock(&syslog_lock);
15321532

15331533
if (!n)
15341534
break;
@@ -1592,9 +1592,9 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
15921592
}
15931593

15941594
if (clear) {
1595-
raw_spin_lock_irq(&syslog_lock);
1595+
mutex_lock(&syslog_lock);
15961596
latched_seq_write(&clear_seq, seq);
1597-
raw_spin_unlock_irq(&syslog_lock);
1597+
mutex_unlock(&syslog_lock);
15981598
}
15991599

16001600
kfree(text);
@@ -1603,21 +1603,9 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
16031603

16041604
static void syslog_clear(void)
16051605
{
1606-
raw_spin_lock_irq(&syslog_lock);
1606+
mutex_lock(&syslog_lock);
16071607
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);
16211609
}
16221610

16231611
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)
16261614
bool clear = false;
16271615
static int saved_console_loglevel = LOGLEVEL_DEFAULT;
16281616
int error;
1617+
u64 seq;
16291618

16301619
error = check_syslog_permissions(type, source);
16311620
if (error)
@@ -1644,8 +1633,12 @@ int do_syslog(int type, char __user *buf, int len, int source)
16441633
if (!access_ok(buf, len))
16451634
return -EFAULT;
16461635

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));
16491642
if (error)
16501643
return error;
16511644
error = syslog_print(buf, len);
@@ -1693,10 +1686,10 @@ int do_syslog(int type, char __user *buf, int len, int source)
16931686
break;
16941687
/* Number of chars in the log buffer */
16951688
case SYSLOG_ACTION_SIZE_UNREAD:
1696-
raw_spin_lock_irq(&syslog_lock);
1689+
mutex_lock(&syslog_lock);
16971690
if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) {
16981691
/* No unread messages. */
1699-
raw_spin_unlock_irq(&syslog_lock);
1692+
mutex_unlock(&syslog_lock);
17001693
return 0;
17011694
}
17021695
if (info.seq != syslog_seq) {
@@ -1714,7 +1707,6 @@ int do_syslog(int type, char __user *buf, int len, int source)
17141707
} else {
17151708
bool time = syslog_partial ? syslog_time : printk_time;
17161709
unsigned int line_count;
1717-
u64 seq;
17181710

17191711
prb_for_each_info(syslog_seq, prb, seq, &info,
17201712
&line_count) {
@@ -1724,7 +1716,7 @@ int do_syslog(int type, char __user *buf, int len, int source)
17241716
}
17251717
error -= syslog_partial;
17261718
}
1727-
raw_spin_unlock_irq(&syslog_lock);
1719+
mutex_unlock(&syslog_lock);
17281720
break;
17291721
/* Size of the log buffer */
17301722
case SYSLOG_ACTION_SIZE_BUFFER:
@@ -2929,7 +2921,6 @@ static int try_enable_new_console(struct console *newcon, bool user_specified)
29292921
*/
29302922
void register_console(struct console *newcon)
29312923
{
2932-
unsigned long flags;
29332924
struct console *bcon = NULL;
29342925
int err;
29352926

@@ -3034,9 +3025,9 @@ void register_console(struct console *newcon)
30343025
exclusive_console_stop_seq = console_seq;
30353026

30363027
/* Get a consistent copy of @syslog_seq. */
3037-
raw_spin_lock_irqsave(&syslog_lock, flags);
3028+
mutex_lock(&syslog_lock);
30383029
console_seq = syslog_seq;
3039-
raw_spin_unlock_irqrestore(&syslog_lock, flags);
3030+
mutex_unlock(&syslog_lock);
30403031
}
30413032
console_unlock();
30423033
console_sysfs_notify();

0 commit comments

Comments
 (0)