如何在内核 space 程序中正确构建环形缓冲区?

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

我正在尝试在内核 space 中编写一个带有环形缓冲区的程序,它在用户 space 上工作正常,我用 kmalloc 替换了内存分配器并得到了类型转换错误。这是用户 space:

上的程序
main ()
{
  char last_char = 'a';
  RingBuffer *buffer = newRingBuffer (10);
  RingBuffer_trywrite (buffer, last_char);
  RingBuffer_tryread(buffer, &last_char);
  printf ("%s", &last_char);

  return 0;
}

以下是内核space程序的部分代码:

struct RingBuffer* buffer;
static int __init ch_drv_init(void) {
buffer = newRingBuffer(BUF_CAPACITY);
}

环形缓冲区的实现取自维基百科(https://ru.wikipedia.org/wiki/Кольцевой_буфер)

请试试这个:

#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");