From bd277b53c5da993ba13ae7363d8b917c18912fa7 Mon Sep 17 00:00:00 2001 From: zy Date: Thu, 16 Nov 2023 14:07:37 +0800 Subject: [PATCH] buffer --- source/buffer/internal.h | 189 ++++++++++++++++++++++++ source/buffer/trace_buffer.c | 215 +++++++++++++++++++++++++++ source/buffer/trace_buffer.h | 106 ++++++++++++++ source/buffer/variant_buffer.c | 260 +++++++++++++++++++++++++++++++++ source/buffer/variant_buffer.h | 64 ++++++++ 5 files changed, 834 insertions(+) create mode 100644 source/buffer/internal.h create mode 100644 source/buffer/trace_buffer.c create mode 100644 source/buffer/trace_buffer.h create mode 100644 source/buffer/variant_buffer.c create mode 100644 source/buffer/variant_buffer.h diff --git a/source/buffer/internal.h b/source/buffer/internal.h new file mode 100644 index 0000000..9139e1e --- /dev/null +++ b/source/buffer/internal.h @@ -0,0 +1,189 @@ +// /* +// * Linux内核诊断工具--杂项定义头文件 +// * +// * Copyright (C) 2020 Alibaba Ltd. +// * +// * 作者: Baoyou Xie +// * +// * License terms: GNU General Public License (GPL) version 3 +// * +// */ + +// #include +// #include +// #include "uapi/ali_diagnose.h" +// #include "json/json.h" + +// #include +// #include +// #include + +// #include "debug.h" + +// extern std::set g_proc_map; + +// int run_trace_main(int argc, char **argv); +// int sys_delay_main(int argc, char **argv); +// int sched_delay_main(int argc, char **argv); +// int throttle_delay_main(int argc, char **argv); +// int load_monitor_main(int argc, char **argv); +// int exit_monitor_main(int argc, char **argv); +// int utilization_main(int argc, char **argv); +// int perf_main(int argc, char **argv); +// int tcp_retrans_main(int argc, char **argv); +// int tcp_connect_main(int argc, char **argv); +// int rw_top_main(int argc, char **argv); +// int irq_delay_main(int argc, char **argv); +// int mutex_monitor_main(int argc, char **argv); +// int alloc_top_main(int argc, char **argv); +// int alloc_load_main(int argc, char **argv); +// int drop_packet_main(int argc, char **argv); +// int fs_orphan_main(int argc, char **argv); +// int df_du_main(int argc, char **argv); +// int exec_monitor_main(int argc, char **argv); +// int fs_shm_main(int argc, char **argv); +// int irq_stats_main(int argc, char **argv); +// int irq_trace_main(int argc, char **argv); +// int kprobe_main(int argc, char **argv); +// int mm_leak_main(int argc, char **argv); +// int proc_monitor_main(int argc, char **argv); +// int runq_info_main(int argc, char **argv); +// int reboot_main(int argc, char **argv); +// int pi_main(int argc, char *argv[]); +// int memcpy_main(int argc, char* argv[]); +// int md5_main(int argc, char *argv[]); +// int net_bandwidth_main(int argc, char *argv[]); +// int sig_info_main(int argc, char *argv[]); +// int task_monitor_main(int argc, char **argv); +// int rw_sem_main(int argc, char **argv); +// int rss_monitor_main(int argc, char **argv); + +// void usage_run_trace(void); +// void usage_sys_delay(void); +// void usage_load_monitor(void); +// void usage_exit_monitor(void); +// void usage_utilization(void); +// void usage_perf(); +// void usage_tcp_retrans(); +// void usage_rw_top(); +// void usage_irq_delay(); +// void usage_mutex_monitor(); +// void usage_alloc_top(); +// void usage_drop_packet(); +// void usage_fs_orphan(); +// void usage_exec_monitor(); +// void usage_fs_shm(); +// void usage_irq_stats(); +// void usage_irq_trace(); +// void usage_kprobe(); +// void usage_mm_leak(); +// void usage_testcase(void); +// void usage_pupil(void); +// void usage_sched_delay(void); +// void usage_reboot(void); +// void usage_test_memcpy(void); +// void usage_test_pi(void); +// void usage_test_md5(void); +// void usage_net_bandwidth(void); +// void usage_sig_info(void); +// void usage_task_monitor(void); +// void usage_rw_sem(void); +// void usage_rss_monitor(void); +// void usage_throttle_delay(void); + +// int uprobe_main(int argc, char **argv); +// void usage_uprobe(); + +// int ping_delay_main(int argc, char *argv[]); +// void usage_ping_delay(void); +// int ping_delay6_main(int argc, char *argv[]); +// void usage_ping_delay6(void); + +// int test_run_trace_main(int argc, char *argv[]); +// void usage_test_run_trace(void); + +// int memcg_stats_main(int argc, char *argv[]); +// void usage_memcg_stats(void); + +// int diag_activate(const char func[]); +// int diag_deactivate(const char func[]); + +// void diag_printf_inode(struct diag_inode_detail *inode); +// void diag_printf_time(struct diag_timespec *tv); +// void diag_printf_task(struct diag_task_detail *task); +// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains); +// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse); +// void diag_printf_proc_chains(struct diag_proc_chains_detail *proc_chains, int reverse, int detail); +// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack); +// void diag_printf_kern_stack(struct diag_kern_stack_detail *kern_stack, int reverse); +// void diag_printf_user_stack(int pid, int ns_pid, const char *comm, +// struct diag_user_stack_detail *user_stack); +// void diag_printf_user_stack(int pid, int ns_pid, const char *comm, +// struct diag_user_stack_detail *user_stack, int attach); +// void diag_printf_user_stack(int pid, int ns_pid, const char *comm, +// struct diag_user_stack_detail *user_stack, int attach, int reverse); +// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, +// struct diag_raw_stack_detail *raw_stack); +// void diag_printf_raw_stack(int pid, int ns_pid, const char *comm, +// struct diag_raw_stack_detail *raw_stack, int attach); +// void init_java_env(const char *agent, int pid, int ns_pid, const char *comm, std::set &); +// void diag_unwind_raw_stack(int pid, int ns_pid, +// struct diag_raw_stack_detail *raw_stack, unsigned long stack[BACKTRACE_DEPTH]); + +// void diag_sls_time(struct diag_timespec *tv, Json::Value &owner); +// void diag_sls_task(struct diag_task_detail *tsk_info, Json::Value &task); +// void diag_sls_proc_chains(struct diag_proc_chains_detail *proc_chains, Json::Value &task); +// void diag_sls_kern_stack(struct diag_kern_stack_detail *kern_stack, Json::Value &task); +// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm, +// struct diag_user_stack_detail *user_stack, Json::Value &task); +// void diag_sls_user_stack(pid_t pid, pid_t ns_pid, const char *comm, +// struct diag_user_stack_detail *user_stack, Json::Value &task, int attach); +// void diag_sls_inode(struct diag_inode_detail *inode, Json::Value &root); +// int log_config(char *arg, char *sls_file, int *p_syslog_enabled); +// void write_syslog(int enabled, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root); +// void write_file(char *sls_file, const char mod[], struct diag_timespec *tv, unsigned long id, int seq, Json::Value &root); +// void diag_ip_addr_to_str(unsigned char *ip_addr,const char type[], Json::Value &root); +// #define ULONG_MAX (~0UL) +// #define STACK_IS_END(v) ((v) == 0 || (v) == ULONG_MAX) + +// class pid_cmdline { +// private: +// std::map cmdlines; +// public: +// void clear(void); +// std::string & get_pid_cmdline(int pid); +// }; + +// int jmaps_main(int argc, char **argv); +// void restore_global_env(); +// int attach_ns_env(int pid); +// int java_attach_once(int flag_no_attach = 0); + +// extern class pid_cmdline pid_cmdline; + +// extern void clear_symbol_info(class pid_cmdline &pid_cmdline, std::set &procs, int dist); +// extern unsigned int ipstr2int(const char *ipstr); +// extern char *int2ipstr(const unsigned int ip, char *ipstr, const unsigned int ip_str_len); + +// extern int is_linux_2_6_x(void); +// extern int linux_2_6_x; + +// int sys_cost_main(int argc, char **argv); +// void usage_sys_cost(); + +// int fs_cache_main(int argc, char *argv[]); +// void usage_fs_cache(void); + +// int high_order_main(int argc, char *argv[]); +// void usage_high_order(void); + +// int pmu_main(int argc, char **argv); +// void usage_pmu(void); + +// int testcase_main(int argc, char *argv[]); + +// struct timeval; +// struct timezone; +// extern "C" { +// void diag_gettimeofday(struct diag_timespec *tv, struct timezone *tz); +// } diff --git a/source/buffer/trace_buffer.c b/source/buffer/trace_buffer.c new file mode 100644 index 0000000..3fb08ab --- /dev/null +++ b/source/buffer/trace_buffer.c @@ -0,0 +1,215 @@ +/* + * diagnose-tools 工具通用调试缓冲区模块 + * 这是为了解决procfs/trace的问题而编写 + * + * Copyright (C) 2020 Alibaba Ltd. + * + * 作者: Baoyou Xie + * + * License terms: GNU General Public License (GPL) version 3 + * + */ + +#include + +// #include "internal.h" +#include "trace_buffer.h" + +int init_diag_trace_buffer(struct diag_trace_buffer *buffer, + unsigned int buf_size) +{ + int ret = -ENOMEM; + char *buf1 = NULL, *buf2 = NULL; + + ret = -EINVAL; + if (buf_size < 10 * DIAG_TRACE_BUF_SIZE) + return ret; + + buf1 = vmalloc(buf_size); + if (!buf1) + goto out_nomem; + + buf2 = vmalloc(buf_size); + if (!buf2) + goto out_nomem; + + memset(buf1, 0, buf_size); + memset(buf2, 0, buf_size); + memset(buffer, 0, sizeof(struct diag_trace_buffer)); + buffer->buf_size = buf_size; + buffer->buffer.data = buf1; + spin_lock_init(&buffer->buffer.lock); + mutex_init(&buffer->buffer.mutex); + buffer->product.data = buf2; + + ret = 0; + return ret; +out_nomem: + if (buf1) + vfree(buf1); + if (buf2) + vfree(buf2); + + return ret; +} + +void destroy_diag_trace_buffer(struct diag_trace_buffer *buffer) +{ + if (buffer->buffer.data) + vfree(buffer->buffer.data); + if (buffer->product.data) + vfree(buffer->product.data); + + memset(buffer, 0, sizeof(struct diag_trace_buffer)); +} + +void discard_diag_trace_buffer(struct diag_trace_buffer *buffer) +{ + unsigned long flags; + + diag_trace_buffer_mutex_lock(buffer); + diag_trace_buffer_spin_lock(buffer, flags); + buffer->buffer.circle = buffer->buffer.pos = buffer->buffer.tail = 0; + diag_trace_buffer_spin_unlock(buffer, flags); + diag_trace_buffer_mutex_unlock(buffer); +} + +void backup_diag_trace_buffer(struct diag_trace_buffer *buffer) +{ + unsigned long flags; + + if (!buffer->buffer.data || !buffer->product.data) + return; + + diag_trace_buffer_mutex_lock(buffer); + diag_trace_buffer_spin_lock(buffer, flags); + + buffer->product.len = 0; + if (buffer->buffer.pos < buffer->buf_size) { + if (buffer->buffer.circle) { + int tail_len = 0; + if (buffer->buffer.tail > buffer->buffer.pos) { + tail_len = buffer->buffer.tail - buffer->buffer.pos; + + memcpy(buffer->product.data, + buffer->buffer.data + buffer->buffer.pos, + tail_len); + } + memcpy(buffer->product.data + tail_len, + buffer->buffer.data, + buffer->buffer.pos); + buffer->product.len = buffer->buffer.pos + tail_len; + } else { + memcpy(buffer->product.data, buffer->buffer.data, buffer->buffer.pos); + buffer->product.len = buffer->buffer.pos; + } + } + + buffer->buffer.circle = buffer->buffer.pos = buffer->buffer.tail = 0; + + diag_trace_buffer_spin_unlock(buffer, flags); + diag_trace_buffer_mutex_unlock(buffer); +} + +asmlinkage int +diag_trace_buffer_write_nolock(struct diag_trace_buffer *buffer, + const void *data, size_t len) +{ + unsigned int left; + + left = buffer->buf_size - buffer->buffer.pos; + if (len < left) { + memcpy(buffer->buffer.data + buffer->buffer.pos, + data, len); + buffer->buffer.pos += len; + } else { + buffer->buffer.tail = buffer->buffer.pos; + memcpy(buffer->buffer.data, data, len); + buffer->buffer.pos = len; + buffer->buffer.circle = 1; + } + + return len; +} + +asmlinkage int +diag_trace_buffer_write(struct diag_trace_buffer *buffer, + const void *data, size_t len) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&buffer->buffer.lock, flags); + ret = diag_trace_buffer_write_nolock(buffer, data, len); + spin_unlock_irqrestore(&buffer->buffer.lock, flags); + + return ret; +} + +static asmlinkage int +__diag_trace_buffer_printk_nolock(struct diag_trace_buffer *buffer, + const char *fmt, va_list ap) +{ + unsigned int len = 0; + unsigned int left; + + len = vsnprintf(buffer->fmt_buffer, DIAG_TRACE_BUF_SIZE, fmt, ap); + if (len > DIAG_TRACE_BUF_SIZE) + return len; + + left = buffer->buf_size - buffer->buffer.pos; + if (len < left) { + memcpy(buffer->buffer.data + buffer->buffer.pos, + buffer->fmt_buffer, len); + buffer->buffer.pos += len; + } else { + buffer->buffer.tail = buffer->buffer.pos; + memcpy(buffer->buffer.data, buffer->fmt_buffer, len); + buffer->buffer.pos = len; + buffer->buffer.circle = 1; + } + + return len; +} + +asmlinkage int +diag_trace_buffer_printk_nolock(struct diag_trace_buffer *buffer, + const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = __diag_trace_buffer_printk_nolock(buffer, fmt, ap); + va_end(ap); + + return ret; +} + +asmlinkage int +diag_trace_buffer_printk(struct diag_trace_buffer *buffer, + const char *fmt, ...) +{ + int ret; + unsigned long flags; + va_list ap; + + spin_lock_irqsave(&buffer->buffer.lock, flags); + va_start(ap, fmt); + ret = __diag_trace_buffer_printk_nolock(buffer, fmt, ap); + va_end(ap); + spin_unlock_irqrestore(&buffer->buffer.lock, flags); + + return ret; +} + +void diag_trace_buffer_mutex_lock(struct diag_trace_buffer *buffer) +{ + mutex_lock(&buffer->buffer.mutex); +} + +void diag_trace_buffer_mutex_unlock(struct diag_trace_buffer *buffer) +{ + mutex_unlock(&buffer->buffer.mutex); +} + diff --git a/source/buffer/trace_buffer.h b/source/buffer/trace_buffer.h new file mode 100644 index 0000000..80c9e3b --- /dev/null +++ b/source/buffer/trace_buffer.h @@ -0,0 +1,106 @@ +/* + * diagnose-tools 工具通用调试缓冲区模块 + * 这是为了解决procfs/trace的问题而编写 + * + * Copyright (C) 2020 Alibaba Ltd. + * + * 作者: Baoyou Xie + * + * License terms: GNU General Public License (GPL) version 3 + * + */ + +#include +#include +#include + +/** + * 调试缓冲区描述符 + * buffer: 当前正在接受调用者输出的缓冲区 + * data: 数据起始指针 + * pos: 当前写入位置 + * circle: 是否已经产生了回绕 + * tail: 有效位置的尾部 + * product: 将buffer中数据临时保存到此,避免影响记录速度 + * data: 数据起始指针 + * len: 数据有效长度 + * buf_size: buffer/product的大小 + */ +#define DIAG_TRACE_BUF_SIZE 1024 + +struct diag_trace_buffer { + struct { + char *data; + unsigned int pos; + int circle; + unsigned int tail; + spinlock_t lock; + struct mutex mutex; + } buffer; + + struct { + char *data; + unsigned int len; + } product; + + char fmt_buffer[DIAG_TRACE_BUF_SIZE]; + unsigned int buf_size; +}; + +int init_diag_trace_buffer(struct diag_trace_buffer *buffer, + unsigned int buf_size); +void destroy_diag_trace_buffer(struct diag_trace_buffer *buffer); +void discard_diag_trace_buffer(struct diag_trace_buffer *buffer); +void backup_diag_trace_buffer(struct diag_trace_buffer *buffer); +asmlinkage int +diag_trace_buffer_printk_nolock(struct diag_trace_buffer *buffer, + const char *fmt, ...); +asmlinkage int +diag_trace_buffer_printk(struct diag_trace_buffer *buffer, + const char *fmt, ...); +asmlinkage int +diag_trace_buffer_write_nolock(struct diag_trace_buffer *buffer, + const void *data, size_t len); +asmlinkage int +diag_trace_buffer_write(struct diag_trace_buffer *buffer, + const void *data, size_t len); +#define diag_trace_buffer_spin_lock(__buffer, flags) \ + spin_lock_irqsave(&((__buffer)->buffer.lock), flags) +#define diag_trace_buffer_spin_unlock(__buffer, flags) \ + spin_unlock_irqrestore(&((__buffer)->buffer.lock), flags) +void diag_trace_buffer_mutex_lock(struct diag_trace_buffer *buffer); +void diag_trace_buffer_mutex_unlock(struct diag_trace_buffer *buffer); + +void diagnose_trace_buffer_stack_trace(int pre, struct diag_trace_buffer *buffer, + struct task_struct *p, unsigned long *backtrace); +void diagnose_trace_buffer_nolock_stack_trace(int pre, struct diag_trace_buffer *buffer, + struct task_struct *p, unsigned long *backtrace); +void diagnose_trace_buffer_nolock_stack_trace_user(int pre, struct diag_trace_buffer *buffer, + unsigned long *backtrace); +void diagnose_trace_buffer_stack_trace_user(int pre, struct diag_trace_buffer *buffer, + unsigned long *backtrace); +void diagnose_trace_buffer_nolock_stack_trace_user_tsk(int pre, struct diag_trace_buffer *buffer, + struct task_struct *tsk, unsigned long *backtrace); +void diagnose_trace_buffer_stack_trace_user_tsk(int pre, struct diag_trace_buffer *buffer, + struct task_struct *tsk, unsigned long *backtrace); +void diag_trace_buffer_process_chain(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk); +void diag_trace_buffer_nolock_process_chain(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk); +void diag_trace_buffer_process_chain_cmdline(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk); +void diag_trace_buffer_nolock_process_chain_cmdline(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk); +void trace_buffer_cgroups_tsk(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk); +void trace_buffer_nolock_cgroups_tsk(int pre, struct diag_trace_buffer *buffer, struct task_struct *tsk); +void trace_buffer_cgroups(int pre, struct diag_trace_buffer *buffer); +void trace_buffer_nolock_cgroups(int pre, struct diag_trace_buffer *buffer); +void diag_trace_buffer_all_task_stack(int pre, struct diag_trace_buffer *buffer); +void diag_trace_buffer_nolock_all_task_stack(int pre, + struct diag_trace_buffer *buffer); +void diagnose_trace_buffer_nolock_stack_trace_unfold(int pre, struct diag_trace_buffer *buffer, + struct task_struct *p, unsigned long *backtrace); +void diagnose_trace_buffer_nolock_stack_trace_unfold_user(int pre, struct diag_trace_buffer *buffer, + unsigned long *backtrace); +void diagnose_print_stack_trace_unfold_user_tsk(int pre, int might_sleep, struct task_struct *tsk, unsigned long *backtrace); +void diagnose_trace_buffer_nolock_stack_trace_unfold_user_tsk(int pre, int might_sleep, struct diag_trace_buffer *buffer, + struct task_struct *tsk, unsigned long *backtrace); +void diagnose_trace_buffer_stack_trace_unfold_user_tsk(int pre, int might_sleep, struct diag_trace_buffer *buffer, + struct task_struct *tsk, unsigned long *backtrace); + diff --git a/source/buffer/variant_buffer.c b/source/buffer/variant_buffer.c new file mode 100644 index 0000000..676b89e --- /dev/null +++ b/source/buffer/variant_buffer.c @@ -0,0 +1,260 @@ +/* + * Linux内核诊断工具--工具通用调试缓冲区模块 + * 这是为了解决procfs/trace的问题而编写 + * + * Copyright (C) 2020 Alibaba Ltd. + * + * 作者: Baoyou Xie + * + * License terms: GNU General Public License (GPL) version 3 + */ + +#include +#include + +#include "trace_buffer.h" +// #include "internal.h" +#include "variant_buffer.h" + +int init_diag_variant_buffer(struct diag_variant_buffer *buffer, + unsigned int buf_size) { + int ret = 0; + + ret = -EINVAL; + if (buf_size < 10 * DIAG_TRACE_BUF_SIZE) + return ret; + + memset(buffer, 0, sizeof(struct diag_variant_buffer)); + buffer->buf_size = buf_size; + spin_lock_init(&buffer->lock); + mutex_init(&buffer->mutex); + + ret = 0; + return ret; +} + +int alloc_diag_variant_buffer(struct diag_variant_buffer *buffer) { + int ret = -ENOMEM; + char *buf1 = NULL, *buf2 = NULL, *buf3 = NULL; + unsigned int buf_size; + + buf_size = buffer->buf_size; + if (buffer->alloced) + return 0; + + ret = -EINVAL; + if (buf_size < 10 * DIAG_TRACE_BUF_SIZE) + return ret; + + ret = -ENOMEM; + buf1 = vmalloc(buf_size); + if (!buf1) + goto out_nomem; + + buf2 = vmalloc(buf_size); + if (!buf2) + goto out_nomem; + + buf3 = vmalloc(buf_size * 2); + if (!buf3) + goto out_nomem; + + memset(buf1, 0, buf_size); + memset(buf2, 0, buf_size); + memset(buf3, 0, buf_size * 2); + buffer->buffers[0].data = buf1; + buffer->buffers[1].data = buf2; + buffer->product.data = buf3; + + buffer->alloced = 1; + + ret = 0; + return ret; +out_nomem: + if (buf1) + vfree(buf1); + if (buf2) + vfree(buf2); + if (buf3) + vfree(buf3); + + return ret; +} + +void destroy_diag_variant_buffer(struct diag_variant_buffer *buffer) { + if (buffer->buffers[0].data) + vfree(buffer->buffers[0].data); + if (buffer->buffers[1].data) + vfree(buffer->buffers[1].data); + if (buffer->product.data) + vfree(buffer->product.data); + + memset(buffer, 0, sizeof(struct diag_variant_buffer)); +} + +void discard_diag_variant_buffer(struct diag_variant_buffer *buffer) { + unsigned long flags; + + if (!buffer->alloced) + return; + + diag_variant_buffer_mutex_lock(buffer); + diag_variant_buffer_spin_lock(buffer, flags); + buffer->buffers[0].pos = buffer->buffers[1].pos = 0; + buffer->buffer_toggle = 0; + diag_variant_buffer_spin_unlock(buffer, flags); + diag_variant_buffer_mutex_unlock(buffer); +} + +void backup_diag_variant_buffer(struct diag_variant_buffer *buffer) { + unsigned long flags; + + if (!buffer->alloced) + return; + + diag_variant_buffer_mutex_lock(buffer); + diag_variant_buffer_spin_lock(buffer, flags); + + buffer->product.len = 0; + if (buffer->buffer_toggle == 0) { + if (buffer->buffers[1].pos) { + memcpy(buffer->product.data, buffer->buffers[1].data, + buffer->buffers[1].pos); + buffer->product.len = buffer->product.len + buffer->buffers[1].pos; + } + if (buffer->buffers[0].pos) { + memcpy(buffer->product.data + buffer->product.len, + buffer->buffers[0].data, buffer->buffers[0].pos); + buffer->product.len = buffer->product.len + buffer->buffers[0].pos; + } + } else { + if (buffer->buffers[0].pos) { + memcpy(buffer->product.data, buffer->buffers[0].data, + buffer->buffers[0].pos); + buffer->product.len = buffer->product.len + buffer->buffers[0].pos; + } + if (buffer->buffers[1].pos) { + memcpy(buffer->product.data + buffer->product.len, + buffer->buffers[1].data, buffer->buffers[1].pos); + buffer->product.len = buffer->product.len + buffer->buffers[1].pos; + } + } + + buffer->buffers[0].pos = buffer->buffers[1].pos = 0; + buffer->buffers[0].head = buffer->buffers[1].head = NULL; + buffer->buffer_toggle = 0; + + diag_variant_buffer_spin_unlock(buffer, flags); + diag_variant_buffer_mutex_unlock(buffer); +} + +asmlinkage int diag_variant_buffer_reserve(struct diag_variant_buffer *buffer, + size_t len) { + int real_len = (len + sizeof(unsigned long)) & (sizeof(unsigned long) - 1); + real_len += sizeof(struct diag_variant_buffer_head); + /** + * 这样可以简单的略过整型溢出检查。 + */ + if (len > 1024 * 1024 * 1024) + return len; + if (!buffer->alloced) + return len; + + if (buffer->buffer_toggle == 0) { + if (buffer->buffers[0].pos + real_len >= buffer->buf_size) { + buffer->buffer_toggle = 1; + buffer->buffers[1].pos = sizeof(struct diag_variant_buffer_head); + buffer->buffers[1].head = (void *)buffer->buffers[1].data; + memset(buffer->buffers[1].head, 0, + sizeof(struct diag_variant_buffer_head)); + } else { + buffer->buffers[0].head = + (void *)buffer->buffers[0].data + buffer->buffers[0].pos; + memset(buffer->buffers[0].head, 0, + sizeof(struct diag_variant_buffer_head)); + buffer->buffers[0].pos += sizeof(struct diag_variant_buffer_head); + } + } else { + if (buffer->buffers[1].pos + real_len >= buffer->buf_size) { + buffer->buffer_toggle = 0; + buffer->buffers[0].pos = sizeof(struct diag_variant_buffer_head); + buffer->buffers[0].head = (void *)buffer->buffers[0].data; + memset(buffer->buffers[0].head, 0, + sizeof(struct diag_variant_buffer_head)); + } else { + buffer->buffers[1].head = + (void *)buffer->buffers[1].data + buffer->buffers[1].pos; + memset(buffer->buffers[1].head, 0, + sizeof(struct diag_variant_buffer_head)); + buffer->buffers[1].pos += sizeof(struct diag_variant_buffer_head); + } + } + + return len; +} + +asmlinkage int diag_variant_buffer_seal(struct diag_variant_buffer *buffer) { + int idx = !!buffer->buffer_toggle; + void *rbound = buffer->buffers[idx].data + buffer->buf_size; + + if (!buffer->alloced) + return -EINVAL; + if ((void *)buffer->buffers[idx].head < (void *)buffer->buffers[idx].data) + return -EINVAL; + if ((void *)buffer->buffers[idx].head > + (rbound - sizeof(struct diag_variant_buffer_head))) + return -EINVAL; + + buffer->buffers[idx].head->magic = DIAG_VARIANT_BUFFER_HEAD_MAGIC_SEALED; + buffer->buffers[idx].head->len = (void *)buffer->buffers[idx].data + + buffer->buffers[idx].pos - + (void *)buffer->buffers[idx].head; + + return 0; +} + +asmlinkage int +diag_variant_buffer_write_nolock(struct diag_variant_buffer *buffer, + const void *data, size_t len) { + unsigned int left; + int idx = !!buffer->buffer_toggle; + + if (!buffer->alloced) + return -EINVAL; + + left = buffer->buf_size - buffer->buffers[idx].pos; + if (len < left) { + memcpy(buffer->buffers[idx].data + buffer->buffers[idx].pos, data, len); + buffer->buffers[idx].pos += len; + } + + return len; +} + +void diag_variant_buffer_mutex_lock(struct diag_variant_buffer *buffer) { + mutex_lock(&buffer->mutex); +} + +void diag_variant_buffer_mutex_unlock(struct diag_variant_buffer *buffer) { + mutex_unlock(&buffer->mutex); +} + +int copy_to_user_variant_buffer(struct diag_variant_buffer *variant_buffer, + void __user *ptr_len, void __user *buf, + size_t size) { + size_t len; + int ret; + + backup_diag_variant_buffer(variant_buffer); + len = variant_buffer->product.len; + if (size < len) + len = size; + ret = copy_to_user(buf, variant_buffer->product.data, len); + if (!ret) + ret = len; + if (ret >= 0) { + ret = copy_to_user(ptr_len, &ret, sizeof(int)); + } + + return ret; +} diff --git a/source/buffer/variant_buffer.h b/source/buffer/variant_buffer.h new file mode 100644 index 0000000..41d27d6 --- /dev/null +++ b/source/buffer/variant_buffer.h @@ -0,0 +1,64 @@ +/* + * Linux内核诊断工具--工具通用调试缓冲区模块 + * 这是为了解决procfs/trace的问题而编写 + * + * Copyright (C) 2020 Alibaba Ltd. + * + * 作者: Baoyou Xie + * + * License terms: GNU General Public License (GPL) version 3 + */ + +#include +#include +#include + +#define DIAG_VARIANT_BUFFER_HEAD_MAGIC_SEALED 197612031122 +#define DIAG_VARIANT_BUFFER_HEAD_MAGIC_UNSEALED 197612031234 + +struct diag_variant_buffer_head { + unsigned long magic; + unsigned long len; +}; + +struct diag_variant_buffer { + struct { + char *data; + unsigned int pos; + struct diag_variant_buffer_head *head; + } buffers[2]; + /* 0 or 1 */ + int buffer_toggle; + + struct { + char *data; + unsigned int len; + } product; + + unsigned int buf_size; + unsigned int alloced; + spinlock_t lock; + struct mutex mutex; +}; + +#define diag_variant_buffer_spin_lock(__buffer, flags) \ + spin_lock_irqsave(&((__buffer)->lock), flags) +#define diag_variant_buffer_spin_unlock(__buffer, flags) \ + spin_unlock_irqrestore(&((__buffer)->lock), flags) +int init_diag_variant_buffer(struct diag_variant_buffer *buffer, + unsigned int buf_size); +int alloc_diag_variant_buffer(struct diag_variant_buffer *buffer); +void destroy_diag_variant_buffer(struct diag_variant_buffer *buffer); +void discard_diag_variant_buffer(struct diag_variant_buffer *buffer); +void backup_diag_variant_buffer(struct diag_variant_buffer *buffer); +asmlinkage int diag_variant_buffer_reserve(struct diag_variant_buffer *buffer, + size_t len); +asmlinkage int diag_variant_buffer_seal(struct diag_variant_buffer *buffer); +asmlinkage int +diag_variant_buffer_write_nolock(struct diag_variant_buffer *buffer, + const void *data, size_t len); +void diag_variant_buffer_mutex_lock(struct diag_variant_buffer *buffer); +void diag_variant_buffer_mutex_unlock(struct diag_variant_buffer *buffer); +int copy_to_user_variant_buffer(struct diag_variant_buffer *variant_buffer, + void __user *ptr_len, void __user *buf, + size_t size);