This is impossible to let the kernel module and the userspace program read/write the same memory area at the same time ?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



hi all:
I have a kernel module, it provide some functions:
1. vmalloc a 4KB memory space (I built a ring buffer manage the 4KB memory space)
2. provide the special mmap(), which can remap the memory space.
3. write some data into the 4KB memory space 

And I have a userspace program, it provide some functions:
1.mmap the kernel memory space into userspace 
2.read some data from that mmap space

The question is:
When I first insmod the kernel module until the data have written in the space, 
I run the userspace program which read some data. This way is OK.
If I insmod the kernel module and run the userspace program at the same time, 
the kernel will stop and computer will reboot. I think the kernel module is 
writing the data and the userspace program is reading the data.  

How to fix it, thank you!

the kernel module code is:
#####################################################
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/cdev.h>
#include <linux/version.h>
#include <linux/vmalloc.h>
#include <linux/ctype.h>
#include <linux/pagemap.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
#include <linux/pid.h>
#include <linux/sched.h>
//#define USE_KMALLOC 

#define PAGE_ORDER   0
#define PAGES_NUMBER 1

static int MAJOR_DEVICE = 30;
void * mmap_buf = 0;
unsigned long mmap_size = 4*1024;

static int ws_open(struct inode *inode, struct file *file)
{
    return 0;    
}


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)
#define LIN_IOCTL_NAME .ioctl
int ws_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long data)
#else
#define LIN_IOCTL_NAME .unlocked_ioctl
long ws_ioctl(struct file *file, u_int cmd, u_long data)
#endif
{
    //todo
    return 0;    
}


int mmap_alloc(void)
{
    //struct page *page;
    int i;    
    mmap_size = PAGE_ALIGN(mmap_size);

    #ifdef USE_KMALLOC //for kmalloc
    mmap_buf = kzalloc(mmap_size, GFP_KERNEL);
    printk("kmalloc mmap_buf=%p\n", (void *)mmap_buf);
    if (!mmap_buf) {
printk("kmalloc failed!\n");
        return -1;
    }
    for (page = virt_to_page(mmap_buf); page < virt_to_page(mmap_buf + mmap_size); page++) {
        SetPageReserved(page);
strcpy((void *)mmap_buf, "Hello world!\n");
    }
    #else //for vmalloc
    mmap_buf  = vmalloc(mmap_size);
    printk("vmalloc mmap_buf=%p  mmap_size=%ld\n", (void *)mmap_buf, mmap_size);
    if (!mmap_buf ) {
printk("vmalloc failed!\n");
        return -1;
    }
    for (i = 0; i < mmap_size; i += PAGE_SIZE) {
        SetPageReserved(vmalloc_to_page(mmap_buf + i));
    }
    #endif

  return 0;
}


int mmap_free(void)
{
    #ifdef USE_KMALLOC
    struct page *page;
    for (page = virt_to_page(mmap_buf); page < virt_to_page(mmap_buf + mmap_size); page++) {
        ClearPageReserved(page);
    }
    kfree((void *)mmap_buf);
    #else
    int i;
    for (i = 0; i < mmap_size; i += PAGE_SIZE) {
        ClearPageReserved(vmalloc_to_page(mmap_buf + i));
    }
    vfree((void *)mmap_buf);
    #endif
    mmap_buf = NULL;
    return 0;
}


static int ws_mmap(struct file *f, struct vm_area_struct *vma)
{
    int ret;
    unsigned long pfn;
    unsigned long start = vma->vm_start;
    unsigned long size = PAGE_ALIGN(vma->vm_end - vma->vm_start);
    void * ptmp = mmap_buf;
    if (size > mmap_size || !mmap_buf) {
        return -EINVAL;
    }
    
    #ifdef USE_KMALLOC
pfn  = virt_to_phys(mmap_buf) >> PAGE_SHIFT;
        return remap_pfn_range(vma, start,  pfn, size, PAGE_SHARED);
    #else
    /* loop over all pages, map it page individually */
    while (size > 0) {
        pfn = vmalloc_to_pfn(ptmp);
        if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0) {
            return ret;
        }
        start += PAGE_SIZE;
        ptmp += PAGE_SIZE;
        size -= PAGE_SIZE;
    }
    #endif
    return 0;
    
}


static int ws_release(struct inode *inode, struct file *file)
{
    return 0;
}


static const struct file_operations ws_fops ={    
    .owner = THIS_MODULE,
     //.write = ws_write,
    //.read = ws_read,
    .mmap = ws_mmap,
    //.ioctl = ws_ioctl,
    //.open = ws_open,
    //.release = ws_release,
};

static void wsmmap_exit(void)
{
    if( 0 != mmap_free( ))
        printk("mmap free failed!\n");
    unregister_chrdev(MAJOR_DEVICE,"wsmmap"); 
    printk("rmmod wsmmap module!\n");
      
}


/*manage data*/
typedef struct {
         char *buffer;
         int length;
         volatile int start;
         volatile int end;
} RingBuffer;

RingBuffer * ring_buffer;

RingBuffer *RingBuffer_create(void *start_malloc, int length)
{
         RingBuffer *buffer = (RingBuffer *)start_malloc;
         buffer->length  = length + 1;
         buffer->start = 0;
         buffer->end = 0;
         buffer->buffer = (char *)start_malloc + sizeof(RingBuffer);

return buffer;
}

#define RingBuffer_available_data(B) ((B)->end % (B)->length - (B)->start)
#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1)
#define RingBuffer_commit_write(B, A) ((B)->end = ((B)->end + (A)) % (B)->length)
#define RingBuffer_ends_at(B) ((B)->buffer + (B)->end)

int RingBuffer_write(RingBuffer *buffer, char *data, int length)
{
if(RingBuffer_available_data(buffer) == 0) {
buffer->start = buffer->end = 0;
}

if (length > RingBuffer_available_space(buffer)){
printk("Not enough space: %d request, %d available", RingBuffer_available_data(buffer), length);
return -1;
}

void *result = memcpy(RingBuffer_ends_at(buffer), data, length);
if (result != RingBuffer_ends_at(buffer)){
printk("Failed to write data into buffer.");
return -1;
}
RingBuffer_commit_write(buffer, length);

return length;
}


int kernel_thread_write(void *argc)
{
char *a = "aa";
int num = 2038;
while (num){
RingBuffer_write(ring_buffer, a, 2);
printk("write length is %d, start is %d, end is %d\n", ring_buffer->length, ring_buffer->start, ring_buffer->end);
--num;
msleep(10);
}
return 0;
}

int wsmmap_init(void)
{
    //int i;
    if(register_chrdev(MAJOR_DEVICE, "wsmmap", &ws_fops))
       printk("Cannot register mmap device as major device 0!\n");
    else 
            printk("wsmmap device driver registed sucessfully!\n"); 
    printk("insmod wsmmap module successfully!\n");    
    if(0 != mmap_alloc( ))
        printk("mmap alloc failed!\n");

   /*
    * Initialization RingBuffer
    */
    ring_buffer = RingBuffer_create(mmap_buf, mmap_size - sizeof(RingBuffer) - 1);

    kernel_thread(kernel_thread_write, NULL, CLONE_KERNEL);
   
    /*
    int i; 
    for (i = 0; i < mmap_size; i += PAGE_SIZE){
memset(mmap_buf + i, 'a', PAGE_SIZE);
memset(mmap_buf + i + PAGE_SIZE - 1, '\0', 1);
    }*/
    return 0;
}


module_init(wsmmap_init);
module_exit(wsmmap_exit);

MODULE_LICENSE("GPL");
MODULE_VERSION("1.0.0");
MODULE_DESCRIPTION("wskmmap");
MODULE_AUTHOR("wssys");

#####################################################

the userspace code is:
#####################################################
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>


#include <unistd.h>
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <string.h>

void handler(int sig)
{
#ifndef WIN32
void *array[10];
size_t size;
size = backtrace(array, 10);
int file_dump = open("/opt/dump.log", O_APPEND | O_RDWR);
char message[7] = "BEGIN ";
write(file_dump, message, 7);

time_t now;
struct tm *timenow;
char strtemp[255];

time(&now);  
timenow = localtime(&now);
sprintf(strtemp, "recent time is : %s\n", asctime(timenow));

int length=strlen(strtemp)+1;
write(file_dump, strtemp, length);

backtrace_symbols_fd(array, size, file_dump);

close(file_dump);

exit(1);
#endif
}


unsigned long phymem_addr = 0;
unsigned long phymem_size = 4*1024;

/*manage data*/
typedef struct {
   char *buffer;
   int length;
   volatile int start;
   volatile int end;
} RingBuffer;

RingBuffer *ring;
int read_dump;

#define RingBuffer_available_data(B) ((B)->end % (B)->length - (B)->start)
#define RingBuffer_starts_at(B) ((B)->buffer + (B)->start)
#define RingBuffer_commit_read(B, A) ((B)->start = ((B)->start + (A)) % (B)->length)
#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1)
#define RingBuffer_commit_write(B, A) ((B)->end = ((B)->end + (A)) % (B)->length)
#define RingBuffer_ends_at(B) ((B)->buffer + (B)->end)



int RingBuffer_read(RingBuffer *buffer, char *target, int amount)
{
      
       if (amount > RingBuffer_available_data(buffer)){
                printf("Not enough in the buffer: has %d, needs %d", RingBuffer_available_data(buffer), amount);
                return -1;
        }
 
     
        void *result = memcpy(target, RingBuffer_starts_at(buffer), amount);
     
        if (result != target){
                 printf("Failed to write buffer into data.");
                 return -1;
        }

  
       RingBuffer_commit_read(buffer, amount);
     
 
        if(buffer->end == buffer->start) {
                 buffer->start = buffer->end = 0;
        }
      
        
return amount;
}


void *thread_read(void *arg)
{
char mem_data[64];
int num = 2038;

while (num){
RingBuffer_read(ring, mem_data, 2);
mem_data[2] = '\0';
printf("read length is %d, start is %d, end is %d, data is %s\n", ring->length, ring->start, ring->end, mem_data);
--num;
sleep(1);
}
}

int main(void)
{
int fd;
int i=0;
void *mmap_addr = NULL;

signal(SIGSEGV, handler);   // install our handler

fd = open("/dev/wsmmap", O_RDWR);
if(fd < 0) {
perror("open");
return 0;
}

mmap_addr = mmap(NULL, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if(mmap_addr == MAP_FAILED) {
perror("mmap");
return 0;
}

ring = (RingBuffer *)mmap_addr;
ring->buffer = mmap_addr + sizeof(RingBuffer);

int res;
pthread_t t_read;
res = pthread_create(&t_read, NULL, thread_read, NULL);
if (res != 0){
perror("join failed");
return -1;
}

void *thread_r_read;
res = pthread_join(t_read, &thread_r_read);
if (res != 0){
perror("Thread join failed");
return -1;
}
free(mmap_addr);
mmap_addr=NULL;
        close(fd); 
    return 0;    
}

#####################################################

 
_______________________________________________
Kernelnewbies mailing list
Kernelnewbies@xxxxxxxxxxxxxxxxx
http://lists.kernelnewbies.org/mailman/listinfo/kernelnewbies

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux