This is impossible to let the kernel module and the userspace program read/write the same memory area at the same time ?
lx
lxlenovostar at gmail.com
Sat Aug 30 08:02:27 EDT 2014
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 at 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;
> }
>
> #####################################################
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20140830/dd7e21d9/attachment-0001.html
More information about the Kernelnewbies
mailing list