00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <linux/config.h>
00013 #include <linux/slab.h>
00014 #include <linux/shm.h>
00015 #include <linux/mman.h>
00016 #include <linux/smp_lock.h>
00017 #include <linux/pagemap.h>
00018
00019 #include <asm/uaccess.h>
00020 #include <asm/pgtable.h>
00021
00022 #include <ipldef.h>
00023 #include <phddef.h>
00024 #include <rdedef.h>
00025 #include <misc_routines.h>
00026
00027 static inline int mlock_fixup_all(struct _rde * vma, int newflags)
00028 {
00029
00030 vma->rde_l_flags = newflags;
00031
00032 return 0;
00033 }
00034
00035 static inline int mlock_fixup_start(struct _rde * vma,
00036 unsigned long end, int newflags)
00037 {
00038 struct _rde * n;
00039
00040 n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
00041 if (!n)
00042 return -EAGAIN;
00043 *n = *vma;
00044 n->rde_q_region_size = end - (unsigned long)n->rde$pq_start_va;
00045 n->rde_l_flags = newflags;
00046
00047 #if 0
00048 if (n->vm_file)
00049 get_file(n->vm_file);
00050 if (n->vm_ops && n->vm_ops->open)
00051 n->vm_ops->open(n);
00052 vma->vm_pgoff += (end - vma->rde_pq_start_va) >> PAGE_SHIFT;
00053 #endif
00054 lock_vma_mappings(vma);
00055
00056 vma->rde_pq_start_va = end;
00057
00058 insrde(n,¤t->pcb_l_phd->phd$ps_p0_va_list_flink);
00059
00060 unlock_vma_mappings(vma);
00061 return 0;
00062 }
00063
00064 static inline int mlock_fixup_end(struct _rde * vma,
00065 unsigned long start, int newflags)
00066 {
00067 struct _rde * n;
00068
00069 n = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
00070 if (!n)
00071 return -EAGAIN;
00072 *n = *vma;
00073 n->rde_pq_start_va = start;
00074
00075 n->rde_l_flags = newflags;
00076 #if 0
00077 n->vm_raend = 0;
00078 if (n->vm_file)
00079 get_file(n->vm_file);
00080 if (n->vm_ops && n->vm_ops->open)
00081 n->vm_ops->open(n);
00082 lock_vma_mappings(vma);
00083 #endif
00084
00085 vma->rde_q_region_size = start - (unsigned long)vma->rde$pq_start_va;
00086
00087 insrde(n,¤t->pcb_l_phd->phd$ps_p0_va_list_flink);
00088
00089 unlock_vma_mappings(vma);
00090 return 0;
00091 }
00092
00093 static inline int mlock_fixup_middle(struct _rde * vma,
00094 unsigned long start, unsigned long end, int newflags)
00095 {
00096 struct _rde * left, * right;
00097
00098 left = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
00099 if (!left)
00100 return -EAGAIN;
00101 right = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL);
00102 if (!right) {
00103 kmem_cache_free(vm_area_cachep, left);
00104 return -EAGAIN;
00105 }
00106 *left = *vma;
00107 *right = *vma;
00108 left->rde_q_region_size = start - (unsigned long)left->rde$pq_start_va;
00109 right->rde_pq_start_va = end;
00110 #if 0
00111 right->vm_pgoff += (right->rde_pq_start_va - left->rde$pq_start_va) >> PAGE_SHIFT;
00112 #endif
00113 vma->rde_l_flags = newflags;
00114 #if 0
00115 left->vm_raend = 0;
00116 right->vm_raend = 0;
00117 if (vma->vm_file)
00118 atomic_add(2, &vma->vm_file->f_count);
00119
00120 if (vma->vm_ops && vma->vm_ops->open) {
00121 vma->vm_ops->open(left);
00122 vma->vm_ops->open(right);
00123 }
00124 vma->vm_raend = 0;
00125 vma->vm_pgoff += (start - vma->rde_pq_start_va) >> PAGE_SHIFT;
00126 #endif
00127 lock_vma_mappings(vma);
00128
00129 vma->rde_pq_start_va = start;
00130 vma->rde_q_region_size = end - (unsigned long)vma->rde$pq_start_va;
00131 vma->rde_l_flags = newflags;
00132
00133 insrde(left,¤t->pcb_l_phd->phd$ps_p0_va_list_flink);
00134
00135 insrde(right,¤t->pcb_l_phd->phd$ps_p0_va_list_flink);
00136
00137 unlock_vma_mappings(vma);
00138 return 0;
00139 }
00140
00141 static int mlock_fixup(struct _rde * vma,
00142 unsigned long start, unsigned long end, unsigned int newflags)
00143 {
00144 int pages, retval;
00145
00146 if (newflags == vma->rde_l_flags)
00147 return 0;
00148
00149 if (start == vma->rde_pq_start_va) {
00150 if (end == (vma->rde_pq_start_va + vma->rde$q_region_size))
00151 retval = mlock_fixup_all(vma, newflags);
00152 else
00153 retval = mlock_fixup_start(vma, end, newflags);
00154 } else {
00155 if (end == (vma->rde_pq_start_va + vma->rde$q_region_size))
00156 retval = mlock_fixup_end(vma, start, newflags);
00157 else
00158 retval = mlock_fixup_middle(vma, start, end, newflags);
00159 }
00160 if (!retval) {
00161
00162 pages = (end - start) >> PAGE_SHIFT;
00163 if (newflags & VM_LOCKED) {
00164 pages = -pages;
00165 make_pages_present(start, end);
00166 }
00167
00168 }
00169 return retval;
00170 }
00171
00172 static int do_mlock(unsigned long start, size_t len, int on)
00173 {
00174 unsigned long nstart, end, tmp;
00175 struct _rde * vma, * next;
00176 int error;
00177
00178 if (on && !capable(CAP_IPC_LOCK))
00179 return -EPERM;
00180 len = PAGE_ALIGN(len);
00181 end = start + len;
00182 if (end < start)
00183 return -EINVAL;
00184 if (end == start)
00185 return 0;
00186
00187 vma = find_vma(current->pcb_l_phd,start);
00188 if (!vma || vma->rde_pq_start_va > start)
00189 return -ENOMEM;
00190
00191 for (nstart = start ; ; ) {
00192 unsigned int newflags;
00193
00194
00195
00196 newflags = vma->rde_l_flags | VM_LOCKED;
00197 if (!on)
00198 newflags &= ~VM_LOCKED;
00199
00200 if ((vma->rde_pq_start_va + vma->rde$q_region_size) >= end) {
00201 error = mlock_fixup(vma, nstart, end, newflags);
00202 break;
00203 }
00204
00205 tmp = (vma->rde_pq_start_va + vma->rde$q_region_size);
00206 next = vma->rde_ps_va_list_flink;
00207 error = mlock_fixup(vma, nstart, tmp, newflags);
00208 if (error)
00209 break;
00210 nstart = tmp;
00211 vma = next;
00212 if (!vma || vma->rde_pq_start_va != nstart) {
00213 error = -ENOMEM;
00214 break;
00215 }
00216 }
00217 return error;
00218 }
00219
00220 asmlinkage long sys_mlock(unsigned long start, size_t len)
00221 {
00222 unsigned long locked;
00223 unsigned long lock_limit;
00224 int error = -ENOMEM;
00225
00226 down_write(¤t->mm->mmap_sem);
00227 len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
00228 start &= PAGE_MASK;
00229
00230 locked = len >> PAGE_SHIFT;
00231 locked += current->mm->locked_vm;
00232
00233 lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
00234 lock_limit >>= PAGE_SHIFT;
00235
00236
00237 if (locked > lock_limit)
00238 goto out;
00239
00240
00241
00242 if (locked > num_physpages/2)
00243 goto out;
00244
00245 error = do_mlock(start, len, 1);
00246 out:
00247 up_write(¤t->mm->mmap_sem);
00248 return error;
00249 }
00250
00251 asmlinkage long sys_munlock(unsigned long start, size_t len)
00252 {
00253 int ret;
00254
00255 down_write(¤t->mm->mmap_sem);
00256 len = PAGE_ALIGN(len + (start & ~PAGE_MASK));
00257 start &= PAGE_MASK;
00258 ret = do_mlock(start, len, 0);
00259 up_write(¤t->mm->mmap_sem);
00260 return ret;
00261 }
00262
00263 static int do_mlockall(int flags)
00264 {
00265 int error;
00266 unsigned int def_flags;
00267 struct _rde * vma;
00268
00269 if (!capable(CAP_IPC_LOCK))
00270 return -EPERM;
00271
00272 def_flags = 0;
00273 if (flags & MCL_FUTURE)
00274 def_flags = VM_LOCKED;
00275 current->mm->def_flags = def_flags;
00276
00277 error = 0;
00278 for (vma = current->mm->mmap; vma ; vma = vma->rde_ps_va_list_flink) {
00279 unsigned int newflags;
00280
00281 newflags = vma->rde_l_flags | VM_LOCKED;
00282 if (!(flags & MCL_CURRENT))
00283 newflags &= ~VM_LOCKED;
00284 error = mlock_fixup(vma, vma->rde_pq_start_va, (vma->rde$pq_start_va + vma->rde$q_region_size), newflags);
00285 if (error)
00286 break;
00287 }
00288 return error;
00289 }
00290
00291 asmlinkage long sys_mlockall(int flags)
00292 {
00293 unsigned long lock_limit;
00294 int ret = -EINVAL;
00295
00296 down_write(¤t->mm->mmap_sem);
00297 if (!flags || (flags & ~(MCL_CURRENT | MCL_FUTURE)))
00298 goto out;
00299
00300 lock_limit = current->rlim[RLIMIT_MEMLOCK].rlim_cur;
00301 lock_limit >>= PAGE_SHIFT;
00302
00303 ret = -ENOMEM;
00304 if (current->mm->total_vm > lock_limit)
00305 goto out;
00306
00307
00308
00309 if (current->mm->total_vm > num_physpages/2)
00310 goto out;
00311
00312 ret = do_mlockall(flags);
00313 out:
00314 up_write(¤t->mm->mmap_sem);
00315 return ret;
00316 }
00317
00318 asmlinkage long sys_munlockall(void)
00319 {
00320 int ret;
00321
00322 down_write(¤t->mm->mmap_sem);
00323 ret = do_mlockall(0);
00324 up_write(¤t->mm->mmap_sem);
00325 return ret;
00326 }
00327