1
2
3
4
5
6#include <linux/slab.h>
7#include <linux/shm.h>
8#include <linux/mman.h>
9#include <linux/pagemap.h>
10#include <linux/swap.h>
11#include <linux/swapctl.h>
12#include <linux/smp_lock.h>
13#include <linux/init.h>
14#include <linux/file.h>
15
16#include <asm/uaccess.h>
17#include <asm/pgtable.h>
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34pgprot_t protection_map[16] = {
35 __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
36 __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
37};
38
39
40kmem_cache_t *vm_area_cachep;
41
42int sysctl_overcommit_memory;
43
44
45
46
47int vm_enough_memory(long pages)
48{
49
50
51
52
53
54
55
56
57
58
59 long free;
60
61
62 if (sysctl_overcommit_memory)
63 return 1;
64
65 free = buffermem >> PAGE_SHIFT;
66 free += page_cache_size;
67 free += nr_free_pages;
68 free += nr_swap_pages;
69 free -= (page_cache.min_percent + buffer_mem.min_percent + 2)*num_physpages/100;
70 return free > pages;
71}
72
73
74static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
75{
76 struct file * file = vma->vm_file;
77
78 if (file) {
79 if (vma->vm_flags & VM_DENYWRITE)
80 file->f_dentry->d_inode->i_writecount++;
81 if(vma->vm_next_share)
82 vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
83 *vma->vm_pprev_share = vma->vm_next_share;
84 }
85}
86
87asmlinkage unsigned long sys_brk(unsigned long brk)
88{
89 unsigned long rlim, retval;
90 unsigned long newbrk, oldbrk;
91 struct mm_struct *mm = current->mm;
92
93 down(&mm->mmap_sem);
94
95
96
97
98
99
100
101
102
103
104
105
106
107 lock_kernel();
108
109 if (brk < mm->end_code)
110 goto out;
111 newbrk = PAGE_ALIGN(brk);
112 oldbrk = PAGE_ALIGN(mm->brk);
113 if (oldbrk == newbrk)
114 goto set_brk;
115
116
117 if (brk <= mm->brk) {
118 if (!do_munmap(newbrk, oldbrk-newbrk))
119 goto set_brk;
120 goto out;
121 }
122
123
124 rlim = current->rlim[RLIMIT_DATA].rlim_cur;
125 if (rlim < RLIM_INFINITY && brk - mm->end_code > rlim)
126 goto out;
127
128
129 if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
130 goto out;
131
132
133 if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
134 goto out;
135
136
137 if (do_mmap(NULL, oldbrk, newbrk-oldbrk,
138 PROT_READ|PROT_WRITE|PROT_EXEC,
139 MAP_FIXED|MAP_PRIVATE, 0) != oldbrk)
140 goto out;
141set_brk:
142 mm->brk = brk;
143out:
144 retval = mm->brk;
145 unlock_kernel();
146 up(&mm->mmap_sem);
147 return retval;
148}
149
150
151
152
153
154static inline unsigned long vm_flags(unsigned long prot, unsigned long flags)
155{
156#define _trans(x,bit1,bit2) \
157((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
158
159 unsigned long prot_bits, flag_bits;
160 prot_bits =
161 _trans(prot, PROT_READ, VM_READ) |
162 _trans(prot, PROT_WRITE, VM_WRITE) |
163 _trans(prot, PROT_EXEC, VM_EXEC);
164 flag_bits =
165 _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) |
166 _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) |
167 _trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE);
168 return prot_bits | flag_bits;
169#undef _trans
170}
171
172unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
173 unsigned long prot, unsigned long flags, unsigned long off)
174{
175 struct mm_struct * mm = current->mm;
176 struct vm_area_struct * vma;
177 int error;
178
179 if (file && (!file->f_op || !file->f_op->mmap))
180 return -ENODEV;
181
182 if ((len = PAGE_ALIGN(len)) == 0)
183 return addr;
184
185 if (len > TASK_SIZE || addr > TASK_SIZE-len)
186 return -EINVAL;
187
188
189 if (off + len - 1 < off)
190 return -EINVAL;
191
192
193 if (mm->map_count > MAX_MAP_COUNT)
194 return -ENOMEM;
195
196
197 if (mm->def_flags & VM_LOCKED) {
198 unsigned long locked = mm->locked_vm << PAGE_SHIFT;
199 locked += len;
200 if (locked < len)
201 return -EAGAIN;
202 if ((current->rlim[RLIMIT_MEMLOCK].rlim_cur < RLIM_INFINITY) &&
203 (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur))
204 return -EAGAIN;
205 }
206
207
208
209
210
211 if (file != NULL) {
212 switch (flags & MAP_TYPE) {
213 case MAP_SHARED:
214 if ((prot & PROT_WRITE) && !(file->f_mode & 2))
215 return -EACCES;
216
217
218 if (IS_APPEND(file->f_dentry->d_inode) && (file->f_mode & 2))
219 return -EACCES;
220
221
222 if (locks_verify_locked(file->f_dentry->d_inode))
223 return -EAGAIN;
224
225
226 case MAP_PRIVATE:
227 if (!(file->f_mode & 1))
228 return -EACCES;
229 break;
230
231 default:
232 return -EINVAL;
233 }
234 } else if ((flags & MAP_TYPE) != MAP_PRIVATE)
235 return -EINVAL;
236
237
238
239
240 if (flags & MAP_FIXED) {
241 if (addr & ~PAGE_MASK)
242 return -EINVAL;
243 } else {
244 addr = get_unmapped_area(addr, len);
245 if (!addr)
246 return -ENOMEM;
247 }
248
249
250
251
252
253 vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
254 if (!vma)
255 return -ENOMEM;
256
257 vma->vm_mm = mm;
258 vma->vm_start = addr;
259 vma->vm_end = addr + len;
260 vma->vm_flags = vm_flags(prot,flags) | mm->def_flags;
261
262 if (file) {
263 if (file->f_mode & 1)
264 vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
265 if (flags & MAP_SHARED) {
266 vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
267
268
269
270
271
272
273
274
275
276
277 if (!(file->f_mode & 2))
278 vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
279 }
280 } else
281 vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
282 vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
283 vma->vm_ops = NULL;
284 vma->vm_offset = off;
285 vma->vm_file = NULL;
286 vma->vm_pte = 0;
287
288
289 error = -ENOMEM;
290 if (do_munmap(addr, len))
291 goto free_vma;
292
293
294 if ((mm->total_vm << PAGE_SHIFT) + len < len)
295 goto free_vma;
296 if ((current->rlim[RLIMIT_AS].rlim_cur < RLIM_INFINITY) &&
297 ((mm->total_vm << PAGE_SHIFT) + len
298 > current->rlim[RLIMIT_AS].rlim_cur))
299 goto free_vma;
300
301
302 if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE &&
303 !(flags & MAP_NORESERVE) &&
304 !vm_enough_memory(len >> PAGE_SHIFT))
305 goto free_vma;
306
307 if (file) {
308 int correct_wcount = 0;
309 if (vma->vm_flags & VM_DENYWRITE) {
310 if (file->f_dentry->d_inode->i_writecount > 0) {
311 error = -ETXTBSY;
312 goto free_vma;
313 }
314
315
316
317
318
319 file->f_dentry->d_inode->i_writecount--;
320 correct_wcount = 1;
321 }
322 error = file->f_op->mmap(file, vma);
323
324 if (correct_wcount)
325 file->f_dentry->d_inode->i_writecount++;
326 if (error)
327 goto unmap_and_free_vma;
328 vma->vm_file = file;
329 file->f_count++;
330 }
331
332
333
334
335
336 flags = vma->vm_flags;
337 addr = vma->vm_start;
338 insert_vm_struct(mm, vma);
339 merge_segments(mm, vma->vm_start, vma->vm_end);
340
341 mm->total_vm += len >> PAGE_SHIFT;
342 if (flags & VM_LOCKED) {
343 mm->locked_vm += len >> PAGE_SHIFT;
344 make_pages_present(addr, addr + len);
345 }
346 return addr;
347
348unmap_and_free_vma:
349
350 flush_cache_range(mm, vma->vm_start, vma->vm_end);
351 zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
352 flush_tlb_range(mm, vma->vm_start, vma->vm_end);
353free_vma:
354 kmem_cache_free(vm_area_cachep, vma);
355 return error;
356}
357
358
359
360
361
362unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
363{
364 struct vm_area_struct * vmm;
365
366 if (len > TASK_SIZE)
367 return 0;
368 if (!addr)
369 addr = TASK_UNMAPPED_BASE;
370 addr = PAGE_ALIGN(addr);
371
372 for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
373
374 if (TASK_SIZE - len < addr)
375 return 0;
376 if (!vmm || addr + len <= vmm->vm_start)
377 return addr;
378 addr = vmm->vm_end;
379 }
380}
381
382#define vm_avl_empty (struct vm_area_struct *) NULL
383
384#include "mmap_avl.c"
385
386
387struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr)
388{
389 struct vm_area_struct *vma = NULL;
390
391 if (mm) {
392
393
394 vma = mm->mmap_cache;
395 if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
396 if (!mm->mmap_avl) {
397
398 vma = mm->mmap;
399 while (vma && vma->vm_end <= addr)
400 vma = vma->vm_next;
401 } else {
402
403 struct vm_area_struct * tree = mm->mmap_avl;
404 vma = NULL;
405 for (;;) {
406 if (tree == vm_avl_empty)
407 break;
408 if (tree->vm_end > addr) {
409 vma = tree;
410 if (tree->vm_start <= addr)
411 break;
412 tree = tree->vm_avl_left;
413 } else
414 tree = tree->vm_avl_right;
415 }
416 }
417 if (vma)
418 mm->mmap_cache = vma;
419 }
420 }
421 return vma;
422}
423
424
425struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr,
426 struct vm_area_struct **pprev)
427{
428 if (mm) {
429 if (!mm->mmap_avl) {
430
431 struct vm_area_struct * prev = NULL;
432 struct vm_area_struct * vma = mm->mmap;
433 while (vma && vma->vm_end <= addr) {
434 prev = vma;
435 vma = vma->vm_next;
436 }
437 *pprev = prev;
438 return vma;
439 } else {
440
441 struct vm_area_struct * vma = NULL;
442 struct vm_area_struct * last_turn_right = NULL;
443 struct vm_area_struct * prev = NULL;
444 struct vm_area_struct * tree = mm->mmap_avl;
445 for (;;) {
446 if (tree == vm_avl_empty)
447 break;
448 if (tree->vm_end > addr) {
449 vma = tree;
450 prev = last_turn_right;
451 if (tree->vm_start <= addr)
452 break;
453 tree = tree->vm_avl_left;
454 } else {
455 last_turn_right = tree;
456 tree = tree->vm_avl_right;
457 }
458 }
459 if (vma) {
460 if (vma->vm_avl_left != vm_avl_empty) {
461 prev = vma->vm_avl_left;
462 while (prev->vm_avl_right != vm_avl_empty)
463 prev = prev->vm_avl_right;
464 }
465 if ((prev ? prev->vm_next : mm->mmap) != vma)
466 printk("find_vma_prev: tree inconsistent with list\n");
467 *pprev = prev;
468 return vma;
469 }
470 }
471 }
472 *pprev = NULL;
473 return NULL;
474}
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499static struct vm_area_struct * unmap_fixup(struct vm_area_struct *area,
500 unsigned long addr, size_t len, struct vm_area_struct *extra)
501{
502 struct vm_area_struct *mpnt;
503 unsigned long end = addr + len;
504
505 area->vm_mm->total_vm -= len >> PAGE_SHIFT;
506 if (area->vm_flags & VM_LOCKED)
507 area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
508
509
510 if (addr == area->vm_start && end == area->vm_end) {
511 if (area->vm_ops && area->vm_ops->close)
512 area->vm_ops->close(area);
513 if (area->vm_file)
514 fput(area->vm_file);
515 kmem_cache_free(vm_area_cachep, area);
516 return extra;
517 }
518
519
520 if (end == area->vm_end)
521 area->vm_end = addr;
522 else if (addr == area->vm_start) {
523 area->vm_offset += (end - area->vm_start);
524 area->vm_start = end;
525 } else {
526
527
528 mpnt = extra;
529 extra = NULL;
530
531 mpnt->vm_mm = area->vm_mm;
532 mpnt->vm_start = end;
533 mpnt->vm_end = area->vm_end;
534 mpnt->vm_page_prot = area->vm_page_prot;
535 mpnt->vm_flags = area->vm_flags;
536 mpnt->vm_ops = area->vm_ops;
537 mpnt->vm_offset = area->vm_offset + (end - area->vm_start);
538 mpnt->vm_file = area->vm_file;
539 mpnt->vm_pte = area->vm_pte;
540 if (mpnt->vm_file)
541 mpnt->vm_file->f_count++;
542 if (mpnt->vm_ops && mpnt->vm_ops->open)
543 mpnt->vm_ops->open(mpnt);
544 area->vm_end = addr;
545 insert_vm_struct(current->mm, mpnt);
546 }
547
548 insert_vm_struct(current->mm, area);
549 return extra;
550}
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565static void free_pgtables(struct mm_struct * mm, struct vm_area_struct *prev,
566 unsigned long start, unsigned long end)
567{
568 unsigned long first = start & PGDIR_MASK;
569 unsigned long last = (end + PGDIR_SIZE - 1) & PGDIR_MASK;
570
571 if (!prev) {
572 prev = mm->mmap;
573 if (!prev)
574 goto no_mmaps;
575 if (prev->vm_end > start) {
576 if (last > prev->vm_start)
577 last = prev->vm_start;
578 goto no_mmaps;
579 }
580 }
581 for (;;) {
582 struct vm_area_struct *next = prev->vm_next;
583
584 if (next) {
585 if (next->vm_start < start) {
586 prev = next;
587 continue;
588 }
589 if (last > next->vm_start)
590 last = next->vm_start;
591 }
592 if (prev->vm_end > first)
593 first = prev->vm_end + PGDIR_SIZE - 1;
594 break;
595 }
596no_mmaps:
597 first = first >> PGDIR_SHIFT;
598 last = last >> PGDIR_SHIFT;
599 if (last > first)
600 clear_page_tables(mm, first, last-first);
601}
602
603
604
605
606
607
608int do_munmap(unsigned long addr, size_t len)
609{
610 struct mm_struct * mm;
611 struct vm_area_struct *mpnt, *prev, **npp, *free, *extra;
612
613 if ((addr & ~PAGE_MASK) || addr >= TASK_SIZE || len > TASK_SIZE-addr)
614 return -EINVAL;
615
616 if ((len = PAGE_ALIGN(len)) == 0)
617 return -EINVAL;
618
619
620
621
622
623
624 mm = current->mm;
625 mpnt = find_vma_prev(mm, addr, &prev);
626 if (!mpnt)
627 return 0;
628
629
630 if (mpnt->vm_start >= addr+len)
631 return 0;
632
633
634 if ((mpnt->vm_start < addr && mpnt->vm_end > addr+len)
635 && mm->map_count >= MAX_MAP_COUNT)
636 return -ENOMEM;
637
638
639
640
641
642 extra = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
643 if (!extra)
644 return -ENOMEM;
645
646 npp = (prev ? &prev->vm_next : &mm->mmap);
647 free = NULL;
648 for ( ; mpnt && mpnt->vm_start < addr+len; mpnt = *npp) {
649 *npp = mpnt->vm_next;
650 mpnt->vm_next = free;
651 free = mpnt;
652 if (mm->mmap_avl)
653 avl_remove(mpnt, &mm->mmap_avl);
654 }
655
656
657
658
659
660
661 while ((mpnt = free) != NULL) {
662 unsigned long st, end, size;
663
664 free = free->vm_next;
665
666 st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
667 end = addr+len;
668 end = end > mpnt->vm_end ? mpnt->vm_end : end;
669 size = end - st;
670
671 if (mpnt->vm_ops && mpnt->vm_ops->unmap)
672 mpnt->vm_ops->unmap(mpnt, st, size);
673
674 remove_shared_vm_struct(mpnt);
675 mm->map_count--;
676
677 flush_cache_range(mm, st, end);
678 zap_page_range(mm, st, size);
679 flush_tlb_range(mm, st, end);
680
681
682
683
684 extra = unmap_fixup(mpnt, st, size, extra);
685 }
686
687
688 if (extra)
689 kmem_cache_free(vm_area_cachep, extra);
690
691 free_pgtables(mm, prev, addr, addr+len);
692
693 mm->mmap_cache = NULL;
694 return 0;
695}
696
697asmlinkage int sys_munmap(unsigned long addr, size_t len)
698{
699 int ret;
700
701 down(¤t->mm->mmap_sem);
702 lock_kernel();
703 ret = do_munmap(addr, len);
704 unlock_kernel();
705 up(¤t->mm->mmap_sem);
706 return ret;
707}
708
709
710void build_mmap_avl(struct mm_struct * mm)
711{
712 struct vm_area_struct * vma;
713
714 mm->mmap_avl = NULL;
715 for (vma = mm->mmap; vma; vma = vma->vm_next)
716 avl_insert(vma, &mm->mmap_avl);
717}
718
719
720void exit_mmap(struct mm_struct * mm)
721{
722 struct vm_area_struct * mpnt;
723
724 mpnt = mm->mmap;
725 mm->mmap = mm->mmap_avl = mm->mmap_cache = NULL;
726 mm->rss = 0;
727 mm->total_vm = 0;
728 mm->locked_vm = 0;
729 while (mpnt) {
730 struct vm_area_struct * next = mpnt->vm_next;
731 unsigned long start = mpnt->vm_start;
732 unsigned long end = mpnt->vm_end;
733 unsigned long size = end - start;
734
735 if (mpnt->vm_ops) {
736 if (mpnt->vm_ops->unmap)
737 mpnt->vm_ops->unmap(mpnt, start, size);
738 if (mpnt->vm_ops->close)
739 mpnt->vm_ops->close(mpnt);
740 }
741 mm->map_count--;
742 remove_shared_vm_struct(mpnt);
743 zap_page_range(mm, start, size);
744 if (mpnt->vm_file)
745 fput(mpnt->vm_file);
746 kmem_cache_free(vm_area_cachep, mpnt);
747 mpnt = next;
748 }
749
750
751 if (mm->map_count)
752 printk("exit_mmap: map count is %d\n", mm->map_count);
753
754 clear_page_tables(mm, 0, USER_PTRS_PER_PGD);
755}
756
757
758
759
760void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
761{
762 struct vm_area_struct **pprev;
763 struct file * file;
764
765 if (!mm->mmap_avl) {
766 pprev = &mm->mmap;
767 while (*pprev && (*pprev)->vm_start <= vmp->vm_start)
768 pprev = &(*pprev)->vm_next;
769 } else {
770 struct vm_area_struct *prev, *next;
771 avl_insert_neighbours(vmp, &mm->mmap_avl, &prev, &next);
772 pprev = (prev ? &prev->vm_next : &mm->mmap);
773 if (*pprev != next)
774 printk("insert_vm_struct: tree inconsistent with list\n");
775 }
776 vmp->vm_next = *pprev;
777 *pprev = vmp;
778
779 mm->map_count++;
780 if (mm->map_count >= AVL_MIN_MAP_COUNT && !mm->mmap_avl)
781 build_mmap_avl(mm);
782
783 file = vmp->vm_file;
784 if (file) {
785 struct inode * inode = file->f_dentry->d_inode;
786 struct vm_area_struct **head;
787
788 if (vmp->vm_flags & VM_DENYWRITE)
789 inode->i_writecount--;
790
791 head = &inode->i_mmap;
792 if (vmp->vm_flags & VM_SHARED)
793 head = &inode->i_mmap_shared;
794
795
796 if((vmp->vm_next_share = *head) != NULL)
797 (*head)->vm_pprev_share = &vmp->vm_next_share;
798 *head = vmp;
799 vmp->vm_pprev_share = head;
800 }
801}
802
803
804
805
806
807
808
809
810
811void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
812{
813 struct vm_area_struct *prev, *mpnt, *next, *prev1;
814
815 mpnt = find_vma_prev(mm, start_addr, &prev1);
816 if (!mpnt)
817 return;
818
819 if (prev1) {
820 prev = prev1;
821 } else {
822 prev = mpnt;
823 mpnt = mpnt->vm_next;
824 }
825
826
827
828
829 for ( ; mpnt && prev->vm_start < end_addr ; prev = mpnt, mpnt = next) {
830 next = mpnt->vm_next;
831
832
833 if ((mpnt->vm_file != prev->vm_file)||
834 (mpnt->vm_pte != prev->vm_pte) ||
835 (mpnt->vm_ops != prev->vm_ops) ||
836 (mpnt->vm_flags != prev->vm_flags) ||
837 (prev->vm_end != mpnt->vm_start))
838 continue;
839
840
841
842
843
844 if ((mpnt->vm_file != NULL) || (mpnt->vm_flags & VM_SHM)) {
845 unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
846 if (off != mpnt->vm_offset)
847 continue;
848 }
849
850
851
852
853
854 if (mm->mmap_avl)
855 avl_remove(mpnt, &mm->mmap_avl);
856 prev->vm_end = mpnt->vm_end;
857 prev->vm_next = mpnt->vm_next;
858 if (mpnt->vm_ops && mpnt->vm_ops->close) {
859 mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
860 mpnt->vm_start = mpnt->vm_end;
861 mpnt->vm_ops->close(mpnt);
862 }
863 mm->map_count--;
864 remove_shared_vm_struct(mpnt);
865 if (mpnt->vm_file)
866 fput(mpnt->vm_file);
867 kmem_cache_free(vm_area_cachep, mpnt);
868 mpnt = prev;
869 }
870 mm->mmap_cache = NULL;
871}
872
873void __init vma_init(void)
874{
875 vm_area_cachep = kmem_cache_create("vm_area_struct",
876 sizeof(struct vm_area_struct),
877 0, SLAB_HWCACHE_ALIGN,
878 NULL, NULL);
879 if(!vm_area_cachep)
880 panic("vma_init: Cannot alloc vm_area_struct cache.");
881
882 mm_cachep = kmem_cache_create("mm_struct",
883 sizeof(struct mm_struct),
884 0, SLAB_HWCACHE_ALIGN,
885 NULL, NULL);
886 if(!mm_cachep)
887 panic("vma_init: Cannot alloc mm_struct cache.");
888}
889