<div dir="ltr"><div>hi all:</div><div><span class="" style="white-space:pre">        </span>I have a kernel module, it provide some functions:</div><div>1. vmalloc a 4KB memory space (I built a ring buffer manage the 4KB memory space)</div>
<div>2. provide the special mmap(), which can remap the memory space.</div><div>3. write some data into the 4KB memory space </div><div><br></div><div>And I have a userspace program, it provide some functions:</div><div>1.mmap the kernel memory space into userspace </div>
<div>2.read some data from that mmap space</div><div><br></div><div>The question is:</div><div>When I first insmod the kernel module until the data have written in the space, </div><div>I run the userspace program which read some data. This way is OK.</div>
<div>If I insmod the kernel module and run the userspace program at the same time, </div><div>the kernel will stop and computer will reboot. I think the kernel module is </div><div>writing the data and the userspace program is reading the data. </div>
<div><br></div><div>How to fix it, thank you!</div><div><br></div><div>the kernel module code is:</div><div>#####################################################</div><div>#include <linux/module.h></div><div>#include <linux/kernel.h></div>
<div>#include <linux/fs.h></div><div>#include <linux/errno.h></div><div>#include <linux/types.h></div><div>#include <linux/fcntl.h></div><div>#include <linux/cdev.h></div><div>#include <linux/version.h></div>
<div>#include <linux/vmalloc.h></div><div>#include <linux/ctype.h></div><div>#include <linux/pagemap.h></div><div>#include <linux/mm.h></div><div>#include <linux/slab.h></div><div>#include <linux/proc_fs.h></div>
<div>#include <asm/io.h></div><div>#include <asm/system.h></div><div>#include <linux/uaccess.h></div><div>#include <linux/timer.h></div><div>#include <linux/pid.h></div><div>#include <linux/sched.h></div>
<div>//#define USE_KMALLOC </div><div><br></div><div>#define PAGE_ORDER 0</div><div>#define PAGES_NUMBER 1</div><div><br></div><div>static int MAJOR_DEVICE = 30;</div><div>void * mmap_buf = 0;</div><div>unsigned long mmap_size = 4*1024;</div>
<div><br></div><div>static int ws_open(struct inode *inode, struct file *file)</div><div>{</div><div> return 0; </div><div>}</div><div><br></div><div><br></div><div>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36)<span class="" style="white-space:pre">        </span></div>
<div>#define LIN_IOCTL_NAME<span class="" style="white-space:pre">        </span>.ioctl</div><div>int ws_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long data)</div><div>#else</div><div>#define LIN_IOCTL_NAME<span class="" style="white-space:pre">        </span>.unlocked_ioctl</div>
<div>long ws_ioctl(struct file *file, u_int cmd, u_long data)</div><div>#endif</div><div>{</div><div> //todo</div><div> return 0; </div><div>}</div><div><br></div><div><br></div><div>int mmap_alloc(void)</div><div>
{</div><div> //struct page *page;</div><div> int i; </div><div> mmap_size = PAGE_ALIGN(mmap_size);</div><div><br></div><div> #ifdef USE_KMALLOC //for kmalloc</div><div> mmap_buf = kzalloc(mmap_size, GFP_KERNEL);</div>
<div> printk("kmalloc mmap_buf=%p\n", (void *)mmap_buf);</div><div> if (!mmap_buf) {</div><div><span class="" style="white-space:pre">        </span>printk("kmalloc failed!\n");</div><div> return -1;</div>
<div> }</div><div> for (page = virt_to_page(mmap_buf); page < virt_to_page(mmap_buf + mmap_size); page++) {</div><div> SetPageReserved(page);</div><div><span class="" style="white-space:pre">        </span>strcpy((void *)mmap_buf, "Hello world!\n");</div>
<div> }</div><div> #else //for vmalloc</div><div> mmap_buf = vmalloc(mmap_size);</div><div> printk("vmalloc mmap_buf=%p mmap_size=%ld\n", (void *)mmap_buf, mmap_size);</div><div> if (!mmap_buf ) {</div>
<div><span class="" style="white-space:pre">        </span>printk("vmalloc failed!\n");</div><div> return -1;</div><div> }</div><div> for (i = 0; i < mmap_size; i += PAGE_SIZE) {</div><div> SetPageReserved(vmalloc_to_page(mmap_buf + i));</div>
<div> }</div><div> #endif</div><div><br></div><div> return 0;</div><div>}</div><div><br></div><div><br></div><div>int mmap_free(void)</div><div>{</div><div> #ifdef USE_KMALLOC</div><div> struct page *page;</div>
<div> for (page = virt_to_page(mmap_buf); page < virt_to_page(mmap_buf + mmap_size); page++) {</div><div> ClearPageReserved(page);</div><div> }</div><div> kfree((void *)mmap_buf);</div><div> #else</div>
<div> int i;</div><div> for (i = 0; i < mmap_size; i += PAGE_SIZE) {</div><div> ClearPageReserved(vmalloc_to_page(mmap_buf + i));</div><div> }</div><div> vfree((void *)mmap_buf);</div><div> #endif</div>
<div> mmap_buf = NULL;</div><div> return 0;</div><div>}</div><div><br></div><div><br></div><div>static int ws_mmap(struct file *f, struct vm_area_struct *vma)</div><div>{</div><div> int ret;</div><div> unsigned long pfn;</div>
<div> unsigned long start = vma->vm_start;</div><div> unsigned long size = PAGE_ALIGN(vma->vm_end - vma->vm_start);</div><div> void * ptmp = mmap_buf;</div><div> if (size > mmap_size || !mmap_buf) {</div>
<div> return -EINVAL;</div><div> }</div><div> </div><div> #ifdef USE_KMALLOC</div><div><span class="" style="white-space:pre">        </span>pfn = virt_to_phys(mmap_buf) >> PAGE_SHIFT;</div><div> return remap_pfn_range(vma, start, pfn, size, PAGE_SHARED);</div>
<div> #else</div><div> /* loop over all pages, map it page individually */</div><div> while (size > 0) {</div><div> pfn = vmalloc_to_pfn(ptmp);</div><div> if ((ret = remap_pfn_range(vma, start, pfn, PAGE_SIZE, PAGE_SHARED)) < 0) {</div>
<div> return ret;</div><div> }</div><div> start += PAGE_SIZE;</div><div> ptmp += PAGE_SIZE;</div><div> size -= PAGE_SIZE;</div><div> }</div><div> #endif</div><div> return 0;</div>
<div> </div><div>}</div><div><br></div><div><br></div><div>static int ws_release(struct inode *inode, struct file *file)</div><div>{</div><div> return 0;</div><div>}</div><div><br></div><div><br></div><div>static const struct file_operations ws_fops ={ </div>
<div> .owner = THIS_MODULE,</div><div> //.write = ws_write,</div><div> //.read = ws_read,</div><div> .mmap = ws_mmap,</div><div> //.ioctl = ws_ioctl,</div><div> //.open = ws_open,</div><div> //.release = ws_release,</div>
<div>};</div><div><br></div><div>static void wsmmap_exit(void)</div><div>{</div><div> if( 0 != mmap_free( ))</div><div> printk("mmap free failed!\n");</div><div> unregister_chrdev(MAJOR_DEVICE,"wsmmap"); </div>
<div> printk("rmmod wsmmap module!\n");</div><div> </div><div>}</div><div><br></div><div><br></div><div>/*manage data*/</div><div>typedef struct {</div><div> char *buffer;</div><div> int length;</div>
<div> volatile int start;</div><div> volatile int end;</div><div>} RingBuffer;</div><div><br></div><div>RingBuffer * ring_buffer;</div><div><br></div><div>RingBuffer *RingBuffer_create(void *start_malloc, int length)</div>
<div>{</div><div> RingBuffer *buffer = (RingBuffer *)start_malloc;</div><div> buffer->length = length + 1;</div><div> buffer->start = 0;</div><div> buffer->end = 0;</div><div> buffer->buffer = (char *)start_malloc + sizeof(RingBuffer);</div>
<div><br></div><div><span class="" style="white-space:pre">        </span>return buffer;</div><div>}</div><div><br></div><div>#define RingBuffer_available_data(B) ((B)->end % (B)->length - (B)->start)</div><div>#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1)</div>
<div>#define RingBuffer_commit_write(B, A) ((B)->end = ((B)->end + (A)) % (B)->length)</div><div>#define RingBuffer_ends_at(B) ((B)->buffer + (B)->end)</div><div><br></div><div>int RingBuffer_write(RingBuffer *buffer, char *data, int length)</div>
<div>{</div><div><span class="" style="white-space:pre">        </span></div><div><span class="" style="white-space:pre">        </span>if(RingBuffer_available_data(buffer) == 0) {</div><div><span class="" style="white-space:pre">                </span>buffer->start = buffer->end = 0;</div>
<div><span class="" style="white-space:pre">        </span>}</div><div><br></div><div><span class="" style="white-space:pre">        </span></div><div><span class="" style="white-space:pre">        </span>if (length > RingBuffer_available_space(buffer)){</div>
<div><span class="" style="white-space:pre">                </span>printk("Not enough space: %d request, %d available", RingBuffer_available_data(buffer), length);</div><div><span class="" style="white-space:pre">                </span>return -1;</div>
<div><span class="" style="white-space:pre">        </span>}</div><div><br></div><div><span class="" style="white-space:pre">        </span>void *result = memcpy(RingBuffer_ends_at(buffer), data, length);</div><div><span class="" style="white-space:pre">        </span></div>
<div><span class="" style="white-space:pre">        </span>if (result != RingBuffer_ends_at(buffer)){</div><div><span class="" style="white-space:pre">                </span>printk("Failed to write data into buffer.");</div><div><span class="" style="white-space:pre">                </span>return -1;</div>
<div><span class="" style="white-space:pre">        </span>}</div><div><span class="" style="white-space:pre">        </span></div><div><span class="" style="white-space:pre">        </span>RingBuffer_commit_write(buffer, length);</div><div><br>
</div><div><span class="" style="white-space:pre">        </span>return length;</div><div>}</div><div><br></div><div><br></div><div>int kernel_thread_write(void *argc)</div><div>{</div><div><span class="" style="white-space:pre">        </span> char *a = "aa";</div>
<div><span class="" style="white-space:pre">        </span> int num = 2038;</div><div><span class="" style="white-space:pre">        </span> while (num){</div><div><span class="" style="white-space:pre">                </span> RingBuffer_write(ring_buffer, a, 2);</div>
<div><span class="" style="white-space:pre">                </span> printk("write length is %d, start is %d, end is %d\n", ring_buffer->length, ring_buffer->start, ring_buffer->end);</div><div><span class="" style="white-space:pre">                </span> --num;</div>
<div><span class="" style="white-space:pre">                </span> msleep(10);</div><div><span class="" style="white-space:pre">        </span> }</div><div><span class="" style="white-space:pre">        </span>return 0;</div><div>}</div><div><br></div>
<div>int wsmmap_init(void)</div><div>{</div><div> //int i;</div><div> if(register_chrdev(MAJOR_DEVICE, "wsmmap", &ws_fops))</div><div> <span class="" style="white-space:pre">        </span> printk("Cannot register mmap device as major device 0!\n");</div>
<div> <span class="" style="white-space:pre">        </span>else </div><div> printk("wsmmap device driver registed sucessfully!\n"); </div><div> printk("insmod wsmmap module successfully!\n"); </div>
<div> if(0 != mmap_alloc( ))</div><div> printk("mmap alloc failed!\n");</div><div><br></div><div> /*</div><div> * Initialization RingBuffer</div><div> */</div><div> ring_buffer = RingBuffer_create(mmap_buf, mmap_size - sizeof(RingBuffer) - 1);</div>
<div><br></div><div> kernel_thread(kernel_thread_write, NULL, CLONE_KERNEL);</div><div> </div><div> /*</div><div> int i; </div><div> for (i = 0; i < mmap_size; i += PAGE_SIZE){</div><div><span class="" style="white-space:pre">        </span>memset(mmap_buf + i, 'a', PAGE_SIZE);</div>
<div><span class="" style="white-space:pre">        </span>memset(mmap_buf + i + PAGE_SIZE - 1, '\0', 1);</div><div> }*/</div><div> return 0;</div><div>}</div><div><br></div><div><br></div><div>module_init(wsmmap_init);</div>
<div>module_exit(wsmmap_exit);</div><div><br></div><div>MODULE_LICENSE("GPL");</div><div>MODULE_VERSION("1.0.0");</div><div>MODULE_DESCRIPTION("wskmmap");</div><div>MODULE_AUTHOR("wssys");</div>
<div><br></div><div>#####################################################</div><div><br></div><div>the userspace code is:</div><div>#####################################################</div><div>#include <stdio.h></div>
<div>#include <stdlib.h></div><div>#include <unistd.h></div><div>#include <sys/mman.h></div><div>#include <sys/types.h></div><div>#include <sys/stat.h></div><div>#include <fcntl.h></div>
<div>#include <string.h></div><div>#include <unistd.h></div><div>#include <pthread.h></div><div><br></div><div><br></div><div>#include <unistd.h></div><div>#include <stdio.h></div><div>#include <execinfo.h></div>
<div>#include <signal.h></div><div>#include <stdlib.h></div><div>#include <sys/types.h></div><div>#include <sys/stat.h></div><div>#include <fcntl.h></div><div>#include <time.h></div><div>
#include <string.h></div><div><br></div><div>void handler(int sig)</div><div>{</div><div>#ifndef WIN32</div><div><span class="" style="white-space:pre">        </span>void *array[10];</div><div><span class="" style="white-space:pre">        </span>size_t size;</div>
<div><span class="" style="white-space:pre">        </span>size = backtrace(array, 10);</div><div><span class="" style="white-space:pre">        </span>int file_dump = open("/opt/dump.log", O_APPEND | O_RDWR);</div><div><span class="" style="white-space:pre">        </span>char message[7] = "BEGIN ";</div>
<div><span class="" style="white-space:pre">        </span>write(file_dump, message, 7);</div><div><br></div><div><span class="" style="white-space:pre">        </span>time_t now;</div><div><span class="" style="white-space:pre">        </span>struct tm *timenow;</div>
<div><span class="" style="white-space:pre">        </span>char strtemp[255];</div><div><br></div><div><span class="" style="white-space:pre">        </span>time(&now); </div><div><span class="" style="white-space:pre">        </span>timenow = localtime(&now);</div>
<div><span class="" style="white-space:pre">        </span>sprintf(strtemp, "recent time is : %s\n", asctime(timenow));</div><div><br></div><div><span class="" style="white-space:pre">        </span>int length=strlen(strtemp)+1;</div>
<div><span class="" style="white-space:pre">        </span>write(file_dump, strtemp, length);</div><div><br></div><div><span class="" style="white-space:pre">        </span>backtrace_symbols_fd(array, size, file_dump);</div><div><br></div>
<div><span class="" style="white-space:pre">        </span>close(file_dump);</div><div><br></div><div><span class="" style="white-space:pre">        </span>exit(1);</div><div>#endif</div><div>}</div><div><br></div><div><br></div><div>unsigned long phymem_addr = 0;</div>
<div>unsigned long phymem_size = 4*1024;</div><div><br></div><div>/*manage data*/</div><div>typedef struct {</div><div> char *buffer;</div><div> int length;</div><div> volatile int start;</div><div> volatile int end;</div>
<div>} RingBuffer;</div><div><br></div><div>RingBuffer *ring;</div><div>int read_dump;</div><div><br></div><div>#define RingBuffer_available_data(B) ((B)->end % (B)->length - (B)->start)</div><div>#define RingBuffer_starts_at(B) ((B)->buffer + (B)->start)</div>
<div>#define RingBuffer_commit_read(B, A) ((B)->start = ((B)->start + (A)) % (B)->length)</div><div>#define RingBuffer_available_space(B) ((B)->length - (B)->end - 1)</div><div>#define RingBuffer_commit_write(B, A) ((B)->end = ((B)->end + (A)) % (B)->length)</div>
<div>#define RingBuffer_ends_at(B) ((B)->buffer + (B)->end)</div><div><br></div><div><br></div><div><br></div><div>int RingBuffer_read(RingBuffer *buffer, char *target, int amount)</div><div>{</div><div> </div>
<div> if (amount > RingBuffer_available_data(buffer)){</div><div> printf("Not enough in the buffer: has %d, needs %d", RingBuffer_available_data(buffer), amount);</div><div> return -1;</div>
<div> }</div><div> </div><div> </div><div> void *result = memcpy(target, RingBuffer_starts_at(buffer), amount);</div><div> </div><div> if (result != target){</div><div> printf("Failed to write buffer into data.");</div>
<div> return -1;</div><div> }</div><div><br></div><div> </div><div> RingBuffer_commit_read(buffer, amount);</div><div> </div><div> </div><div> if(buffer->end == buffer->start) {</div>
<div> buffer->start = buffer->end = 0;</div><div> }</div><div> </div><div> </div><div><span class="" style="white-space:pre">        </span>return amount;</div><div>}</div><div><br></div>
<div><br></div><div>void *thread_read(void *arg)</div><div>{</div><div><span class="" style="white-space:pre">        </span>char mem_data[64];</div><div><span class="" style="white-space:pre">        </span>int num = 2038;</div><div><br>
</div><div><span class="" style="white-space:pre">        </span>while (num){</div><div><span class="" style="white-space:pre">                </span>RingBuffer_read(ring, mem_data, 2);</div><div><span class="" style="white-space:pre">                </span>mem_data[2] = '\0';</div>
<div><span class="" style="white-space:pre">                </span>printf("read length is %d, start is %d, end is %d, data is %s\n", ring->length, ring->start, ring->end, mem_data);</div><div><span class="" style="white-space:pre">                </span>--num;</div>
<div><span class="" style="white-space:pre">                </span>sleep(1);</div><div><span class="" style="white-space:pre">        </span>}</div><div>}</div><div><br></div><div>int main(void)</div><div>{</div><div><span class="" style="white-space:pre">        </span>int fd;</div>
<div><span class="" style="white-space:pre">        </span>int i=0;</div><div><span class="" style="white-space:pre">        </span>void *mmap_addr = NULL;</div><div><br></div><div><span class="" style="white-space:pre">        </span>signal(SIGSEGV, handler); // install our handler</div>
<div><br></div><div><span class="" style="white-space:pre">        </span>fd = open("/dev/wsmmap", O_RDWR);</div><div><span class="" style="white-space:pre">        </span>if(fd < 0) {</div><div><span class="" style="white-space:pre">                </span>perror("open");</div>
<div><span class="" style="white-space:pre">                </span>return 0;</div><div><span class="" style="white-space:pre">        </span>}</div><div><br></div><div><span class="" style="white-space:pre">        </span>mmap_addr = mmap(NULL, phymem_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);</div>
<div><span class="" style="white-space:pre">        </span>if(mmap_addr == MAP_FAILED) {</div><div><span class="" style="white-space:pre">                </span>perror("mmap");</div><div><span class="" style="white-space:pre">        </span> <span class="" style="white-space:pre">        </span>return 0;</div>
<div><span class="" style="white-space:pre">        </span>}</div><div><br></div><div><span class="" style="white-space:pre">        </span>ring = (RingBuffer *)mmap_addr;</div><div><span class="" style="white-space:pre">        </span>ring->buffer = mmap_addr + sizeof(RingBuffer);<span class="" style="white-space:pre">        </span></div>
<div><br></div><div><span class="" style="white-space:pre">        </span></div><div><span class="" style="white-space:pre">        </span>int res;</div><div><span class="" style="white-space:pre">        </span>pthread_t t_read;</div><div><span class="" style="white-space:pre">        </span></div>
<div><span class="" style="white-space:pre">        </span>res = pthread_create(&t_read, NULL, thread_read, NULL);</div><div><span class="" style="white-space:pre">        </span>if (res != 0){</div><div><span class="" style="white-space:pre">                </span>perror("join failed");</div>
<div><span class="" style="white-space:pre">                </span>return -1;</div><div><span class="" style="white-space:pre">        </span>}</div><div><br></div><div><span class="" style="white-space:pre">        </span>void *thread_r_read;</div>
<div><span class="" style="white-space:pre">        </span>res = pthread_join(t_read, &thread_r_read);</div><div><span class="" style="white-space:pre">        </span>if (res != 0){</div><div><span class="" style="white-space:pre">                </span>perror("Thread join failed");</div>
<div><span class="" style="white-space:pre">                </span>return -1;</div><div><span class="" style="white-space:pre">        </span>}</div><div><span class="" style="white-space:pre">        </span></div><div><span class="" style="white-space:pre">        </span>free(mmap_addr);</div>
<div><span class="" style="white-space:pre">        </span>mmap_addr=NULL;</div><div> <span class="" style="white-space:pre">        </span>close(fd); </div><div> <span class="" style="white-space:pre">        </span>return 0; </div>
<div>}</div><div><br></div><div>#####################################################</div><div><br></div><div> </div></div>