Skip to content

Commit 13791c8

Browse files
jognesspmladek
authored andcommitted
printk: avoid prb_first_valid_seq() where possible
If message sizes average larger than expected (more than 32 characters), the data_ring will wrap before the desc_ring. Once the data_ring wraps, it will start invalidating descriptors. These invalid descriptors hang around until they are eventually recycled when the desc_ring wraps. Readers do not care about invalid descriptors, but they still need to iterate past them. If the average message size is much larger than 32 characters, then there will be many invalid descriptors preceding the valid descriptors. The function prb_first_valid_seq() always begins at the oldest descriptor and searches for the first valid descriptor. This can be rather expensive for the above scenario. And, in fact, because of its heavy usage in /dev/kmsg, there have been reports of long delays and even RCU stalls. For code that does not need to search from the oldest record, replace prb_first_valid_seq() usage with prb_read_valid_*() functions, which provide a start sequence number to search from. Fixes: 896fbe2 ("printk: use the lockless ringbuffer") Reported-by: kernel test robot <[email protected]> Reported-by: J. Avila <[email protected]> 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 9bc284c commit 13791c8

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

kernel/printk/printk.c

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -736,9 +736,9 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
736736
logbuf_lock_irq();
737737
}
738738

739-
if (user->seq < prb_first_valid_seq(prb)) {
739+
if (r->info->seq != user->seq) {
740740
/* our last seen message is gone, return error and reset */
741-
user->seq = prb_first_valid_seq(prb);
741+
user->seq = r->info->seq;
742742
ret = -EPIPE;
743743
logbuf_unlock_irq();
744744
goto out;
@@ -813,6 +813,7 @@ static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence)
813813
static __poll_t devkmsg_poll(struct file *file, poll_table *wait)
814814
{
815815
struct devkmsg_user *user = file->private_data;
816+
struct printk_info info;
816817
__poll_t ret = 0;
817818

818819
if (!user)
@@ -821,9 +822,9 @@ static __poll_t devkmsg_poll(struct file *file, poll_table *wait)
821822
poll_wait(file, &log_wait, wait);
822823

823824
logbuf_lock_irq();
824-
if (prb_read_valid(prb, user->seq, NULL)) {
825+
if (prb_read_valid_info(prb, user->seq, &info, NULL)) {
825826
/* return error when data has vanished underneath us */
826-
if (user->seq < prb_first_valid_seq(prb))
827+
if (info.seq != user->seq)
827828
ret = EPOLLIN|EPOLLRDNORM|EPOLLERR|EPOLLPRI;
828829
else
829830
ret = EPOLLIN|EPOLLRDNORM;
@@ -1560,6 +1561,7 @@ static void syslog_clear(void)
15601561

15611562
int do_syslog(int type, char __user *buf, int len, int source)
15621563
{
1564+
struct printk_info info;
15631565
bool clear = false;
15641566
static int saved_console_loglevel = LOGLEVEL_DEFAULT;
15651567
int error;
@@ -1630,9 +1632,14 @@ int do_syslog(int type, char __user *buf, int len, int source)
16301632
/* Number of chars in the log buffer */
16311633
case SYSLOG_ACTION_SIZE_UNREAD:
16321634
logbuf_lock_irq();
1633-
if (syslog_seq < prb_first_valid_seq(prb)) {
1635+
if (!prb_read_valid_info(prb, syslog_seq, &info, NULL)) {
1636+
/* No unread messages. */
1637+
logbuf_unlock_irq();
1638+
return 0;
1639+
}
1640+
if (info.seq != syslog_seq) {
16341641
/* messages are gone, move to first one */
1635-
syslog_seq = prb_first_valid_seq(prb);
1642+
syslog_seq = info.seq;
16361643
syslog_partial = 0;
16371644
}
16381645
if (source == SYSLOG_FROM_PROC) {
@@ -1644,7 +1651,6 @@ int do_syslog(int type, char __user *buf, int len, int source)
16441651
error = prb_next_seq(prb) - syslog_seq;
16451652
} else {
16461653
bool time = syslog_partial ? syslog_time : printk_time;
1647-
struct printk_info info;
16481654
unsigned int line_count;
16491655
u64 seq;
16501656

@@ -3425,9 +3431,11 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
34253431
goto out;
34263432

34273433
logbuf_lock_irqsave(flags);
3428-
if (dumper->cur_seq < prb_first_valid_seq(prb)) {
3429-
/* messages are gone, move to first available one */
3430-
dumper->cur_seq = prb_first_valid_seq(prb);
3434+
if (prb_read_valid_info(prb, dumper->cur_seq, &info, NULL)) {
3435+
if (info.seq != dumper->cur_seq) {
3436+
/* messages are gone, move to first available one */
3437+
dumper->cur_seq = info.seq;
3438+
}
34313439
}
34323440

34333441
/* last entry */

0 commit comments

Comments
 (0)