How to Read Ring Buffer Within Linux Kernel Space

How to read ring buffer within linux kernel space?

What you are looking for is /proc/kmsg. This is the kernel ring buffer!

  1. Yes, this is inside kernel space. Any process trying to read it should have super user privileges to read it!

  2. How to read it the ring buffer? Here is a beautiful illustration from IBM Developerworks

Reading the Kernel Ring Buffer

dmesg would be your first resort! How does dmesg accomplish its task? By a call to syslog()! How does syslog do its job? Through the system call interface which in turn call do_syslog(). do_syslog() does the finishing act like this.

Here are a few more resources to get you more info about /proc/kmsg and kernel logging in general-

  1. http://www.makelinux.net/ldd3/chp-4-sect-2

  2. http://www.ibm.com/developerworks/linux/library/l-kernel-logging-apis/index.html

  3. http://oguzhanozmen.blogspot.in/2008/09/kernel-log-buffering-printk-syslog-ng.html

How to correctly build a ring buffer in a kernel space program?

Please try this:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/vmalloc.h>

#define CHAR_SIZE (sizeof(char))
#define RINGBUFFER_OK (0)
#define RINGBUFFER_ERR_NULL (-1)
#define RINGBUFFER_ERR_EMPTY (-2)
#define RINGBUFFER_ERR_FULL (-3)

struct RingBuffer {
char *start;
char *end;
volatile char *readptr;
volatile char *writeptr;
};

struct RingBuffer *newRingBuffer(unsigned long int capacity)
{
struct RingBuffer *rb;
char *mem = vmalloc(capacity * CHAR_SIZE);
if (mem == NULL) {
return NULL;
}

rb = vmalloc(sizeof(*rb));
if (rb == NULL) {
vfree(mem);
return NULL;
}

rb->start = mem;
rb->end = mem + capacity;
rb->readptr = mem;
rb->writeptr = mem;

return rb;
}

void deleteRingBuffer(struct RingBuffer *rb)
{
if (rb == NULL)
return;

vfree(rb->start);
vfree(rb);
}

int RingBuffer_trywrite(struct RingBuffer *rb, char c)
{
volatile char *tmp;
if (rb == NULL)
return RINGBUFFER_ERR_NULL;

if (rb->writeptr + 1 == rb->readptr)
return RINGBUFFER_ERR_FULL;

*(rb->writeptr) = c;
tmp = rb->writeptr + 1;
if (tmp >= rb->end) tmp = rb->start;
rb->writeptr = tmp;

return RINGBUFFER_OK;
}

int RingBuffer_tryread(struct RingBuffer *rb, char *c)
{
volatile char *tmp;
if (rb == NULL)
return RINGBUFFER_ERR_NULL;

if (rb->readptr == rb->writeptr)
return RINGBUFFER_ERR_EMPTY;

*c = (*rb->readptr);
tmp = rb->readptr + 1;
if (tmp >= rb->end) tmp = rb->start;
rb->readptr = tmp;

return RINGBUFFER_OK;
}

static int __init init_test_module(void)
{
char last_char = 'a';
struct RingBuffer *buffer = newRingBuffer(10);
RingBuffer_trywrite(buffer, last_char);
RingBuffer_tryread(buffer, &last_char);
pr_info("last_char: %c\n", last_char);
deleteRingBuffer(buffer);

return 0;
}

static void __exit exit_test_module(void)
{
}

module_init(init_test_module);
module_exit(exit_test_module);
MODULE_LICENSE("GPL");

does read() clear kernel ring buffer /proc/kmsg?

Become root and run this cat /proc/kmsg >> File1.txt and cat /proc/kmsg >> File2.txt. Compare File1.txt and File2.txt You will immediately know whether the ring buffer is getting cleared on read() cos cat internally invokes read() anyways!

Also read about ring buffers and how they behave in the Kernel Documentation here-
http://www.mjmwired.net/kernel/Documentation/trace/ring-buffer-design.txt

EDIT: I found something interesting in the book Linux Device Drivers by Jonathan Corbet-

The printk function writes messages into a circular buffer that is
__LOG_BUF_LEN bytes long: a value from 4 KB to 1 MB chosen while configuring the kernel. The function then wakes any process that is
waiting for messages, that is, any process that is sleeping in the
syslog system call or that is reading /proc/kmsg. These two interfaces
to the logging engine are almost equivalent, but note that reading
from /proc/kmsg consumes the data from the log buffer
, whereas the
syslog system call can optionally return log data while leaving it for
other processes as well. In general, reading the /proc file is easier
and is the default behavior for klogd. The dmesg command can be used
to look at the content of the buffer without flushing it; actually,
the command returns to stdout the whole content of the buffer, whether
or not it has already been read

So in your particular case, if you are using a plain read(), I think the buffer is indeed getting cleared and new data is being constantly written into it and hence you find some data all the time! Kernel experts can correct me here!

shared lock-free queue between kernel/user address space

For syncrhonize between kernel and user space you may use curcular buffer mechanism (documentation at Documentation/circular-buffers.txt).

Key factor of such buffers is two pointers (head and tail), which can be updated separately, which fits well for separated user and kernel codes. Also, implementation of circular buffer is quite simple, so it is not difficult to implement it in user space.

Note, that for multiple producers in the kernel you need to syncrhonize them with spinlock or similar.



Related Topics



Leave a reply



Submit