diff options
author | David Howells <dhowells@redhat.com> | 2006-09-27 04:50:20 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-27 11:26:14 -0400 |
commit | 3034097a5017dd9281b1f795e80af9859627850e (patch) | |
tree | d03d6749ac52e6c23020bd9caa5fdee301ca8fa6 | |
parent | dbf8685c8e21404e3a8ed244bd0219d3c4b89101 (diff) |
[PATCH] NOMMU: Order the per-mm_struct VMA list
Order the per-mm_struct VMA list by address so that searching it can be cut
short when the appropriate address has been exceeded.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | mm/nommu.c | 104 |
1 files changed, 72 insertions, 32 deletions
diff --git a/mm/nommu.c b/mm/nommu.c index 829fc904de11..4f87b2f43a2b 100644 --- a/mm/nommu.c +++ b/mm/nommu.c | |||
@@ -310,6 +310,48 @@ static void show_process_blocks(void) | |||
310 | } | 310 | } |
311 | #endif /* DEBUG */ | 311 | #endif /* DEBUG */ |
312 | 312 | ||
313 | /* | ||
314 | * add a VMA into a process's mm_struct in the appropriate place in the list | ||
315 | * - should be called with mm->mmap_sem held writelocked | ||
316 | */ | ||
317 | static void add_vma_to_mm(struct mm_struct *mm, struct vm_list_struct *vml) | ||
318 | { | ||
319 | struct vm_list_struct **ppv; | ||
320 | |||
321 | for (ppv = ¤t->mm->context.vmlist; *ppv; ppv = &(*ppv)->next) | ||
322 | if ((*ppv)->vma->vm_start > vml->vma->vm_start) | ||
323 | break; | ||
324 | |||
325 | vml->next = *ppv; | ||
326 | *ppv = vml; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * look up the first VMA in which addr resides, NULL if none | ||
331 | * - should be called with mm->mmap_sem at least held readlocked | ||
332 | */ | ||
333 | struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) | ||
334 | { | ||
335 | struct vm_list_struct *loop, *vml; | ||
336 | |||
337 | /* search the vm_start ordered list */ | ||
338 | vml = NULL; | ||
339 | for (loop = mm->context.vmlist; loop; loop = loop->next) { | ||
340 | if (loop->vma->vm_start > addr) | ||
341 | break; | ||
342 | vml = loop; | ||
343 | } | ||
344 | |||
345 | if (vml && vml->vma->vm_end > addr) | ||
346 | return vml->vma; | ||
347 | |||
348 | return NULL; | ||
349 | } | ||
350 | EXPORT_SYMBOL(find_vma); | ||
351 | |||
352 | /* | ||
353 | * find a VMA in the global tree | ||
354 | */ | ||
313 | static inline struct vm_area_struct *find_nommu_vma(unsigned long start) | 355 | static inline struct vm_area_struct *find_nommu_vma(unsigned long start) |
314 | { | 356 | { |
315 | struct vm_area_struct *vma; | 357 | struct vm_area_struct *vma; |
@@ -329,6 +371,9 @@ static inline struct vm_area_struct *find_nommu_vma(unsigned long start) | |||
329 | return NULL; | 371 | return NULL; |
330 | } | 372 | } |
331 | 373 | ||
374 | /* | ||
375 | * add a VMA in the global tree | ||
376 | */ | ||
332 | static void add_nommu_vma(struct vm_area_struct *vma) | 377 | static void add_nommu_vma(struct vm_area_struct *vma) |
333 | { | 378 | { |
334 | struct vm_area_struct *pvma; | 379 | struct vm_area_struct *pvma; |
@@ -375,6 +420,9 @@ static void add_nommu_vma(struct vm_area_struct *vma) | |||
375 | rb_insert_color(&vma->vm_rb, &nommu_vma_tree); | 420 | rb_insert_color(&vma->vm_rb, &nommu_vma_tree); |
376 | } | 421 | } |
377 | 422 | ||
423 | /* | ||
424 | * delete a VMA from the global list | ||
425 | */ | ||
378 | static void delete_nommu_vma(struct vm_area_struct *vma) | 426 | static void delete_nommu_vma(struct vm_area_struct *vma) |
379 | { | 427 | { |
380 | struct address_space *mapping; | 428 | struct address_space *mapping; |
@@ -852,8 +900,7 @@ unsigned long do_mmap_pgoff(struct file *file, | |||
852 | realalloc += kobjsize(vml); | 900 | realalloc += kobjsize(vml); |
853 | askedalloc += sizeof(*vml); | 901 | askedalloc += sizeof(*vml); |
854 | 902 | ||
855 | vml->next = current->mm->context.vmlist; | 903 | add_vma_to_mm(current->mm, vml); |
856 | current->mm->context.vmlist = vml; | ||
857 | 904 | ||
858 | up_write(&nommu_vma_sem); | 905 | up_write(&nommu_vma_sem); |
859 | 906 | ||
@@ -932,6 +979,11 @@ static void put_vma(struct vm_area_struct *vma) | |||
932 | } | 979 | } |
933 | } | 980 | } |
934 | 981 | ||
982 | /* | ||
983 | * release a mapping | ||
984 | * - under NOMMU conditions the parameters must match exactly to the mapping to | ||
985 | * be removed | ||
986 | */ | ||
935 | int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) | 987 | int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) |
936 | { | 988 | { |
937 | struct vm_list_struct *vml, **parent; | 989 | struct vm_list_struct *vml, **parent; |
@@ -941,10 +993,13 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) | |||
941 | printk("do_munmap:\n"); | 993 | printk("do_munmap:\n"); |
942 | #endif | 994 | #endif |
943 | 995 | ||
944 | for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) | 996 | for (parent = &mm->context.vmlist; *parent; parent = &(*parent)->next) { |
997 | if ((*parent)->vma->vm_start > addr) | ||
998 | break; | ||
945 | if ((*parent)->vma->vm_start == addr && | 999 | if ((*parent)->vma->vm_start == addr && |
946 | ((len == 0) || ((*parent)->vma->vm_end == end))) | 1000 | ((len == 0) || ((*parent)->vma->vm_end == end))) |
947 | goto found; | 1001 | goto found; |
1002 | } | ||
948 | 1003 | ||
949 | printk("munmap of non-mmaped memory by process %d (%s): %p\n", | 1004 | printk("munmap of non-mmaped memory by process %d (%s): %p\n", |
950 | current->pid, current->comm, (void *) addr); | 1005 | current->pid, current->comm, (void *) addr); |
@@ -970,7 +1025,20 @@ int do_munmap(struct mm_struct *mm, unsigned long addr, size_t len) | |||
970 | return 0; | 1025 | return 0; |
971 | } | 1026 | } |
972 | 1027 | ||
973 | /* Release all mmaps. */ | 1028 | asmlinkage long sys_munmap(unsigned long addr, size_t len) |
1029 | { | ||
1030 | int ret; | ||
1031 | struct mm_struct *mm = current->mm; | ||
1032 | |||
1033 | down_write(&mm->mmap_sem); | ||
1034 | ret = do_munmap(mm, addr, len); | ||
1035 | up_write(&mm->mmap_sem); | ||
1036 | return ret; | ||
1037 | } | ||
1038 | |||
1039 | /* | ||
1040 | * Release all mappings | ||
1041 | */ | ||
974 | void exit_mmap(struct mm_struct * mm) | 1042 | void exit_mmap(struct mm_struct * mm) |
975 | { | 1043 | { |
976 | struct vm_list_struct *tmp; | 1044 | struct vm_list_struct *tmp; |
@@ -997,17 +1065,6 @@ void exit_mmap(struct mm_struct * mm) | |||
997 | } | 1065 | } |
998 | } | 1066 | } |
999 | 1067 | ||
1000 | asmlinkage long sys_munmap(unsigned long addr, size_t len) | ||
1001 | { | ||
1002 | int ret; | ||
1003 | struct mm_struct *mm = current->mm; | ||
1004 | |||
1005 | down_write(&mm->mmap_sem); | ||
1006 | ret = do_munmap(mm, addr, len); | ||
1007 | up_write(&mm->mmap_sem); | ||
1008 | return ret; | ||
1009 | } | ||
1010 | |||
1011 | unsigned long do_brk(unsigned long addr, unsigned long len) | 1068 | unsigned long do_brk(unsigned long addr, unsigned long len) |
1012 | { | 1069 | { |
1013 | return -ENOMEM; | 1070 | return -ENOMEM; |
@@ -1061,23 +1118,6 @@ unsigned long do_mremap(unsigned long addr, | |||
1061 | return vml->vma->vm_start; | 1118 | return vml->vma->vm_start; |
1062 | } | 1119 | } |
1063 | 1120 | ||
1064 | /* | ||
1065 | * Look up the first VMA which satisfies addr < vm_end, NULL if none | ||
1066 | * - should be called with mm->mmap_sem at least readlocked | ||
1067 | */ | ||
1068 | struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) | ||
1069 | { | ||
1070 | struct vm_list_struct *vml; | ||
1071 | |||
1072 | for (vml = mm->context.vmlist; vml; vml = vml->next) | ||
1073 | if (addr >= vml->vma->vm_start && addr < vml->vma->vm_end) | ||
1074 | return vml->vma; | ||
1075 | |||
1076 | return NULL; | ||
1077 | } | ||
1078 | |||
1079 | EXPORT_SYMBOL(find_vma); | ||
1080 | |||
1081 | struct page *follow_page(struct vm_area_struct *vma, unsigned long address, | 1121 | struct page *follow_page(struct vm_area_struct *vma, unsigned long address, |
1082 | unsigned int foll_flags) | 1122 | unsigned int foll_flags) |
1083 | { | 1123 | { |