/* * 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); }