This is impossible to let the kernel module and the userspace program read/write the same memory area at the same time ?
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; } #####################################################
hi all: I make a error: ################## ring->buffer = mmap_addr + sizeof(RingBuffer); ################## the codes in the userspace program will let the kernel module access the userspace virtual address. 2014-08-30 17:17 GMT+08:00 lx <lxlenovostar@gmail.com>:
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; }
#####################################################
participants (1)
-
lx