linux-old/mm/mlock.c
<<
>>
Prefs
   1/*
   2 *      linux/mm/mlock.c
   3 *
   4 *  (C) Copyright 1995 Linus Torvalds
   5 */
   6#include <linux/slab.h>
   7#include <linux/shm.h>
   8#include <linux/mman.h>
   9#include <linux/smp_lock.h>
  10
  11#include <asm/uaccess.h>
  12#include <asm/pgtable.h>
  13
  14static inline int mlock_fixup_all(struct vm_area_struct * vma, int newflags)
  15{
  16        vma->vm_flags = newflags;
  17        return 0;
  18}
  19
  20static inline int mlock_fixup_start(struct vm_area_struct * vma,
  21        unsigned long end, int newflags)
  22{
  23        struct vm_area_struct * n;
  24
  25        n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
  26        if (!n)
  27                return -EAGAIN;
  28        *n = *vma;
  29        vma->vm_start = end;
  30        n->vm_end = end;
  31        vma->vm_offset += vma->vm_start - n->vm_start;
  32        n->vm_flags = newflags;
  33        if (n->vm_file)
  34                n->vm_file->f_count++;
  35        if (n->vm_ops && n->vm_ops->open)
  36                n->vm_ops->open(n);
  37        insert_vm_struct(current->mm, n);
  38        return 0;
  39}
  40
  41static inline int mlock_fixup_end(struct vm_area_struct * vma,
  42        unsigned long start, int newflags)
  43{
  44        struct vm_area_struct * n;
  45
  46        n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
  47        if (!n)
  48                return -EAGAIN;
  49        *n = *vma;
  50        vma->vm_end = start;
  51        n->vm_start = start;
  52        n->vm_offset += n->vm_start - vma->vm_start;
  53        n->vm_flags = newflags;
  54        if (n->vm_file)
  55                n->vm_file->f_count++;
  56        if (n->vm_ops && n->vm_ops->open)
  57                n->vm_ops->open(n);
  58        insert_vm_struct(current->mm, n);
  59        return 0;
  60}
  61
  62static inline int mlock_fixup_middle(struct vm_area_struct * vma,
  63        unsigned long start, unsigned long end, int newflags)
  64{
  65        struct vm_area_struct * left, * right;
  66
  67        left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
  68        if (!left)
  69                return -EAGAIN;
  70        right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
  71        if (!right) {
  72                kmem_cache_free(vm_area_cachep, left);
  73                return -EAGAIN;
  74        }
  75        *left = *vma;
  76        *right = *vma;
  77        left->vm_end = start;
  78        vma->vm_start = start;
  79        vma->vm_end = end;
  80        right->vm_start = end;
  81        vma->vm_offset += vma->vm_start - left->vm_start;
  82        right->vm_offset += right->vm_start - left->vm_start;
  83        vma->vm_flags = newflags;
  84        if (vma->vm_file)
  85                vma->vm_file->f_count += 2;
  86
  87        if (vma->vm_ops && vma->vm_ops->open) {
  88                vma->vm_ops->open(left);
  89                vma->vm_ops->open(right);
  90        }
  91        insert_vm_struct(current->mm, left);
  92        insert_vm_struct(current->mm, right);
  93        return 0;
  94}
  95
  96static int mlock_fixup(struct vm_area_struct * vma, 
  97        unsigned long start, unsigned long end, unsigned int newflags)
  98{
  99        int pages, retval;
 100
 101        if (newflags == vma->vm_flags)
 102                return 0;
 103
 104        if (start == vma->vm_start) {
 105                if (end == vma->vm_end)
 106                        retval = mlock_fixup_all(vma, newflags);
 107                else
 108                        retval = mlock_fixup_start(vma, end, newflags);
 109        } else {
 110                if (end == vma->vm_end)
 111                        retval = mlock_fixup_end(vma, start, newflags);
 112                else
 113                        retval = mlock_fixup_middle(vma, start, end, newflags);
 114        }
 115        if (!retval) {
 116                /* keep track of amount of locked VM */
 117                pages = (end - start) >> PAGE_SHIFT;
 118                if (!(newflags & VM_LOCKED))
 119                        pages = -pages;
 120                vma->vm_mm->locked_vm += pages;
 121                make_pages_present(start, end);
 122        }
 123        return retval;
 124}
 125
 126static int do_mlock(unsigned long start, size_t len, int on)
 127{
 128        unsigned long nstart, end, tmp;
 129        struct vm_area_struct * vma, * next;
 130        int error;
 131
 132        if (on && !capable(CAP_IPC_LOCK))
 133                return -EPERM;
 134        len = (len + ~PAGE_MASK) & PAGE_MASK;
 135        end = start + len;
 136        if (end < start)
 137                return -EINVAL;
 138        if (end == start)
 139                return 0;
 140        vma = find_vma(current->mm, start);
 141        if (!vma || vma->vm_start > start)
 142                return -ENOMEM;
 143
 144        for (nstart = start ; ; ) {
 145                unsigned int newflags;
 146
 147                /* Here we know that  vma->vm_start <= nstart < vma->vm_end. */
 148
 149                newflags = vma->vm_flags | VM_LOCKED;
 150                if (!on)
 151                        newflags &= ~VM_LOCKED;
 152
 153                if (vma->vm_end >= end) {
 154                        error = mlock_fixup(vma, nstart, end, newflags);
 155                        break;
 156                }
 157
 158                tmp = vma->vm_end;
 159                next = vma->vm_next;
 160                error = mlock_fixup(vma, nstart, tmp, newflags);
 161                if (error)
 162                        break;
 163                nstart = tmp;
 164                vma = next;
 165                if (!vma || vma->vm_start != nstart) {
 166                        error = -ENOMEM;
 167                        break;
 168                }
 169        }
 170        merge_segments(current->mm, start, end);
 171        return error;
 172}
 173
 174asmlinkage int sys_mlock(unsigned long start, size_t len)
 175{
 176        unsigned long locked;
 177        unsigned long lock_limit;
 178        int error = -ENOMEM;
 179
 180        down(&current->mm->mmap_sem);
 181        lock_kernel();
 182        len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 183        start &= PAGE_MASK;
 184
 185        locked = len >> PAGE_SHIFT;
 186        locked += current->mm->locked_vm;
 187
 188        lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 189        if (lock_limit < RLIM_INFINITY) {
 190                lock_limit >>= PAGE_SHIFT;
 191
 192                /* check against resource limits */
 193                if (locked > lock_limit)
 194                        goto out;
 195        }
 196
 197        /* we may lock at most half of physical memory... */
 198        /* (this check is pretty bogus, but doesn't hurt) */
 199        if (locked > num_physpages/2)
 200                goto out;
 201
 202        error = do_mlock(start, len, 1);
 203out:
 204        unlock_kernel();
 205        up(&current->mm->mmap_sem);
 206        return error;
 207}
 208
 209asmlinkage int sys_munlock(unsigned long start, size_t len)
 210{
 211        int ret;
 212
 213        down(&current->mm->mmap_sem);
 214        lock_kernel();
 215        len = (len + (start & ~PAGE_MASK) + ~PAGE_MASK) & PAGE_MASK;
 216        start &= PAGE_MASK;
 217        ret = do_mlock(start, len, 0);
 218        unlock_kernel();
 219        up(&current->mm->mmap_sem);
 220        return ret;
 221}
 222
 223static int do_mlockall(int flags)
 224{
 225        int error;
 226        unsigned int def_flags;
 227        struct vm_area_struct * vma;
 228
 229        if (!capable(CAP_IPC_LOCK))
 230                return -EPERM;
 231
 232        def_flags = 0;
 233        if (flags & MCL_FUTURE)
 234                def_flags = VM_LOCKED;
 235        current->mm->def_flags = def_flags;
 236
 237        error = 0;
 238        for (vma = current->mm->mmap; vma ; vma = vma->vm_next) {
 239                unsigned int newflags;
 240
 241                newflags = vma->vm_flags | VM_LOCKED;
 242                if (!(flags & MCL_CURRENT))
 243                        newflags &= ~VM_LOCKED;
 244                error = mlock_fixup(vma, vma->vm_start, vma->vm_end, newflags);
 245                if (error)
 246                        break;
 247        }
 248        merge_segments(current->mm, 0, TASK_SIZE);
 249        return error;
 250}
 251
 252asmlinkage int sys_mlockall(int flags)
 253{
 254        unsigned long lock_limit;
 255        int ret = -EINVAL;
 256
 257        down(&current->mm->mmap_sem);
 258        lock_kernel();
 259        if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
 260                goto out;
 261
 262        ret = -ENOMEM;
 263        lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
 264        if (lock_limit < RLIM_INFINITY) {
 265                lock_limit >>= PAGE_SHIFT;
 266
 267                if (current->mm->total_vm > lock_limit)
 268                        goto out;
 269        }
 270
 271        /* we may lock at most half of physical memory... */
 272        /* (this check is pretty bogus, but doesn't hurt) */
 273        if (current->mm->total_vm > num_physpages/2)
 274                goto out;
 275
 276        ret = do_mlockall(flags);
 277out:
 278        unlock_kernel();
 279        up(&current->mm->mmap_sem);
 280        return ret;
 281}
 282
 283asmlinkage int sys_munlockall(void)
 284{
 285        int ret;
 286
 287        down(&current->mm->mmap_sem);
 288        lock_kernel();
 289        ret = do_mlockall(0);
 290        unlock_kernel();
 291        up(&current->mm->mmap_sem);
 292        return ret;
 293}
 294
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.