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;
  17        int ret = 0;
  18
  19        if (newflags == vma->vm_flags)
  20                goto out;
  21
  22        if (start != vma->vm_start) {
  23                if (split_vma(mm, vma, start, 1)) {
  24                        ret = -EAGAIN;
  25                        goto out;
  26                }
  27        }
  28
  29        if (end != vma->vm_end) {
  30                if (split_vma(mm, vma, end, 0)) {
  31                        ret = -EAGAIN;
  32                        goto out;
  33                }
  34        }
  35
  36        /*
  37         * vm_flags is protected by the mmap_sem held in write mode.
  38         * It's okay if try_to_unmap_one unmaps a page just after we
  39         * set VM_LOCKED, make_pages_present below will bring it back.
  40         */
  41        vma->vm_flags = newflags;
  42
  43        /*
  44         * Keep track of amount of locked VM.
  45         */
  46        pages = (end - start) >> PAGE_SHIFT;
  47        if (newflags & VM_LOCKED) {
  48                pages = -pages;
  49                ret = make_pages_present(start, end);
  50        }
  51
  52        vma->vm_mm->locked_vm -= pages;
  53out:
  54        return ret;
  55}
  56
  57static int do_mlock(unsigned long start, size_t len, int on)
  58{
  59        unsigned long nstart, end, tmp;
  60        struct vm_area_struct * vma, * next;
  61        int error;
  62
  63        if (on && !capable(CAP_IPC_LOCK))
  64                return -EPERM;
  65        len = PAGE_ALIGN(len);
  66        end = start + len;
  67        if (end < start)
  68                return -EINVAL;
  69        if (end == start)
  70                return 0;
  71        vma = find_vma(current->mm, start);
  72        if (!vma || vma->vm_start > start)
  73                return -ENOMEM;
  74
  75        for (nstart = start ; ; ) {
  76                unsigned int newflags;
  77
  78                /* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
  79
  80                newflags = vma->vm_flags | VM_LOCKED;
  81                if (!on)
  82                        newflags &= ~VM_LOCKED;
  83
  84                if (vma->vm_end >= end) {
  85                        error = mlock_fixup(vma, nstart, end, newflags);
  86                        break;
  87                }
  88
  89                tmp = vma->vm_end;
  90                next = vma->vm_next;
  91                error = mlock_fixup(vma, nstart, tmp, newflags);
  92                if (error)
  93                        break;
  94                nstart = tmp;
  95                vma = next;
  96                if (!vma || vma->vm_start != nstart) {
  97                        error = -ENOMEM;
  98                        break;
  99                }
 100        }
 101        return error;
 102}
 103
 104asmlinkage long sys_mlock(unsigned long start, size_t len)
 105{
 106        unsigned long locked;
 107        unsigned long lock_limit;
 108        int error = -ENOMEM;
 109
 110        down_write(&current->mm->mmap_sem);
 111        len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 112        start &= PAGE_MASK;
 113
 114        locked = len >> PAGE_SHIFT;
 115        locked += current->mm->locked_vm;
 116
 117        lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 118        lock_limit >>= PAGE_SHIFT;
 119
 120        /* check against resource limits */
 121        if (locked <= lock_limit)
 122                error = do_mlock(start, len, 1);
 123        up_write(&current->mm->mmap_sem);
 124        return error;
 125}
 126
 127asmlinkage long sys_munlock(unsigned long start, size_t len)
 128{
 129        int ret;
 130
 131        down_write(&current->mm->mmap_sem);
 132        len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
 133        start &= PAGE_MASK;
 134        ret = do_mlock(start, len, 0);
 135        up_write(&current->mm->mmap_sem);
 136        return ret;
 137}
 138
 139static int do_mlockall(int flags)
 140{
 141        int error;
 142        unsigned int def_flags;
 143        struct vm_area_struct * vma;
 144
 145        if (!capable(CAP_IPC_LOCK))
 146                return -EPERM;
 147
 148        def_flags = 0;
 149        if (flags & MCL_FUTURE)
 150                def_flags = VM_LOCKED;
 151        current->mm->def_flags = def_flags;
 152
 153        error = 0;
 154        for (vma = current->mm->mmap; vma ; vma = vma->vm_next) {
 155                unsigned int newflags;
 156
 157                newflags = vma->vm_flags | VM_LOCKED;
 158                if (!(flags & MCL_CURRENT))
 159                        newflags &= ~VM_LOCKED;
 160
 161                /* Ignore errors */
 162                mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
 163        }
 164        return error;
 165}
 166
 167asmlinkage long sys_mlockall(int flags)
 168{
 169        unsigned long lock_limit;
 170        int ret = -EINVAL;
 171
 172        down_write(&current->mm->mmap_sem);
 173        if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 174                goto out;
 175
 176        lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 177        lock_limit >>= PAGE_SHIFT;
 178
 179        ret = -ENOMEM;
 180        if (current->mm->total_vm <= lock_limit)
 181                ret = do_mlockall(flags);
 182out:
 183        up_write(&current->mm->mmap_sem);
 184        return ret;
 185}
 186
 187asmlinkage long sys_munlockall(void)
 188{
 189        int ret;
 190
 191        down_write(&current->mm->mmap_sem);
 192        ret = do_mlockall(0);
 193        up_write(&current->mm->mmap_sem);
 194        return ret;
 195}
 196
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.