aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/mem.c39
-rw-r--r--fs/char_dev.c20
-rw-r--r--include/linux/cdev.h2
3 files changed, 61 insertions, 0 deletions
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 917b20402664..4ac70ec697f0 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -238,6 +238,32 @@ static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
238} 238}
239#endif 239#endif
240 240
241#ifndef CONFIG_MMU
242static unsigned long get_unmapped_area_mem(struct file *file,
243 unsigned long addr,
244 unsigned long len,
245 unsigned long pgoff,
246 unsigned long flags)
247{
248 if (!valid_mmap_phys_addr_range(pgoff, len))
249 return (unsigned long) -EINVAL;
250 return pgoff;
251}
252
253/* can't do an in-place private mapping if there's no MMU */
254static inline int private_mapping_ok(struct vm_area_struct *vma)
255{
256 return vma->vm_flags & VM_MAYSHARE;
257}
258#else
259#define get_unmapped_area_mem NULL
260
261static inline int private_mapping_ok(struct vm_area_struct *vma)
262{
263 return 1;
264}
265#endif
266
241static int mmap_mem(struct file * file, struct vm_area_struct * vma) 267static int mmap_mem(struct file * file, struct vm_area_struct * vma)
242{ 268{
243 size_t size = vma->vm_end - vma->vm_start; 269 size_t size = vma->vm_end - vma->vm_start;
@@ -245,6 +271,9 @@ static int mmap_mem(struct file * file, struct vm_area_struct * vma)
245 if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) 271 if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size))
246 return -EINVAL; 272 return -EINVAL;
247 273
274 if (!private_mapping_ok(vma))
275 return -ENOSYS;
276
248 vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, 277 vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff,
249 size, 278 size,
250 vma->vm_page_prot); 279 vma->vm_page_prot);
@@ -782,6 +811,7 @@ static const struct file_operations mem_fops = {
782 .write = write_mem, 811 .write = write_mem,
783 .mmap = mmap_mem, 812 .mmap = mmap_mem,
784 .open = open_mem, 813 .open = open_mem,
814 .get_unmapped_area = get_unmapped_area_mem,
785}; 815};
786 816
787static const struct file_operations kmem_fops = { 817static const struct file_operations kmem_fops = {
@@ -790,6 +820,7 @@ static const struct file_operations kmem_fops = {
790 .write = write_kmem, 820 .write = write_kmem,
791 .mmap = mmap_kmem, 821 .mmap = mmap_kmem,
792 .open = open_kmem, 822 .open = open_kmem,
823 .get_unmapped_area = get_unmapped_area_mem,
793}; 824};
794 825
795static const struct file_operations null_fops = { 826static const struct file_operations null_fops = {
@@ -815,6 +846,10 @@ static const struct file_operations zero_fops = {
815 .mmap = mmap_zero, 846 .mmap = mmap_zero,
816}; 847};
817 848
849/*
850 * capabilities for /dev/zero
851 * - permits private mappings, "copies" are taken of the source of zeros
852 */
818static struct backing_dev_info zero_bdi = { 853static struct backing_dev_info zero_bdi = {
819 .capabilities = BDI_CAP_MAP_COPY, 854 .capabilities = BDI_CAP_MAP_COPY,
820}; 855};
@@ -862,9 +897,13 @@ static int memory_open(struct inode * inode, struct file * filp)
862 switch (iminor(inode)) { 897 switch (iminor(inode)) {
863 case 1: 898 case 1:
864 filp->f_op = &mem_fops; 899 filp->f_op = &mem_fops;
900 filp->f_mapping->backing_dev_info =
901 &directly_mappable_cdev_bdi;
865 break; 902 break;
866 case 2: 903 case 2:
867 filp->f_op = &kmem_fops; 904 filp->f_op = &kmem_fops;
905 filp->f_mapping->backing_dev_info =
906 &directly_mappable_cdev_bdi;
868 break; 907 break;
869 case 3: 908 case 3:
870 filp->f_op = &null_fops; 909 filp->f_op = &null_fops;
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 3483d3cf8087..0009346d827f 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -19,11 +19,30 @@
19#include <linux/kobj_map.h> 19#include <linux/kobj_map.h>
20#include <linux/cdev.h> 20#include <linux/cdev.h>
21#include <linux/mutex.h> 21#include <linux/mutex.h>
22#include <linux/backing-dev.h>
22 23
23#ifdef CONFIG_KMOD 24#ifdef CONFIG_KMOD
24#include <linux/kmod.h> 25#include <linux/kmod.h>
25#endif 26#endif
26 27
28/*
29 * capabilities for /dev/mem, /dev/kmem and similar directly mappable character
30 * devices
31 * - permits shared-mmap for read, write and/or exec
32 * - does not permit private mmap in NOMMU mode (can't do COW)
33 * - no readahead or I/O queue unplugging required
34 */
35struct backing_dev_info directly_mappable_cdev_bdi = {
36 .capabilities = (
37#ifdef CONFIG_MMU
38 /* permit private copies of the data to be taken */
39 BDI_CAP_MAP_COPY |
40#endif
41 /* permit direct mmap, for read, write or exec */
42 BDI_CAP_MAP_DIRECT |
43 BDI_CAP_READ_MAP | BDI_CAP_WRITE_MAP | BDI_CAP_EXEC_MAP),
44};
45
27static struct kobj_map *cdev_map; 46static struct kobj_map *cdev_map;
28 47
29static DEFINE_MUTEX(chrdevs_lock); 48static DEFINE_MUTEX(chrdevs_lock);
@@ -461,3 +480,4 @@ EXPORT_SYMBOL(cdev_del);
461EXPORT_SYMBOL(cdev_add); 480EXPORT_SYMBOL(cdev_add);
462EXPORT_SYMBOL(register_chrdev); 481EXPORT_SYMBOL(register_chrdev);
463EXPORT_SYMBOL(unregister_chrdev); 482EXPORT_SYMBOL(unregister_chrdev);
483EXPORT_SYMBOL(directly_mappable_cdev_bdi);
diff --git a/include/linux/cdev.h b/include/linux/cdev.h
index 2216638962d2..ee5f53f2ca15 100644
--- a/include/linux/cdev.h
+++ b/include/linux/cdev.h
@@ -23,5 +23,7 @@ void cdev_del(struct cdev *);
23 23
24void cd_forget(struct inode *); 24void cd_forget(struct inode *);
25 25
26extern struct backing_dev_info directly_mappable_cdev_bdi;
27
26#endif 28#endif
27#endif 29#endif