The commit is pushed to "branch-rh9-5.14.vz9.1.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git after ark-5.14 ------> commit 2a9c7bf672a7769150cb0618868ebee20116ac72 Author: Vladimir Davydov <vdavydov....@gmail.com> Date: Wed Sep 29 19:45:53 2021 +0300
ve/printk: Introduce struct "log_state" and virtualize log_buf/log_buf_len https://jira.sw.ru/browse/PSBM-17899 Signed-off-by: Vladimir Davydov <vdavy...@parallels.com> Signed-off-by: Stanislav Kinsburskiy <skinsbur...@virtuozzo.com> +++ ve/printk: Fix printk virtualization 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 Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com> Rebasing to vz9: part of vz8 commit: d63aeb311a64 ("ve/printk: printk virtualization") https://jira.sw.ru/browse/PSBM-133985 Signed-off-by: Konstantin Khorenko <khore...@virtuozzo.com> --- include/linux/printk.h | 13 ++++ include/linux/ve.h | 3 + kernel/printk/printk.c | 165 +++++++++++++++++++++++++++++++++++++++++-------- kernel/ve/ve.c | 8 +++ 4 files changed, 164 insertions(+), 25 deletions(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index e834d78f0478..f178e2e5d7f5 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -176,6 +176,10 @@ int vprintk(const char *fmt, va_list args); asmlinkage __printf(1, 2) __cold int printk(const char *fmt, ...); +struct ve_struct; +int ve_log_init(struct ve_struct *ve); +void ve_log_destroy(struct ve_struct *ve); + /* * Special printk facility for scheduler/timekeeping use only, _DO_NOT_USE_ ! */ @@ -222,6 +226,15 @@ int printk(const char *s, ...) { return 0; } +static inline +int ve_log_init(struct ve_struct *ve) +{ + return 0; +} +static inline +void ve_log_destroy(struct ve_struct *ve) +{ +} static inline __printf(1, 2) __cold int printk_deferred(const char *s, ...) { diff --git a/include/linux/ve.h b/include/linux/ve.h index 248cdeb0a2e4..552fa577e2f9 100644 --- a/include/linux/ve.h +++ b/include/linux/ve.h @@ -50,6 +50,9 @@ struct ve_struct { /* see vzcalluser.h for VE_FEATURE_XXX definitions */ __u64 features; + void *log_state; +#define VE_LOG_BUF_LEN 4096 + struct kstat_lat_pcpu_struct sched_lat_ve; struct kmapset_key sysfs_perms_key; diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index 142a58d124d9..77e6787c752e 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -44,6 +44,7 @@ #include <linux/irq_work.h> #include <linux/ctype.h> #include <linux/uio.h> +#include <linux/ve.h> #include <linux/sched/clock.h> #include <linux/sched/debug.h> #include <linux/sched/task_stack.h> @@ -408,8 +409,6 @@ static struct latched_seq clear_seq = { #define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) #define LOG_BUF_LEN_MAX (u32)(1 << 31) static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); -static char *log_buf = __log_buf; -static u32 log_buf_len = __LOG_BUF_LEN; /* * Define the average message size. This only affects the number of @@ -427,6 +426,34 @@ _DEFINE_PRINTKRB(printk_rb_static, CONFIG_LOG_BUF_SHIFT - PRB_AVGBITS, static struct printk_ringbuffer printk_rb_dynamic; static struct printk_ringbuffer *prb = &printk_rb_static; +static struct log_state { + char *buf; + u32 buf_len; +} init_log_state = { + .buf = __log_buf, + .buf_len = __LOG_BUF_LEN, +}; + +/* kdump relies on some log_* symbols, let's make it happy */ +#define DEFINE_STRUCT_MEMBER_ALIAS(name, inst, memb) \ +static void ____ ## name ## _definition(void) __attribute__((used)); \ +static void ____ ## name ## _definition(void) \ +{ \ + asm (".globl " #name "\n\t.set " #name ", " #inst "+%c0" \ + : : "g" (offsetof(typeof(inst), memb))); \ +} \ +extern typeof(inst.memb) name; +#undef DEFINE_STRUCT_MEMBER_ALIAS + +static inline struct log_state *ve_log_state(void) +{ + struct log_state *log = &init_log_state; +#ifdef CONFIG_VE + if (get_exec_env()->log_state) + log = get_exec_env()->log_state; +#endif + return log; +} /* * We cannot access per-CPU data (e.g. per-CPU flush irq_work) before @@ -468,13 +495,13 @@ static u64 latched_seq_read_nolock(struct latched_seq *ls) /* Return log buffer address */ char *log_buf_addr_get(void) { - return log_buf; + return init_log_state.buf; } /* Return log buffer size */ u32 log_buf_len_get(void) { - return log_buf_len; + return init_log_state.buf_len; } /* @@ -485,13 +512,14 @@ u32 log_buf_len_get(void) #define MAX_LOG_TAKE_PART 4 static const char trunc_msg[] = "<truncated>"; -static void truncate_msg(u16 *text_len, u16 *trunc_msg_len) +static void truncate_msg(struct log_state *log, + u16 *text_len, u16 *trunc_msg_len) { /* * The message should not take the whole buffer. Otherwise, it might * get removed too soon. */ - u32 max_text_len = log_buf_len / MAX_LOG_TAKE_PART; + u32 max_text_len = log->buf_len / MAX_LOG_TAKE_PART; if (*text_len > max_text_len) *text_len = max_text_len; @@ -642,14 +670,20 @@ struct devkmsg_user { struct printk_record record; }; -static __printf(3, 4) __cold -int devkmsg_emit(int facility, int level, const char *fmt, ...) +asmlinkage int vprintk_emit_log(struct log_state *log, + int facility, int level, + const struct dev_printk_info *dev_info, + const char *fmt, va_list args); + +static __printf(4, 5) __cold +int devkmsg_emit_log(struct log_state *log, int facility, int level, + const char *fmt, ...) { va_list args; int r; va_start(args, fmt); - r = vprintk_emit(facility, level, NULL, fmt, args); + r = vprintk_emit_log(log, facility, level, NULL, fmt, args); va_end(args); return r; @@ -657,6 +691,7 @@ int devkmsg_emit(int facility, int level, const char *fmt, ...) static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) { + struct log_state *log = ve_log_state(); char *buf, *line; int level = default_message_loglevel; int facility = 1; /* LOG_USER */ @@ -712,7 +747,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) } } - devkmsg_emit(facility, level, "%s", line); + devkmsg_emit_log(log, facility, level, "%s", line); kfree(buf); return ret; } @@ -987,11 +1022,11 @@ static void __init log_buf_len_update(u64 size) if (size) size = roundup_pow_of_two(size); - if (size > log_buf_len) + if (size > init_log_state.buf_len) new_log_buf_len = (unsigned long)size; } -/* save requested log_buf_len since it's too early to process it */ +/* save requested log->buf_len since it's too early to process it */ static int __init log_buf_len_setup(char *str) { u64 size; @@ -1077,6 +1112,7 @@ static char setup_text_buf[LOG_LINE_MAX] __initdata; void __init setup_log_buf(int early) { + struct log_state *log = &init_log_state; struct printk_info *new_infos; unsigned int new_descs_count; struct prb_desc *new_descs; @@ -1097,7 +1133,7 @@ void __init setup_log_buf(int early) if (!early) set_percpu_data_ready(); - if (log_buf != __log_buf) + if (log->buf != __log_buf) return; if (!early && !new_log_buf_len) @@ -1144,8 +1180,8 @@ void __init setup_log_buf(int early) printk_safe_enter_irqsave(flags); - log_buf_len = new_log_buf_len; - log_buf = new_log_buf; + log->buf_len = new_log_buf_len; + log->buf = new_log_buf; new_log_buf_len = 0; free = __LOG_BUF_LEN; @@ -1166,7 +1202,7 @@ void __init setup_log_buf(int early) prb_next_seq(&printk_rb_static) - seq); } - pr_info("log_buf_len: %u bytes\n", log_buf_len); + pr_info("log_buf_len: %u bytes\n", log->buf_len); pr_info("early log buf free: %u(%u%%)\n", free, (free * 100) / __LOG_BUF_LEN); return; @@ -1632,6 +1668,7 @@ static u64 read_syslog_seq_irq(void) int do_syslog(int type, char __user *buf, int len, int source) { + struct log_state *log = ve_log_state(); struct printk_info info; bool clear = false; static int saved_console_loglevel = LOGLEVEL_DEFAULT; @@ -1741,7 +1778,7 @@ int do_syslog(int type, char __user *buf, int len, int source) break; /* Size of the log buffer */ case SYSLOG_ACTION_SIZE_BUFFER: - error = log_buf_len; + error = log->buf_len; break; default: error = -EINVAL; @@ -2031,8 +2068,8 @@ static u16 printk_sprint(char *text, u16 size, int facility, enum log_flags *lfl return text_len; } -__printf(4, 0) -int vprintk_store(int facility, int level, +__printf(5, 0) +int vprintk_store_log(struct log_state *log, int facility, int level, const struct dev_printk_info *dev_info, const char *fmt, va_list args) { @@ -2104,7 +2141,7 @@ int vprintk_store(int facility, int level, prb_rec_init_wr(&r, reserve_size); if (!prb_reserve(&e, prb, &r)) { /* truncate the message if it is too long for empty buffer */ - truncate_msg(&reserve_size, &trunc_msg_len); + truncate_msg(log, &reserve_size, &trunc_msg_len); prb_rec_init_wr(&r, reserve_size + trunc_msg_len); if (!prb_reserve(&e, prb, &r)) @@ -2133,9 +2170,18 @@ int vprintk_store(int facility, int level, return (text_len + trunc_msg_len); } -asmlinkage int vprintk_emit(int facility, int level, - const struct dev_printk_info *dev_info, - const char *fmt, va_list args) +int vprintk_store(int facility, int level, + const struct dev_printk_info *dev_info, + const char *fmt, va_list args) +{ + return vprintk_store_log(&init_log_state, facility, level, + dev_info, fmt, args); +} + +asmlinkage int vprintk_emit_log(struct log_state *log, + int facility, int level, + const struct dev_printk_info *dev_info, + const char *fmt, va_list args) { int printed_len; bool in_sched = false; @@ -2154,7 +2200,7 @@ asmlinkage int vprintk_emit(int facility, int level, printk_delay(); printk_safe_enter_irqsave(flags); - printed_len = vprintk_store(facility, level, dev_info, fmt, args); + printed_len = vprintk_store_log(log, facility, level, dev_info, fmt, args); printk_safe_exit_irqrestore(flags); /* If called from the scheduler, we can not call up(). */ @@ -2178,8 +2224,23 @@ asmlinkage int vprintk_emit(int facility, int level, wake_up_klogd(); return printed_len; } + +asmlinkage int vprintk_emit(int facility, int level, + const struct dev_printk_info *dev_info, + const char *fmt, va_list args) +{ + return vprintk_emit_log(&init_log_state, + facility, level, dev_info, + fmt, args); +} EXPORT_SYMBOL(vprintk_emit); +static int __vprintk(const char *fmt, va_list args) +{ + return vprintk_emit_log(ve_log_state(), 0, LOGLEVEL_DEFAULT, + NULL, fmt, args); +} + int vprintk_default(const char *fmt, va_list args) { return vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, fmt, args); @@ -3530,7 +3591,61 @@ void kmsg_dump_rewind(struct kmsg_dump_iter *iter) } EXPORT_SYMBOL_GPL(kmsg_dump_rewind); -#endif +#ifdef CONFIG_VE +int setup_log_buf_ve(struct log_state *log, struct ve_struct *ve, int early) +{ + unsigned long local_log_buf_len; + int ret = -EINVAL; + + char *new_log_buf; + + local_log_buf_len = VE_LOG_BUF_LEN; + + ret = -ENOMEM; + new_log_buf = kmalloc(local_log_buf_len, GFP_KERNEL); + if (unlikely(!new_log_buf)) { + pr_err("log_buf_len: %lu text bytes not available\n", + local_log_buf_len); + goto out; + } + + log->buf_len = local_log_buf_len; + log->buf = new_log_buf; + + return 0; +out: + return ret; +} + +int ve_log_init(struct ve_struct *ve) +{ + struct log_state *log; + int ret; + + log = kzalloc(sizeof(*log), GFP_KERNEL); + if (!log) + return -ENOMEM; + + ret = setup_log_buf_ve(log, ve, 0); + if (!ret) { + kfree(log); + return ret; + } + + ve->log_state = log; + return 0; +} + +void ve_log_destroy(struct ve_struct *ve) +{ + struct log_state *log = ve->log_state; + + kfree(log->buf); + kfree(log); +} +#endif /* CONFIG_VE */ + +#endif /* CONFIG_PRINTK */ #ifdef CONFIG_SMP static atomic_t printk_cpulock_owner = ATOMIC_INIT(-1); diff --git a/kernel/ve/ve.c b/kernel/ve/ve.c index 8f192ee41832..e3a07d4c9fe4 100644 --- a/kernel/ve/ve.c +++ b/kernel/ve/ve.c @@ -590,12 +590,19 @@ static struct cgroup_subsys_state *ve_create(struct cgroup_subsys_state *parent_ atomic_set(&ve->netns_avail_nr, NETNS_MAX_NR_DEFAULT); ve->netns_max_nr = NETNS_MAX_NR_DEFAULT; + + err = ve_log_init(ve); + if (err) + goto err_log; + do_init: init_rwsem(&ve->op_sem); INIT_LIST_HEAD(&ve->ve_list); kmapset_init_key(&ve->sysfs_perms_key); return &ve->css; +err_log: + free_percpu(ve->sched_lat_ve.cur); err_lat: kmem_cache_free(ve_cachep, ve); err_ve: @@ -637,6 +644,7 @@ static void ve_destroy(struct cgroup_subsys_state *css) struct ve_struct *ve = css_to_ve(css); kmapset_unlink(&ve->sysfs_perms_key, &sysfs_ve_perms_set); + ve_log_destroy(ve); free_percpu(ve->sched_lat_ve.cur); kmem_cache_free(ve_cachep, ve); } _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel