216 lines
4.8 KiB
C
216 lines
4.8 KiB
C
/*
|
||
* diagnose-tools 工具通用调试缓冲区模块
|
||
* 这是为了解决procfs/trace的问题而编写
|
||
*
|
||
* Copyright (C) 2020 Alibaba Ltd.
|
||
*
|
||
* 作者: Baoyou Xie <baoyou.xie@linux.alibaba.com>
|
||
*
|
||
* 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);
|
||
}
|
||
|