diff options
Diffstat (limited to 'mm/nommu.c')
-rw-r--r-- | mm/nommu.c | 63 |
1 files changed, 46 insertions, 17 deletions
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, |