aboutsummaryrefslogtreecommitdiffstats
path: root/mm/nommu.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-09-27 04:50:21 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-27 11:26:14 -0400
commit6fa5f80bc34da1a49b42117602b44441402cac2f (patch)
tree7cdc7bf5c0df29b218c9c40d6cddd5124587b7a5 /mm/nommu.c
parent3034097a5017dd9281b1f795e80af9859627850e (diff)
[PATCH] NOMMU: Make mremap() partially work for NOMMU kernels
Make mremap() partially work for NOMMU kernels. It may resize a VMA provided that it doesn't exceed the size of the slab object in which the storage is allocated that the VMA refers to. Shareable VMAs may not be resized. Moving VMAs (as permitted by MREMAP_MAYMOVE) is not currently supported. This patch also makes use of the fact that the VMA list is now ordered to cut it short when possible. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm/nommu.c')
-rw-r--r--mm/nommu.c63
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)
350EXPORT_SYMBOL(find_vma); 350EXPORT_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 */
356static 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 */
355static inline struct vm_area_struct *find_nommu_vma(unsigned long start) 375static 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 */
1083unsigned long do_mremap(unsigned long addr, 1103unsigned 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
1138asmlinkage 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(&current->mm->mmap_sem);
1145 ret = do_mremap(addr, old_len, new_len, flags, new_addr);
1146 up_write(&current->mm->mmap_sem);
1147 return ret;
1119} 1148}
1120 1149
1121struct page *follow_page(struct vm_area_struct *vma, unsigned long address, 1150struct page *follow_page(struct vm_area_struct *vma, unsigned long address,