[Devel] [PATCH vz8] ve/printk: Fix printk virtualization
Andrey Ryabinin
aryabinin at virtuozzo.com
Mon Jul 20 14:37:43 MSK 2020
ve_printk() corrupts host's dmesg:
# dmesg|wc -l
599
# vzctl create 101
# vzctl set 101 --netif_add eth0 --save
# vzctl start 101
# vzctl exec 101 'tcpdump -w tcpdump.out -U -n -i eth0 esp'
# dmesg|wc -l
2
Add missing parts of prinkt virtualization to fix this.
https://jira.sw.ru/browse/PSBM-17899
https://jira.sw.ru/browse/PSBM-105442
Fixes: 7c0dae2429 ("ve/printk: printk virtualization")
Signed-off-by: Andrey Ryabinin <aryabinin at virtuozzo.com>
---
kernel/printk/printk.c | 99 ++++++++++++++++++++++++++++--------------
1 file changed, 66 insertions(+), 33 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 4cccbba92b6c..b55fdd7b25ea 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -530,23 +530,23 @@ static char *log_dict(const struct printk_log *msg)
}
/* get record by index; idx must point to valid msg */
-static struct printk_log *log_from_idx(u32 idx)
+static struct printk_log *log_from_idx(struct log_state *log, u32 idx)
{
- struct printk_log *msg = (struct printk_log *)(log_buf + idx);
+ struct printk_log *msg = (struct printk_log *)(log->buf + idx);
/*
* A length == 0 record is the end of buffer marker. Wrap around and
* read the message at the start of the buffer.
*/
if (!msg->len)
- return (struct printk_log *)log_buf;
+ return (struct printk_log *)log->buf;
return msg;
}
/* get next record; idx must point to valid msg */
-static u32 log_next(u32 idx)
+static u32 log_next(struct log_state *log, u32 idx)
{
- struct printk_log *msg = (struct printk_log *)(log_buf + idx);
+ struct printk_log *msg = (struct printk_log *)(log->buf + idx);
/* length == 0 indicates the end of the buffer; wrap */
/*
@@ -555,7 +555,7 @@ static u32 log_next(u32 idx)
* return the one after that.
*/
if (!msg->len) {
- msg = (struct printk_log *)log_buf;
+ msg = (struct printk_log *)log->buf;
return msg->len;
}
return idx + msg->len;
@@ -593,7 +593,7 @@ static int log_make_free_space(struct log_state *log,
while (log->first_seq < log->next_seq &&
!logbuf_has_space(log, msg_size, false)) {
/* drop old messages until we have enough contiguous space */
- log->first_idx = log_next(log->first_idx);
+ log->first_idx = log_next(log, log->first_idx);
log->first_seq++;
}
@@ -677,12 +677,12 @@ static int log_store(struct log_state *log,
* at the end of the buffer. Add an empty header with len == 0
* to signify a wrap around.
*/
- memset(log_buf + log->next_idx, 0, sizeof(struct printk_log));
+ memset(log->buf + log->next_idx, 0, sizeof(struct printk_log));
log->next_idx = 0;
}
/* fill message */
- msg = (struct printk_log *)(log_buf + log->next_idx);
+ msg = (struct printk_log *)(log->buf + log->next_idx);
memcpy(log_text(msg), text, text_len);
msg->text_len = text_len;
if (trunc_msg_len) {
@@ -930,14 +930,14 @@ static ssize_t devkmsg_read(struct file *file, char __user *buf,
goto out;
}
- msg = log_from_idx(user->idx);
+ msg = log_from_idx(log, user->idx);
len = msg_print_ext_header(user->buf, sizeof(user->buf),
msg, user->seq);
len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len,
log_dict(msg), msg->dict_len,
log_text(msg), msg->text_len);
- user->idx = log_next(user->idx);
+ user->idx = log_next(log, user->idx);
user->seq++;
logbuf_unlock_irq();
@@ -1389,11 +1389,11 @@ static int syslog_print(struct log_state *log,
}
skip = log->syslog_partial;
- msg = log_from_idx(log->syslog_idx);
+ msg = log_from_idx(log, log->syslog_idx);
n = msg_print_text(msg, true, text, LOG_LINE_MAX + PREFIX_MAX);
if (n - log->syslog_partial <= size) {
/* message fits into buffer, move forward */
- log->syslog_idx = log_next(log->syslog_idx);
+ log->syslog_idx = log_next(log, log->syslog_idx);
log->syslog_seq++;
n -= log->syslog_partial;
log->syslog_partial = 0;
@@ -1446,10 +1446,10 @@ static int syslog_print_all(struct log_state *log,
seq = log->clear_seq;
idx = log->clear_idx;
while (seq < log->next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
len += msg_print_text(msg, true, NULL, 0);
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
}
@@ -1457,10 +1457,10 @@ static int syslog_print_all(struct log_state *log,
seq = log->clear_seq;
idx = log->clear_idx;
while (len > size && seq < log->next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
len -= msg_print_text(msg, true, NULL, 0);
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
}
@@ -1469,7 +1469,7 @@ static int syslog_print_all(struct log_state *log,
len = 0;
while (len >= 0 && seq < next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
int textlen;
textlen = msg_print_text(msg, true, text,
@@ -1478,7 +1478,7 @@ static int syslog_print_all(struct log_state *log,
len = textlen;
break;
}
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
logbuf_unlock_irq();
@@ -1597,10 +1597,10 @@ int do_syslog(int type, char __user *buf, int len, int source)
u32 idx = log->syslog_idx;
while (seq < log->next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
error += msg_print_text(msg, true, NULL, 0);
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
}
error -= log->syslog_partial;
@@ -1892,6 +1892,20 @@ static size_t log_output(struct log_state *log,
return log_store(log, facility, level, lflags, 0, dict, dictlen, text, text_len);
}
+static int log_state_init(struct log_state *log)
+{
+#ifdef CONFIG_VE
+ if (log->buf)
+ return 0;
+
+ log->buf = kzalloc(log->buf_len, GFP_ATOMIC);
+ if (!log->buf)
+ return -ENOMEM;
+#endif
+ return 0;
+}
+
+
asmlinkage int vprintk_emit_log(struct log_state *log,
int facility, int level,
const char *dict, size_t dictlen,
@@ -1904,6 +1918,8 @@ asmlinkage int vprintk_emit_log(struct log_state *log,
unsigned long flags;
int printed_len;
bool in_sched = false;
+ bool need_wake = false;
+ int err;
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
@@ -1915,6 +1931,13 @@ asmlinkage int vprintk_emit_log(struct log_state *log,
/* This stops the holder of console_sem just where we want him */
logbuf_lock_irqsave(flags);
+
+ err = log_state_init(log);
+ if (err) {
+ logbuf_unlock_irqrestore(flags);
+ return err;
+ }
+
/*
* The printf needs to come first; we need the syslog
* prefix which might be passed-in as a parameter.
@@ -1972,9 +1995,19 @@ asmlinkage int vprintk_emit_log(struct log_state *log,
* semaphore. The release will print out buffers and wake up
* /dev/kmsg and syslog() users.
*/
- if (console_trylock_spinning())
+ if (log != &init_log_state) {
+ logbuf_lock_irqsave(flags);
+ if (log->seen_seq != log->next_seq && !oops_in_progress) {
+ log->seen_seq = log->next_seq;
+ need_wake = true;
+ }
+ logbuf_unlock_irqrestore(flags);
+ } else if (console_trylock_spinning())
console_unlock();
preempt_enable();
+
+ if (need_wake)
+ wake_up_interruptible(&log->wait);
}
wake_up_klogd();
@@ -2465,14 +2498,14 @@ void console_unlock(void)
if (log->console_seq == log->next_seq)
break;
- msg = log_from_idx(log->console_idx);
+ msg = log_from_idx(log, log->console_idx);
if (suppress_message_printing(msg->level)) {
/*
* Skip record we have buffered and already printed
* directly to the console when we received it, and
* record that has level above the console loglevel.
*/
- log->console_idx = log_next(log->console_idx);
+ log->console_idx = log_next(log, log->console_idx);
log->console_seq++;
goto skip;
}
@@ -2490,7 +2523,7 @@ void console_unlock(void)
log_dict(msg), msg->dict_len,
log_text(msg), msg->text_len);
}
- log->console_idx = log_next(log->console_idx);
+ log->console_idx = log_next(log, log->console_idx);
log->console_seq++;
raw_spin_unlock(&logbuf_lock);
@@ -3200,10 +3233,10 @@ bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog,
if (dumper->cur_seq >= log->next_seq)
goto out;
- msg = log_from_idx(dumper->cur_idx);
+ msg = log_from_idx(log, dumper->cur_idx);
l = msg_print_text(msg, syslog, line, size);
- dumper->cur_idx = log_next(dumper->cur_idx);
+ dumper->cur_idx = log_next(log, dumper->cur_idx);
dumper->cur_seq++;
ret = true;
out:
@@ -3294,10 +3327,10 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
seq = dumper->cur_seq;
idx = dumper->cur_idx;
while (seq < dumper->next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
l += msg_print_text(msg, true, NULL, 0);
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
}
@@ -3305,10 +3338,10 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
seq = dumper->cur_seq;
idx = dumper->cur_idx;
while (l > size && seq < dumper->next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
l -= msg_print_text(msg, true, NULL, 0);
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
}
@@ -3318,10 +3351,10 @@ bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog,
l = 0;
while (seq < dumper->next_seq) {
- struct printk_log *msg = log_from_idx(idx);
+ struct printk_log *msg = log_from_idx(log, idx);
l += msg_print_text(msg, syslog, buf + l, size - l);
- idx = log_next(idx);
+ idx = log_next(log, idx);
seq++;
}
--
2.26.2
More information about the Devel
mailing list