linux-bk/mm/mlock.c
<<
>>
Prefs
   1/*
   2 *      linux/mm/mlock.c
   3 *
   4 *  (C) Copyright 1995 Linus Torvalds
   5 *  (C) Copyright 2002 Christoph Hellwig
   6 */
   7
   8#include <linux/mman.h>
   9#include <linux/mm.h>
  10
  11
  12static int mlock_fixup(struct vm_area_struct * vma, 
  13        unsigned long start, unsigned long end, unsigned int newflags)
  14{
  15        struct mm_struct * mm = vma->vm_mm;
  16        int pages, error;
  17
  18        if (newflags == vma->vm_flags)
  19                return 0;
  20
  21        if (start != vma->vm_start) {
  22                error = split_vma(mm, vma, start, 1);
  23                if (error)
  24                        return -EAGAIN;
  25        }
  26
  27        if (end != vma->vm_end) {
  28                error = split_vma(mm, vma, end, 0);
  29                if (error)
  30                        return -EAGAIN;
  31        }
  32        
  33        spin_lock(&mm->page_table_lock);
  34        vma->vm_flags = newflags;
  35        spin_unlock(&mm->page_table_lock);
  36
  37        /*
  38         * Keep track of amount of locked VM.
  39         */
  40        pages = (end - start) >> PAGE_SHIFT;
  41        if (newflags & VM_LOCKED) {
  42                pages = -pages;
  43                make_pages_present(start, end);
  44        }
  45
  46        vma->vm_mm->locked_vm -= pages;
  47        return 0;
  48}
  49
  50static int do_mlock(unsigned long start, size_t len, int on)
  51{
  52        unsigned long nstart, end, tmp;
  53        struct vm_area_struct * vma, * next;
  54        int error;
  55
  56        if (on && !capable(CAP_IPC_LOCK))
  57                return -EPERM;
  58        len = PAGE_ALIGN(len);
  59        end = start + len;
  60        if (end < start)
  61                return -EINVAL;
  62        if (end == start)
  63                return 0;
  64        vma = find_vma(current->mm, start);
  65        if (!vma || vma->vm_start > start)
  66                return -ENOMEM;
  67
  68        for (nstart = start ; ; ) {
  69                unsigned int newflags;
  70
  71                /* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
  72
  73                newflags = vma->vm_flags | VM_LOCKED;
  74                if (!on)
  75                        newflags &= ~VM_LOCKED;
  76
  77                if (vma->vm_end >= end) {
  78                        error = mlock_fixup(vma, nstart, end, newflags);
  79                        break;
  80                }
  81
  82                tmp = vma->vm_end;
  83                next = vma->vm_next;
  84                error = mlock_fixup(vma, nstart, tmp, newflags);
  85                if (error)
  86                        break;
  87                nstart = tmp;
  88                vma = next;
  89                if (!vma || vma->vm_start != nstart) {
  90                        error = -ENOMEM;
  91                        break;
  92                }
  93        }
  94        return error;
  95}
  96
  97asmlinkage long sys_mlock(unsigned long start, size_t len)
  98{
  99        unsigned long locked;
 100        unsigned long lock_limit;
 101        int error = -ENOMEM;
 102
 103        down_write(&current->mm->mmap_sem);
 104        len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 105        start &= PAGE_MASK;
 106
 107        locked = len >> PAGE_SHIFT;
 108        locked += current->mm->locked_vm;
 109
 110        lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 111        lock_limit >>= PAGE_SHIFT;
 112
 113        /* check against resource limits */
 114        if (locked > lock_limit)
 115                goto out;
 116
 117        /* we may lock at most half of physical memory... */
 118        /* (this check is pretty bogus, but doesn't hurt) */
 119        if (locked > num_physpages/2)
 120                goto out;
 121
 122        error = do_mlock(start, len, 1);
 123out:
 124        up_write(&current->mm->mmap_sem);
 125        return error;
 126}
 127
 128asmlinkage long sys_munlock(unsigned long start, size_t len)
 129{
 130        int ret;
 131
 132        down_write(&current->mm->mmap_sem);
 133        len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 134        start &= PAGE_MASK;
 135        ret = do_mlock(start, len, 0);
 136        up_write(&current->mm->mmap_sem);
 137        return ret;
 138}
 139
 140static int do_mlockall(int flags)
 141{
 142        int error;
 143        unsigned int def_flags;
 144        struct vm_area_struct * vma;
 145
 146        if (!capable(CAP_IPC_LOCK))
 147                return -EPERM;
 148
 149        def_flags = 0;
 150        if (flags & MCL_FUTURE)
 151                def_flags = VM_LOCKED;
 152        current->mm->def_flags = def_flags;
 153
 154        error = 0;
 155        for (vma = current->mm->mmap; vma ; vma = vma->vm_next) {
 156                unsigned int newflags;
 157
 158                newflags = vma->vm_flags | VM_LOCKED;
 159                if (!(flags & MCL_CURRENT))
 160                        newflags &= ~VM_LOCKED;
 161                error = mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
 162                if (error)
 163                        break;
 164        }
 165        return error;
 166}
 167
 168asmlinkage long sys_mlockall(int flags)
 169{
 170        unsigned long lock_limit;
 171        int ret = -EINVAL;
 172
 173        down_write(&current->mm->mmap_sem);
 174        if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 175                goto out;
 176
 177        lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 178        lock_limit >>= PAGE_SHIFT;
 179
 180        ret = -ENOMEM;
 181        if (current->mm->total_vm > lock_limit)
 182                goto out;
 183
 184        /* we may lock at most half of physical memory... */
 185        /* (this check is pretty bogus, but doesn't hurt) */
 186        if (current->mm->total_vm > num_physpages/2)
 187                goto out;
 188
 189        ret = do_mlockall(flags);
 190out:
 191        up_write(&current->mm->mmap_sem);
 192        return ret;
 193}
 194
 195asmlinkage long sys_munlockall(void)
 196{
 197        int ret;
 198
 199        down_write(&current->mm->mmap_sem);
 200        ret = do_mlockall(0);
 201        up_write(&current->mm->mmap_sem);
 202        return ret;
 203}
 204
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.