1
2
3
4
5
6#include <linux/stat.h>
7#include <linux/sched.h>
8#include <linux/kernel.h>
9#include <linux/mm.h>
10#include <linux/slab.h>
11#include <linux/shm.h>
12#include <linux/errno.h>
13#include <linux/mman.h>
14#include <linux/string.h>
15#include <linux/pagemap.h>
16#include <linux/swap.h>
17#include <linux/smp.h>
18#include <linux/smp_lock.h>
19#include <linux/init.h>
20
21#include <asm/uaccess.h>
22#include <asm/system.h>
23#include <asm/pgtable.h>
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40pgprot_t protection_map[16] = {
41 __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111,
42 __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111
43};
44
45
46kmem_cache_t *vm_area_cachep;
47
48int sysctl_overcommit_memory;
49
50
51
52
53static inline int vm_enough_memory(long pages)
54{
55
56
57
58
59 long freepages;
60
61
62 if (sysctl_overcommit_memory)
63 return 1;
64
65 freepages = buffermem >> PAGE_SHIFT;
66 freepages += page_cache_size;
67 freepages >>= 1;
68 freepages += nr_free_pages;
69 freepages += nr_swap_pages;
70 freepages -= num_physpages >> 4;
71 return freepages > pages;
72}
73
74
75static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
76{
77 struct dentry * dentry = vma->vm_dentry;
78
79 if (dentry) {
80 if (vma->vm_flags & VM_DENYWRITE)
81 dentry->d_inode->i_writecount++;
82 if(vma->vm_next_share)
83 vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
84 *vma->vm_pprev_share = vma->vm_next_share;
85 }
86}
87
88asmlinkage unsigned long sys_brk(unsigned long brk)
89{
90 unsigned long rlim, retval;
91 unsigned long newbrk, oldbrk;
92 struct mm_struct *mm = current->mm;
93
94 lock_kernel();
95 retval = mm->brk;
96 if (brk < mm->end_code)
97 goto out;
98 newbrk = PAGE_ALIGN(brk);
99 oldbrk = PAGE_ALIGN(mm->brk);
100 if (oldbrk == newbrk) {
101 retval = mm->brk = brk;
102 goto out;
103 }
104
105
106 if (brk <= mm->brk) {
107 retval = mm->brk = brk;
108 do_munmap(newbrk, oldbrk-newbrk);
109 goto out;
110 }
111
112
113 retval = mm->brk;
114 rlim = current->rlim[RLIMIT_DATA].rlim_cur;
115 if (rlim >= RLIM_INFINITY)
116 rlim = ~0;
117 if (brk - mm->end_code > rlim)
118 goto out;
119
120
121 if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
122 goto out;
123
124
125 if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
126 goto out;
127
128
129 if(do_mmap(NULL, oldbrk, newbrk-oldbrk,
130 PROT_READ|PROT_WRITE|PROT_EXEC,
131 MAP_FIXED|MAP_PRIVATE, 0) == oldbrk)
132 mm->brk = brk;
133 retval = mm->brk;
134out:
135 unlock_kernel();
136 return retval;
137}
138
139
140
141
142
143static inline unsigned long vm_flags(unsigned long prot, unsigned long flags)
144{
145#define _trans(x,bit1,bit2) \
146((bit1==bit2)?(x&bit1):(x&bit1)?bit2:0)
147
148 unsigned long prot_bits, flag_bits;
149 prot_bits =
150 _trans(prot, PROT_READ, VM_READ) |
151 _trans(prot, PROT_WRITE, VM_WRITE) |
152 _trans(prot, PROT_EXEC, VM_EXEC);
153 flag_bits =
154 _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) |
155 _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) |
156 _trans(flags, MAP_EXECUTABLE, VM_EXECUTABLE);
157 return prot_bits | flag_bits;
158#undef _trans
159}
160
161unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
162 unsigned long prot, unsigned long flags, unsigned long off)
163{
164 struct mm_struct * mm = current->mm;
165 struct vm_area_struct * vma;
166 int correct_wcount = 0;
167
168 if ((len = PAGE_ALIGN(len)) == 0)
169 return addr;
170
171 if (len > TASK_SIZE || addr > TASK_SIZE-len)
172 return -EINVAL;
173
174
175 if (off + len < off)
176 return -EINVAL;
177
178
179 if (mm->def_flags & VM_LOCKED) {
180 unsigned long locked = mm->locked_vm << PAGE_SHIFT;
181 locked += len;
182 if (locked > current->rlim[RLIMIT_MEMLOCK].rlim_cur)
183 return -EAGAIN;
184 }
185
186
187
188
189
190 if (file != NULL) {
191 switch (flags & MAP_TYPE) {
192 case MAP_SHARED:
193 if ((prot & PROT_WRITE) && !(file->f_mode & 2))
194 return -EACCES;
195
196
197 if (locks_verify_locked(file->f_dentry->d_inode))
198 return -EAGAIN;
199
200 case MAP_PRIVATE:
201 if (!(file->f_mode & 1))
202 return -EACCES;
203 break;
204
205 default:
206 return -EINVAL;
207 }
208 } else if ((flags & MAP_TYPE) != MAP_PRIVATE)
209 return -EINVAL;
210
211
212
213
214 if (flags & MAP_FIXED) {
215 if (addr & ~PAGE_MASK)
216 return -EINVAL;
217 } else {
218 addr = get_unmapped_area(addr, len);
219 if (!addr)
220 return -ENOMEM;
221 }
222
223
224
225
226
227 if (file && (!file->f_op || !file->f_op->mmap))
228 return -ENODEV;
229
230 vma = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
231 if (!vma)
232 return -ENOMEM;
233
234 vma->vm_mm = mm;
235 vma->vm_start = addr;
236 vma->vm_end = addr + len;
237 vma->vm_flags = vm_flags(prot,flags) | mm->def_flags;
238
239 if (file) {
240 if (file->f_mode & 1)
241 vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
242 if (flags & MAP_SHARED) {
243 vma->vm_flags |= VM_SHARED | VM_MAYSHARE;
244
245
246
247
248
249
250
251
252
253
254 if (!(file->f_mode & 2))
255 vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED);
256 }
257 } else
258 vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
259 vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f];
260 vma->vm_ops = NULL;
261 vma->vm_offset = off;
262 vma->vm_dentry = NULL;
263 vma->vm_pte = 0;
264
265 do_munmap(addr, len);
266
267
268 if ((mm->total_vm << PAGE_SHIFT) + len
269 > current->rlim[RLIMIT_AS].rlim_cur) {
270 kmem_cache_free(vm_area_cachep, vma);
271 return -ENOMEM;
272 }
273
274
275 if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) {
276 if (!(flags & MAP_NORESERVE) &&
277 !vm_enough_memory(len >> PAGE_SHIFT)) {
278 kmem_cache_free(vm_area_cachep, vma);
279 return -ENOMEM;
280 }
281 }
282
283 if (file) {
284 int error = 0;
285 if (vma->vm_flags & VM_DENYWRITE) {
286 if (file->f_dentry->d_inode->i_writecount > 0)
287 error = -ETXTBSY;
288 else {
289
290
291
292
293
294 file->f_dentry->d_inode->i_writecount--;
295 correct_wcount = 1;
296 }
297 }
298 if (!error)
299 error = file->f_op->mmap(file, vma);
300
301 if (error) {
302 if (correct_wcount)
303 file->f_dentry->d_inode->i_writecount++;
304 kmem_cache_free(vm_area_cachep, vma);
305 return error;
306 }
307 }
308
309 flags = vma->vm_flags;
310 insert_vm_struct(mm, vma);
311 if (correct_wcount)
312 file->f_dentry->d_inode->i_writecount++;
313 merge_segments(mm, vma->vm_start, vma->vm_end);
314
315 addr = vma->vm_start;
316
317
318 mm->total_vm += len >> PAGE_SHIFT;
319 if ((flags & VM_LOCKED) && !(flags & VM_IO)) {
320 unsigned long start = addr;
321 mm->locked_vm += len >> PAGE_SHIFT;
322 do {
323 char c;
324 get_user(c,(char *) start);
325 len -= PAGE_SIZE;
326 start += PAGE_SIZE;
327 __asm__ __volatile__("": :"r" (c));
328 } while (len > 0);
329 }
330 return addr;
331}
332
333
334
335
336
337unsigned long get_unmapped_area(unsigned long addr, unsigned long len)
338{
339 struct vm_area_struct * vmm;
340
341 if (len > TASK_SIZE)
342 return 0;
343 if (!addr)
344 addr = TASK_UNMAPPED_BASE;
345 addr = PAGE_ALIGN(addr);
346
347 for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
348
349 if (TASK_SIZE - len < addr)
350 return 0;
351 if (!vmm || addr + len <= vmm->vm_start)
352 return addr;
353 addr = vmm->vm_end;
354 }
355}
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380static int unmap_fixup(struct vm_area_struct *area, unsigned long addr,
381 size_t len, struct vm_area_struct **extra)
382{
383 struct vm_area_struct *mpnt;
384 unsigned long end = addr + len;
385
386 area->vm_mm->total_vm -= len >> PAGE_SHIFT;
387 if (area->vm_flags & VM_LOCKED)
388 area->vm_mm->locked_vm -= len >> PAGE_SHIFT;
389
390
391 if (addr == area->vm_start && end == area->vm_end) {
392 if (area->vm_ops && area->vm_ops->close)
393 area->vm_ops->close(area);
394 if (area->vm_dentry)
395 dput(area->vm_dentry);
396 return 0;
397 }
398
399
400 if (end == area->vm_end)
401 area->vm_end = addr;
402 else if (addr == area->vm_start) {
403 area->vm_offset += (end - area->vm_start);
404 area->vm_start = end;
405 } else {
406
407
408 mpnt = *extra;
409 *extra = NULL;
410
411 mpnt->vm_mm = area->vm_mm;
412 mpnt->vm_start = end;
413 mpnt->vm_end = area->vm_end;
414 mpnt->vm_page_prot = area->vm_page_prot;
415 mpnt->vm_flags = area->vm_flags;
416 mpnt->vm_ops = area->vm_ops;
417 mpnt->vm_offset = area->vm_offset + (end - area->vm_start);
418 mpnt->vm_dentry = dget(area->vm_dentry);
419 if (mpnt->vm_ops && mpnt->vm_ops->open)
420 mpnt->vm_ops->open(mpnt);
421 area->vm_end = addr;
422 insert_vm_struct(current->mm, mpnt);
423 }
424
425
426 if (area->vm_ops && area->vm_ops->close) {
427 end = area->vm_end;
428 area->vm_end = area->vm_start;
429 area->vm_ops->close(area);
430 area->vm_end = end;
431 }
432
433 if (area->vm_ops && area->vm_ops->open)
434 area->vm_ops->open(area);
435 insert_vm_struct(current->mm, area);
436 return 1;
437}
438
439asmlinkage int sys_munmap(unsigned long addr, size_t len)
440{
441 int ret;
442
443 lock_kernel();
444 ret = do_munmap(addr, len);
445 unlock_kernel();
446 return ret;
447}
448
449
450
451
452
453
454int do_munmap(unsigned long addr, size_t len)
455{
456 struct vm_area_struct *mpnt, *next, *free, *extra;
457 int freed;
458
459 if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
460 return -EINVAL;
461
462 if ((len = PAGE_ALIGN(len)) == 0)
463 return 0;
464
465
466
467
468
469
470 mpnt = current->mm->mmap;
471 while(mpnt && mpnt->vm_end <= addr)
472 mpnt = mpnt->vm_next;
473 if (!mpnt)
474 return 0;
475
476
477
478
479
480 extra = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
481 if (!extra)
482 return -ENOMEM;
483
484 next = mpnt->vm_next;
485
486
487 free = NULL;
488 for ( ; mpnt && mpnt->vm_start < addr+len; ) {
489 struct vm_area_struct *next = mpnt->vm_next;
490
491 if(mpnt->vm_next)
492 mpnt->vm_next->vm_pprev = mpnt->vm_pprev;
493 *mpnt->vm_pprev = mpnt->vm_next;
494
495 mpnt->vm_next = free;
496 free = mpnt;
497 mpnt = next;
498 }
499
500
501
502
503
504
505 freed = 0;
506 while ((mpnt = free) != NULL) {
507 unsigned long st, end, size;
508
509 free = free->vm_next;
510 freed = 1;
511
512 remove_shared_vm_struct(mpnt);
513
514 st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
515 end = addr+len;
516 end = end > mpnt->vm_end ? mpnt->vm_end : end;
517 size = end - st;
518
519 if (mpnt->vm_ops && mpnt->vm_ops->unmap)
520 mpnt->vm_ops->unmap(mpnt, st, size);
521
522 flush_cache_range(current->mm, st, end);
523 zap_page_range(current->mm, st, size);
524 flush_tlb_range(current->mm, st, end);
525
526
527
528
529 if (!unmap_fixup(mpnt, st, size, &extra))
530 kmem_cache_free(vm_area_cachep, mpnt);
531 }
532
533
534 if (extra)
535 kmem_cache_free(vm_area_cachep, extra);
536
537 if (freed)
538 current->mm->mmap_cache = NULL;
539 return 0;
540}
541
542
543void exit_mmap(struct mm_struct * mm)
544{
545 struct vm_area_struct * mpnt;
546
547 mpnt = mm->mmap;
548 mm->mmap = mm->mmap_cache = NULL;
549 mm->rss = 0;
550 mm->total_vm = 0;
551 mm->locked_vm = 0;
552 while (mpnt) {
553 struct vm_area_struct * next = mpnt->vm_next;
554 unsigned long start = mpnt->vm_start;
555 unsigned long end = mpnt->vm_end;
556 unsigned long size = end - start;
557
558 if (mpnt->vm_ops) {
559 if (mpnt->vm_ops->unmap)
560 mpnt->vm_ops->unmap(mpnt, start, size);
561 if (mpnt->vm_ops->close)
562 mpnt->vm_ops->close(mpnt);
563 }
564 remove_shared_vm_struct(mpnt);
565 zap_page_range(mm, start, size);
566 if (mpnt->vm_dentry)
567 dput(mpnt->vm_dentry);
568 kmem_cache_free(vm_area_cachep, mpnt);
569 mpnt = next;
570 }
571}
572
573
574
575
576void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
577{
578 struct vm_area_struct **pprev = &mm->mmap;
579 struct dentry * dentry;
580
581
582 while(*pprev && (*pprev)->vm_start <= vmp->vm_start)
583 pprev = &(*pprev)->vm_next;
584
585
586 if((vmp->vm_next = *pprev) != NULL)
587 (*pprev)->vm_pprev = &vmp->vm_next;
588 *pprev = vmp;
589 vmp->vm_pprev = pprev;
590
591 dentry = vmp->vm_dentry;
592 if (dentry) {
593 struct inode * inode = dentry->d_inode;
594 if (vmp->vm_flags & VM_DENYWRITE)
595 inode->i_writecount--;
596
597
598 if((vmp->vm_next_share = inode->i_mmap) != NULL)
599 inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
600 inode->i_mmap = vmp;
601 vmp->vm_pprev_share = &inode->i_mmap;
602 }
603}
604
605
606
607
608
609
610
611void merge_segments (struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr)
612{
613 struct vm_area_struct *prev, *mpnt, *next;
614
615 down(&mm->mmap_sem);
616
617 prev = NULL;
618 mpnt = mm->mmap;
619 while(mpnt && mpnt->vm_end <= start_addr) {
620 prev = mpnt;
621 mpnt = mpnt->vm_next;
622 }
623 if (!mpnt)
624 goto no_vma;
625
626 next = mpnt->vm_next;
627
628
629 if (!prev) {
630 prev = mpnt;
631 mpnt = next;
632 }
633
634
635
636
637 for ( ; mpnt && prev->vm_start < end_addr ; prev = mpnt, mpnt = next) {
638 next = mpnt->vm_next;
639
640
641 if ((mpnt->vm_dentry != prev->vm_dentry)||
642 (mpnt->vm_pte != prev->vm_pte) ||
643 (mpnt->vm_ops != prev->vm_ops) ||
644 (mpnt->vm_flags != prev->vm_flags) ||
645 (prev->vm_end != mpnt->vm_start))
646 continue;
647
648
649
650
651
652 if ((mpnt->vm_dentry != NULL) || (mpnt->vm_flags & VM_SHM)) {
653 unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
654 if (off != mpnt->vm_offset)
655 continue;
656 }
657
658
659
660
661
662 if(mpnt->vm_next)
663 mpnt->vm_next->vm_pprev = mpnt->vm_pprev;
664 *mpnt->vm_pprev = mpnt->vm_next;
665
666 prev->vm_end = mpnt->vm_end;
667 if (mpnt->vm_ops && mpnt->vm_ops->close) {
668 mpnt->vm_offset += mpnt->vm_end - mpnt->vm_start;
669 mpnt->vm_start = mpnt->vm_end;
670 mpnt->vm_ops->close(mpnt);
671 }
672 remove_shared_vm_struct(mpnt);
673 if (mpnt->vm_dentry)
674 dput(mpnt->vm_dentry);
675 kmem_cache_free(vm_area_cachep, mpnt);
676 mpnt = prev;
677 }
678 mm->mmap_cache = NULL;
679no_vma:
680 up(&mm->mmap_sem);
681}
682
683__initfunc(void vma_init(void))
684{
685 vm_area_cachep = kmem_cache_create("vm_area_struct",
686 sizeof(struct vm_area_struct),
687 0, SLAB_HWCACHE_ALIGN,
688 NULL, NULL);
689 if(!vm_area_cachep)
690 panic("vma_init: Cannot alloc vm_area_struct cache.");
691
692 mm_cachep = kmem_cache_create("mm_struct",
693 sizeof(struct mm_struct),
694 0, SLAB_HWCACHE_ALIGN,
695 NULL, NULL);
696 if(!mm_cachep)
697 panic("vma_init: Cannot alloc mm_struct cache.");
698}
699