diff options
-rw-r--r-- | Documentation/nommu-mmap.txt | 24 | ||||
-rw-r--r-- | mm/nommu.c | 63 |
2 files changed, 70 insertions, 17 deletions
diff --git a/Documentation/nommu-mmap.txt b/Documentation/nommu-mmap.txt index 83f4b083d57e..3ce890664936 100644 --- a/Documentation/nommu-mmap.txt +++ b/Documentation/nommu-mmap.txt | |||
@@ -128,6 +128,30 @@ FURTHER NOTES ON NO-MMU MMAP | |||
128 | error will result if they don't. This is most likely to be encountered | 128 | error will result if they don't. This is most likely to be encountered |
129 | with character device files, pipes, fifos and sockets. | 129 | with character device files, pipes, fifos and sockets. |
130 | 130 | ||
131 | |||
132 | ============= | ||
133 | NO-MMU MREMAP | ||
134 | ============= | ||
135 | |||
136 | The mremap() function is partially supported. It may change the size of a | ||
137 | mapping, and may move it[*] if MREMAP_MAYMOVE is specified and if the new size | ||
138 | of the mapping exceeds the size of the slab object currently occupied by the | ||
139 | memory to which the mapping refers, or if a smaller slab object could be used. | ||
140 | |||
141 | MREMAP_FIXED is not supported, though it is ignored if there's no change of | ||
142 | address and the object does not need to be moved. | ||
143 | |||
144 | Shared mappings may not be moved. Shareable mappings may not be moved either, | ||
145 | even if they are not currently shared. | ||
146 | |||
147 | The mremap() function must be given an exact match for base address and size of | ||
148 | a previously mapped object. It may not be used to create holes in existing | ||
149 | mappings, move parts of existing mappings or resize parts of mappings. It must | ||
150 | act on a complete mapping. | ||
151 | |||
152 | [*] Not currently supported. | ||
153 | |||
154 | |||
131 | ============================================ | 155 | ============================================ |
132 | PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT | 156 | PROVIDING SHAREABLE CHARACTER DEVICE SUPPORT |
133 | ============================================ | 157 | ============================================ |
diff --git a/mm/nommu.c b/mm/nommu.c index 4f87b2f43a2b..23cfa8ec914a 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -350,6 +350,26 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) | |||
350 | EXPORT_SYMBOL(find_vma); | 350 | EXPORT_SYMBOL(find_vma); |
351 | 351 | ||
352 | /* | 352 | /* |
353 | * look up the first VMA exactly that exactly matches addr | ||
354 | * - should be called with mm->mmap_sem at least held readlocked | ||
355 | */ | ||
356 | static inline struct vm_area_struct *find_vma_exact(struct mm_struct *mm, | ||
357 | unsigned long addr) | ||
358 | { | ||
359 | struct vm_list_struct *vml; | ||
360 | |||
361 | /* search the vm_start ordered list */ | ||
362 | for (vml = mm->context.vmlist; vml; vml = vml->next) { | ||
363 | if (vml->vma->vm_start == addr) | ||
364 | return vml->vma; | ||
365 | if (vml->vma->vm_start > addr) | ||
366 | break; | ||
367 | } | ||
368 | |||
369 | return NULL; | ||
370 | } | ||
371 | |||
372 | /* | ||
353 | * find a VMA in the global tree | 373 | * find a VMA in the global tree |
354 | */ | 374 | */ |
355 | static inline struct vm_area_struct *find_nommu_vma(unsigned long start) | 375 | static inline struct vm_area_struct *find_nommu_vma(unsigned long start) |
@@ -1071,20 +1091,20 @@ unsigned long do_brk(unsigned long addr, unsigned long len) | |||
1071 | } | 1091 | } |
1072 | 1092 | ||
1073 | /* | 1093 | /* |
1074 | * Expand (or shrink) an existing mapping, potentially moving it at the | 1094 | * expand (or shrink) an existing mapping, potentially moving it at the same |
1075 | * same time (controlled by the MREMAP_MAYMOVE flag and available VM space) | 1095 | * time (controlled by the MREMAP_MAYMOVE flag and available VM space) |
1076 | * | 1096 | * |
1077 | * MREMAP_FIXED option added 5-Dec-1999 by Benjamin LaHaise | 1097 | * under NOMMU conditions, we only permit changing a mapping's size, and only |
1078 | * This option implies MREMAP_MAYMOVE. | 1098 | * as long as it stays within the hole allocated by the kmalloc() call in |
1099 | * do_mmap_pgoff() and the block is not shareable | ||
1079 | * | 1100 | * |
1080 | * on uClinux, we only permit changing a mapping's size, and only as long as it stays within the | 1101 | * MREMAP_FIXED is not supported under NOMMU conditions |
1081 | * hole allocated by the kmalloc() call in do_mmap_pgoff() and the block is not shareable | ||
1082 | */ | 1102 | */ |
1083 | unsigned long do_mremap(unsigned long addr, | 1103 | unsigned long do_mremap(unsigned long addr, |
1084 | unsigned long old_len, unsigned long new_len, | 1104 | unsigned long old_len, unsigned long new_len, |
1085 | unsigned long flags, unsigned long new_addr) | 1105 | unsigned long flags, unsigned long new_addr) |
1086 | { | 1106 | { |
1087 | struct vm_list_struct *vml = NULL; | 1107 | struct vm_area_struct *vma; |
1088 | 1108 | ||
1089 | /* insanity checks first */ | 1109 | /* insanity checks first */ |
1090 | if (new_len == 0) | 1110 | if (new_len == 0) |
@@ -1093,29 +1113,38 @@ unsigned long do_mremap(unsigned long addr, | |||
1093 | if (flags & MREMAP_FIXED && new_addr != addr) | 1113 | if (flags & MREMAP_FIXED && new_addr != addr) |
1094 | return (unsigned long) -EINVAL; | 1114 | return (unsigned long) -EINVAL; |
1095 | 1115 | ||
1096 | for (vml = current->mm->context.vmlist; vml; vml = vml->next) | 1116 | vma = find_vma_exact(current->mm, addr); |
1097 | if (vml->vma->vm_start == addr) | 1117 | if (!vma) |
1098 | goto found; | 1118 | return (unsigned long) -EINVAL; |
1099 | |||
1100 | return (unsigned long) -EINVAL; | ||
1101 | 1119 | ||
1102 | found: | 1120 | if (vma->vm_end != vma->vm_start + old_len) |
1103 | if (vml->vma->vm_end != vml->vma->vm_start + old_len) | ||
1104 | return (unsigned long) -EFAULT; | 1121 | return (unsigned long) -EFAULT; |
1105 | 1122 | ||
1106 | if (vml->vma->vm_flags & VM_MAYSHARE) | 1123 | if (vma->vm_flags & VM_MAYSHARE) |
1107 | return (unsigned long) -EPERM; | 1124 | return (unsigned long) -EPERM; |
1108 | 1125 | ||
1109 | if (new_len > kobjsize((void *) addr)) | 1126 | if (new_len > kobjsize((void *) addr)) |
1110 | return (unsigned long) -ENOMEM; | 1127 | return (unsigned long) -ENOMEM; |
1111 | 1128 | ||
1112 | /* all checks complete - do it */ | 1129 | /* all checks complete - do it */ |
1113 | vml->vma->vm_end = vml->vma->vm_start + new_len; | 1130 | vma->vm_end = vma->vm_start + new_len; |
1114 | 1131 | ||
1115 | askedalloc -= old_len; | 1132 | askedalloc -= old_len; |
1116 | askedalloc += new_len; | 1133 | askedalloc += new_len; |
1117 | 1134 | ||
1118 | return vml->vma->vm_start; | 1135 | return vma->vm_start; |
1136 | } | ||
1137 | |||
1138 | asmlinkage unsigned long sys_mremap(unsigned long addr, | ||
1139 | unsigned long old_len, unsigned long new_len, | ||
1140 | unsigned long flags, unsigned long new_addr) | ||
1141 | { | ||
1142 | unsigned long ret; | ||
1143 | |||
1144 | down_write(¤t->mm->mmap_sem); | ||
1145 | ret = do_mremap(addr, old_len, new_len, flags, new_addr); | ||
1146 | up_write(¤t->mm->mmap_sem); | ||
1147 | return ret; | ||
1119 | } | 1148 | } |
1120 | 1149 | ||
1121 | struct page *follow_page(struct vm_area_struct *vma, unsigned long address, | 1150 | struct page *follow_page(struct vm_area_struct *vma, unsigned long address, |