summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzy <[email protected]>2023-11-16 14:07:37 +0800
committerzy <[email protected]>2023-11-16 14:07:37 +0800
commitbd277b53c5da993ba13ae7363d8b917c18912fa7 (patch)
tree9efb47881b26af512c013769756074f15147caf1
parent1e9c7be927076f26e984c2459941f804fd9e15d6 (diff)
buffer
-rw-r--r--source/buffer/internal.h189
-rw-r--r--source/buffer/trace_buffer.c215
-rw-r--r--source/buffer/trace_buffer.h106
-rw-r--r--source/buffer/variant_buffer.c260
-rw-r--r--source/buffer/variant_buffer.h64
5 files changed, 834 insertions, 0 deletions
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 <[email protected]>
+// *
+// * License terms: GNU General Public License (GPL) version 3
+// *
+// */
+
+// #include <string>
+// #include <set>
+// #include "uapi/ali_diagnose.h"
+// #include "json/json.h"
+
+// #include <fcntl.h>
+// #include <sys/ioctl.h>
+// #include <unistd.h>
+
+// #include "debug.h"
+
+// extern std::set<int> 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<int> &);
+// 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<int, std::string> 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<int> &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 <[email protected]>
+ *
+ * License terms: GNU General Public License (GPL) version 3
+ *
+ */
+
+#include <linux/vmalloc.h>
+
+// #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 <[email protected]>
+ *
+ * License terms: GNU General Public License (GPL) version 3
+ *
+ */
+
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/stddef.h>
+
+/**
+ * 调试缓冲区描述符
+ * 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 <[email protected]>
+ *
+ * License terms: GNU General Public License (GPL) version 3
+ */
+
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+
+#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 <[email protected]>
+ *
+ * License terms: GNU General Public License (GPL) version 3
+ */
+
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+
+#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);