diff options
-rw-r--r-- | drivers/char/mem.c | 39 | ||||
-rw-r--r-- | fs/char_dev.c | 20 | ||||
-rw-r--r-- | include/linux/cdev.h | 2 |
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 | ||
242 | static 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 */ | ||
254 | static 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 | |||
261 | static inline int private_mapping_ok(struct vm_area_struct *vma) | ||
262 | { | ||
263 | return 1; | ||
264 | } | ||
265 | #endif | ||
266 | |||
241 | static int mmap_mem(struct file * file, struct vm_area_struct * vma) | 267 | static 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 | ||
787 | static const struct file_operations kmem_fops = { | 817 | static 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 | ||
795 | static const struct file_operations null_fops = { | 826 | static 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 | */ | ||
818 | static struct backing_dev_info zero_bdi = { | 853 | static 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 | */ | ||
35 | struct 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 | |||
27 | static struct kobj_map *cdev_map; | 46 | static struct kobj_map *cdev_map; |
28 | 47 | ||
29 | static DEFINE_MUTEX(chrdevs_lock); | 48 | static DEFINE_MUTEX(chrdevs_lock); |
@@ -461,3 +480,4 @@ EXPORT_SYMBOL(cdev_del); | |||
461 | EXPORT_SYMBOL(cdev_add); | 480 | EXPORT_SYMBOL(cdev_add); |
462 | EXPORT_SYMBOL(register_chrdev); | 481 | EXPORT_SYMBOL(register_chrdev); |
463 | EXPORT_SYMBOL(unregister_chrdev); | 482 | EXPORT_SYMBOL(unregister_chrdev); |
483 | EXPORT_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 | ||
24 | void cd_forget(struct inode *); | 24 | void cd_forget(struct inode *); |
25 | 25 | ||
26 | extern struct backing_dev_info directly_mappable_cdev_bdi; | ||
27 | |||
26 | #endif | 28 | #endif |
27 | #endif | 29 | #endif |