本文共 7319 字,大约阅读时间需要 24 分钟。
mmap will establish a mapping between kernel and userspace, We can use it to read data from kernel more quickly.
mmap is a function pointer in driver, so we have to write a driver to realize it, a simple char device driver is enough.If you don't know how to write a simple char device driver, my code also can help you know it.I descript the process as below:1. define a mmap function for struct file_operations, which will register as a driver.2. When userspace call mmap(system call), file_operations->mmap() will be called.3. file_operations->mmap should call remap_page_range() to map the memory between userspace and kernel space.4. userspace call mmap actively, mmap return a void pointer. Now If userspace modify the pointer's content, kernel will be modified at the same time.here is also some link which maybe can help you:1. has a sample too: http://linux.insigma.com.cn/devbbs/printpage.asp?BoardID=14&ID=1002. has a userspace sample too: http://www.opengroup.org/onlinepubs/009695399/functions/mmap.html3. "man mmap" will help you more, such as the difference between MAP_SHARED and MAP_PRIVATE.4. Linux Device Driver(ldd2) has some introduce about mmap. (Section 13)Note:1. We should malloc whole page memory in kernel for map.2. A non-regular file can't be map to write.3. The size that userspace request to map, will be changed to whole page then sent to kernel.below is code:kernel module: mmap.cCode:#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/slab.h>#include <asm/uaccess.h>#include <linux/wrapper.h>#include <asm/io.h>MODULE_PARM(mmap_major, "i");MODULE_PARM(mmap_nr_devs, "i");#define DEVICE "mmap"#define DATASIZE PAGE_SIZE<<3int mmap_major = 0;int mmap_nr_devs = 1;typedef struct mmap_state{ char data[DATASIZE]; unsigned int size; void *handle; unsigned int access_key; struct semaphore sem;}mmap_state;#define TYPE(dev) (MINOR(dev) >>4)#define NUM(dev) (MINOR(dev) &0xf)int mmap_open(struct inode *inode, struct file *filp);ssize_t mmap_read(struct file *filp, char *buf, size_t count, loff_t *f_pos);ssize_t mmap_write(struct file *filp,const char *buf,size_t count,loff_t *f_pos);int mmap_release(struct inode *inode, struct file *filp);static int mmap_mmap(struct file * file, struct vm_area_struct * vma);int mmap_trim(mmap_state *dev);int mmap_init_module(void);void mmap_cleanup_module(void);struct file_operations mmap_fops = { open: mmap_open, read: mmap_read, write: mmap_write, llseek: NULL, ioctl: NULL, release: mmap_release, mmap: mmap_mmap,};mmap_state *mmap_devices;int mmap_open(struct inode *inode, struct file *filp){ mmap_state *dev; int num = NUM(inode->i_rdev); int type = TYPE(inode->i_rdev); if (!filp->private_data && type) { printk(KERN_WARNING"data is not valid/n"); return 0; } dev = (mmap_state *)filp->private_data; if (!dev) { if (num >= mmap_nr_devs) return -ENODEV; dev = &mmap_devices[num]; filp->private_data = dev; } MOD_INC_USE_COUNT; if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) { if (down_interruptible(&dev->sem)) { MOD_DEC_USE_COUNT; return -ERESTARTSYS; } mmap_trim(dev); up(&dev->sem); } return 0;}static int mmap_mmap(struct file * file, struct vm_area_struct * vma){ struct mmap_state *state = (struct mmap_state *)file->private_data; unsigned long size; int ret = -EINVAL; //printk("mmap_mmap()/n"); if (vma->vm_pgoff != 0) { printk(" vm_pgoff != 0/n"); goto error; } /* Don't try to swap out physical pages.. */ vma->vm_flags |= VM_RESERVED; size = vma->vm_end - vma->vm_start; //printk(" data = [%p]/n", state->data); //printk(" content = [%s]/n", state->data); //printk(" start=[%lu] size=[%lu] end=[%lu]/n", vma->vm_start, size, vma->vm_end); if (size > state->size) goto error; if (remap_page_range( vma->vm_start, virt_to_phys(state->data), size, vma->vm_page_prot)) return -EAGAIN; //printk("mmap_mmap() success/n"); return 0;error: return ret;}int mmap_release(struct inode *inode, struct file *filp){ MOD_DEC_USE_COUNT; return 0;}ssize_t mmap_read(struct file *filp, char *buf, size_t count, loff_t *f_pos){ int ret = 0; mmap_state *dev = filp->private_data; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (*f_pos >= dev->size) goto out; if (*f_pos + count > dev->size) count = dev->size - *f_pos; if (copy_to_user(buf, &dev->data[*f_pos], count)) { ret = -EFAULT; goto out; } *f_pos += count; ret = count;out: up(&dev->sem); return ret;}ssize_tmmap_write(struct file *filp, const char *buf, size_t count,loff_t *f_pos){ int ret = 0; mmap_state *dev = filp->private_data; if (down_interruptible(&dev->sem)) return -ERESTARTSYS; if (*f_pos + count > dev->size) count = dev->size - *f_pos; if (copy_from_user(&dev->data[*f_pos], buf, count)) { ret = -EFAULT; goto out; } *f_pos += count; ret = count; if (dev->size < *f_pos) dev->size = *f_pos; out: up(&dev->sem); return ret;}int mmap_trim(mmap_state *dev){ memset(dev->data, 0, sizeof(dev->data)); return 0;}int mmap_init_module(void){ int result, i; struct page *page; SET_MODULE_OWNER(&mmap_fops); result = register_chrdev(mmap_major, DEVICE, &mmap_fops); if (result < 0) { printk(KERN_WARNING "mmap:cann't get major %d/n", mmap_major); return result; } if (mmap_major == 0) mmap_major = result; mmap_devices = kmalloc(mmap_nr_devs*sizeof(mmap_state),GFP_KERNEL); if (!mmap_devices) { result = -ENOMEM; goto fail; } memset(mmap_devices, 0, mmap_nr_devs * sizeof(mmap_state)); for (i = 0; i < mmap_nr_devs; i++) { memset(mmap_devices[i].data, 0, sizeof(mmap_devices[i].data)); strcpy(mmap_devices[i].data, "aaa"); mmap_devices[i].size = DATASIZE; /* Note here: if miss it, user space will get NULL */ for (page = virt_to_page(mmap_devices[i].data); page <= virt_to_page(mmap_devices[i].data + (DATASIZE)); page++) { mem_map_reserve(page); } sema_init(&mmap_devices[i].sem, 1); } EXPORT_NO_SYMBOLS; return 0;fail: mmap_cleanup_module(); return result;}void mmap_cleanup_module(void){ int i; unregister_chrdev(mmap_major, DEVICE); if (mmap_devices) { for (i = 0; i < mmap_nr_devs; i++) mmap_trim(mmap_devices + i); kfree(mmap_devices); }}module_init(mmap_init_module);module_exit(mmap_cleanup_module);MODULE_LICENSE("GPL");EXPORT_NO_SYMBOLS;Makefile here:Code:KERNELDIR = /usr/src/linuxinclude $(KERNELDIR)/.configCFLAGS = -DEXPORT_SYMTAB -D__KERNEL__ -DMODULE -I$(KERNELDIR)/include -O -Wallifdef CONFIG_SMP CFLAGS += -D__SMP__ -DSMPendififdef CONFIG_MODVERSIONS CFLAGS += -DMODVERSIONS / -include $(KERNELDIR)/include/linux/modversions.hendifOBJ=mmap.oall:$(OBJ)clean: rm -f *.ouserspace: mmap_user.cCode:#include <sys/mman.h>#include <stdio.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>int main(){ char *ptr = NULL; int fd = open("/dev/mmap0", O_RDWR); if (fd <= 0) { printf("open fail/n"); return 1; } ptr = mmap(0, 90, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); printf("ptr = [%s]/n", ptr); ptr[2] = 'c'; printf("ptr = [%s]/n", ptr);}here is also a script to register a device:Code:#!/bin/shmodule="mmap"device="mmap"mode="664"/sbin/insmod ./$module.o $* || exit 1major=`cat /proc/devices | awk "//$2==/"$device/" {print //$1}"`echo $majorrm -f /dev/${ device}[0-3]mknod /dev/${ device}0 c $major 0ln -sf ${ device}0 /dev/${ device}转载地址:http://zssqi.baihongyu.com/