Skip to content
Permalink
Browse files
printk: implement pr_cont_t
Implement a new buffering mechanism for pr_cont messages.

Old mechanism syntax:

    printk(KERN_INFO "text");
    printk(KERN_CONT " continued");
    printk(KERN_CONT "\n");

New mechanism syntax:

    pr_cont_t c;

    pr_cont_begin(&c, KERN_INFO "text");
    pr_cont_append(&c, " continued");
    pr_cont_end(&c);

Signed-off-by: John Ogness <john.ogness@linutronix.de>
  • Loading branch information
jogness authored and intel-lab-lkp committed Aug 19, 2020
1 parent 377c0d7 commit 2b9bfd8702672aa1b375a495f3286a277ebf7736
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
@@ -380,6 +380,25 @@ extern int kptr_restrict;
#define pr_cont(fmt, ...) \
printk(KERN_CONT fmt, ##__VA_ARGS__)

/* opaque handle for continuous printk messages */
typedef struct {
u8 index;
u8 loglevel;
u16 text_len;
} pr_cont_t;

/* initialize handle, provide loglevel and initial message text */
int pr_cont_begin(pr_cont_t *c, const char *fmt, ...);

/* append message text */
int pr_cont_append(pr_cont_t *c, const char *fmt, ...);

/* flush message to kernel buffer */
void pr_cont_flush(pr_cont_t *c);

/* flush message to kernel buffer, cleanup handle */
void pr_cont_end(pr_cont_t *c);

/**
* pr_devel - Print a debug-level message conditionally
* @fmt: format string
@@ -3453,3 +3453,140 @@ void kmsg_dump_rewind(struct kmsg_dumper *dumper)
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);

#endif

#define CONT_LINE_MAX LOG_LINE_MAX
#define CONT_BUF_COUNT 10
static char cont_buf[CONT_BUF_COUNT][CONT_LINE_MAX];
static DECLARE_BITMAP(cont_buf_map, CONT_BUF_COUNT);

static int get_cont_buf(void)
{
int bit;

do {
bit = find_first_zero_bit(cont_buf_map, CONT_BUF_COUNT);
if (bit == CONT_BUF_COUNT)
break;
} while (test_and_set_bit(bit, cont_buf_map));

return bit;
}

static void put_cont_buf(int index)
{
if (WARN_ON(index >= CONT_BUF_COUNT))
return;
if (WARN_ON(!test_bit(index, cont_buf_map)))
return;
clear_bit(index, cont_buf_map);
}

/* alloc buffer, get loglevel, setup initial text */
int pr_cont_begin(pr_cont_t *c, const char *fmt, ...)
{
int kern_level;
va_list args;
char *text;

c->index = get_cont_buf();
if (c->index == CONT_BUF_COUNT) {
/* Fallback to printk parts individually. */
int text_len;

va_start(args, fmt);
text_len = vprintk(fmt, args);
va_end(args);
return text_len;
}

text = &cont_buf[c->index][0];

va_start(args, fmt);
c->text_len = vscnprintf(text, CONT_LINE_MAX, fmt, args);
va_end(args);

c->loglevel = default_message_loglevel;
while (c->text_len > 1 &&
(kern_level = printk_get_level(text)) != 0) {
switch (kern_level) {
case '0' ... '7':
c->loglevel = kern_level - '0';
break;
}

c->text_len -= 2;
memmove(text, text + 2, c->text_len);
}

return c->text_len;
}

/* printk existing buffer, reset buffer */
void pr_cont_flush(pr_cont_t *c)
{
char *text;

if (c->index == CONT_BUF_COUNT || !c->text_len)
return;

text = &cont_buf[c->index][0];

printk("%c%c%s\n", KERN_SOH_ASCII, c->loglevel + '0', text);

c->text_len = 0;
}

/* printk existing buffer, free buffer */
void pr_cont_end(pr_cont_t *c)
{
if (c->index == CONT_BUF_COUNT)
return;

pr_cont_flush(c);
put_cont_buf(c->index);
c->index = CONT_BUF_COUNT;
}

/* append to buffer */
int pr_cont_append(pr_cont_t *c, const char *fmt, ...)
{
va_list args_copy;
va_list args;
int text_len;
char *text;

if (c->index == CONT_BUF_COUNT) {
/* Fallback to printk parts individually. */
va_start(args, fmt);
text_len = vprintk(fmt, args);
va_end(args);
return text_len;
}

text = &cont_buf[c->index][0];

/* Try to append directly. */
va_start(args, fmt);
va_copy(args_copy, args);
text_len = vsnprintf(text + c->text_len, CONT_LINE_MAX - c->text_len, fmt, args);
va_end(args);

if (text_len >= CONT_LINE_MAX - c->text_len) {
/*
* Not enough space remaining. Set the overwritten terminator,
* Flush any existing parts and start with a clean buffer.
* The loglevel is preserved.
*/

text[c->text_len] = 0;
pr_cont_flush(c);

va_start(args_copy, fmt);
c->text_len = vscnprintf(text, CONT_LINE_MAX, fmt, args_copy);
va_end(args_copy);
return c->text_len;
}

c->text_len += text_len;
return text_len;
}

0 comments on commit 2b9bfd8

Please sign in to comment.