From: David Howells Set the backing device info capabilities for /dev/mem and /dev/kmem to permit direct sharing under no-MMU conditions and full mapping capabilities under MMU conditions. Make the BDI used by these available to all directly mappable character devices. Also comment the capabilities for /dev/zero. Signed-off-by: David Howells Signed-off-by: Andrew Morton --- drivers/char/mem.c | 33 +++++++++++++++++++++++++++++++++ fs/char_dev.c | 20 ++++++++++++++++++++ include/linux/cdev.h | 2 ++ 3 files changed, 55 insertions(+) diff -puN drivers/char/mem.c~nommu-set-bdi-capabilities-for-dev-mem-and-dev-kmem drivers/char/mem.c --- a/drivers/char/mem.c~nommu-set-bdi-capabilities-for-dev-mem-and-dev-kmem +++ a/drivers/char/mem.c @@ -238,6 +238,19 @@ static pgprot_t phys_mem_access_prot(str } #endif +#ifndef CONFIG_MMU +static unsigned long get_unmapped_area_mem(struct file *file, + unsigned long addr, + unsigned long len, + unsigned long pgoff, + unsigned long flags) +{ + if (!valid_mmap_phys_addr_range(pgoff, len)) + return (unsigned long) -EINVAL; + return pgoff; +} +#endif + static int mmap_mem(struct file * file, struct vm_area_struct * vma) { size_t size = vma->vm_end - vma->vm_start; @@ -245,6 +258,12 @@ static int mmap_mem(struct file * file, if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) return -EINVAL; +#ifndef CONFIG_MMU + /* can't do an in-place private mapping if there's no MMU */ + if (!(vma->vm_flags & VM_MAYSHARE)) + return -ENOSYS; +#endif + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot); @@ -782,6 +801,9 @@ static const struct file_operations mem_ .write = write_mem, .mmap = mmap_mem, .open = open_mem, +#ifndef CONFIG_MMU + .get_unmapped_area = get_unmapped_area_mem, +#endif }; static const struct file_operations kmem_fops = { @@ -790,6 +812,9 @@ static const struct file_operations kmem .write = write_kmem, .mmap = mmap_kmem, .open = open_kmem, +#ifndef CONFIG_MMU + .get_unmapped_area = get_unmapped_area_mem, +#endif }; static const struct file_operations null_fops = { @@ -815,6 +840,10 @@ static const struct file_operations zero .mmap = mmap_zero, }; +/* + * capabilities for /dev/zero + * - permits private mappings, "copies" are taken of the source of zeros + */ static struct backing_dev_info zero_bdi = { .capabilities = BDI_CAP_MAP_COPY, }; @@ -862,9 +891,13 @@ static int memory_open(struct inode * in switch (iminor(inode)) { case 1: filp->f_op = &mem_fops; + filp->f_mapping->backing_dev_info = + &directly_mappable_cdev_bdi; break; case 2: filp->f_op = &kmem_fops; + filp->f_mapping->backing_dev_info = + &directly_mappable_cdev_bdi; break; case 3: filp->f_op = &null_fops; diff -puN fs/char_dev.c~nommu-set-bdi-capabilities-for-dev-mem-and-dev-kmem fs/char_dev.c --- a/fs/char_dev.c~nommu-set-bdi-capabilities-for-dev-mem-and-dev-kmem +++ a/fs/char_dev.c @@ -19,12 +19,31 @@ #include #include #include +#include #ifdef CONFIG_KMOD #include #endif #include "internal.h" +/* + * capabilities for /dev/mem, /dev/kmem and similar directly mappable character + * devices + * - permits shared-mmap for read, write and/or exec + * - does not permit private mmap in NOMMU mode (can't do COW) + * - no readahead or I/O queue unplugging required + */ +struct backing_dev_info directly_mappable_cdev_bdi = { + .capabilities = ( +#ifdef CONFIG_MMU + /* permit private copies of the data to be taken */ + BDI_CAP_MAP_COPY | +#endif + /* permit direct mmap, for read, write or exec */ + BDI_CAP_MAP_DIRECT | + BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP), +}; + static struct kobj_map *cdev_map; static DEFINE_MUTEX(chrdevs_lock); @@ -462,3 +481,4 @@ EXPORT_SYMBOL(cdev_del); EXPORT_SYMBOL(cdev_add); EXPORT_SYMBOL(register_chrdev); EXPORT_SYMBOL(unregister_chrdev); +EXPORT_SYMBOL(directly_mappable_cdev_bdi); diff -puN include/linux/cdev.h~nommu-set-bdi-capabilities-for-dev-mem-and-dev-kmem include/linux/cdev.h --- a/include/linux/cdev.h~nommu-set-bdi-capabilities-for-dev-mem-and-dev-kmem +++ a/include/linux/cdev.h @@ -23,5 +23,7 @@ void cdev_del(struct cdev *); void cd_forget(struct inode *); +extern struct backing_dev_info directly_mappable_cdev_bdi; + #endif #endif _