Commit f905bc447c303fefcb180c7e8b641746ffa6cf87

Authored by Paul Mundt
Committed by Linus Torvalds
1 parent f156ac8c7a

nommu: add new vmalloc_user() and remap_vmalloc_range() interfaces.

This builds on top of the earlier vmalloc_32_user() work introduced by
b50731732f926d6c49fd0724616a7344c31cd5cf, as we now have places in the nommu
allmodconfig that hit up against these missing APIs.

As vmalloc_32_user() is already implemented, this is moved over to
vmalloc_user() and simply made a wrapper.  As all current nommu platforms are
32-bit addressable, there's no special casing we have to do for ZONE_DMA and
things of that nature as per GFP_VMALLOC32.

remap_vmalloc_range() needs to check VM_USERMAP in order to figure out whether
we permit the remap or not, which means that we also have to rework the
vmalloc_user() code to grovel for the VMA and set the flag.

Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Acked-by: David McCullough <david_mccullough@securecomputing.com>
Acked-by: David Howells <dhowells@redhat.com>
Acked-by: Greg Ungerer <gerg@snapgear.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 1 changed file with 44 additions and 1 deletions Side-by-side Diff

... ... @@ -10,6 +10,7 @@
10 10 * Copyright (c) 2000-2003 David McCullough <davidm@snapgear.com>
11 11 * Copyright (c) 2000-2001 D Jeff Dionne <jeff@uClinux.org>
12 12 * Copyright (c) 2002 Greg Ungerer <gerg@snapgear.com>
  13 + * Copyright (c) 2007 Paul Mundt <lethal@linux-sh.org>
13 14 */
14 15  
15 16 #include <linux/module.h>
... ... @@ -183,6 +184,26 @@
183 184 }
184 185 EXPORT_SYMBOL(__vmalloc);
185 186  
  187 +void *vmalloc_user(unsigned long size)
  188 +{
  189 + void *ret;
  190 +
  191 + ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
  192 + PAGE_KERNEL);
  193 + if (ret) {
  194 + struct vm_area_struct *vma;
  195 +
  196 + down_write(&current->mm->mmap_sem);
  197 + vma = find_vma(current->mm, (unsigned long)ret);
  198 + if (vma)
  199 + vma->vm_flags |= VM_USERMAP;
  200 + up_write(&current->mm->mmap_sem);
  201 + }
  202 +
  203 + return ret;
  204 +}
  205 +EXPORT_SYMBOL(vmalloc_user);
  206 +
186 207 struct page *vmalloc_to_page(const void *addr)
187 208 {
188 209 return virt_to_page(addr);
189 210  
... ... @@ -253,10 +274,17 @@
253 274 *
254 275 * The resulting memory area is 32bit addressable and zeroed so it can be
255 276 * mapped to userspace without leaking data.
  277 + *
  278 + * VM_USERMAP is set on the corresponding VMA so that subsequent calls to
  279 + * remap_vmalloc_range() are permissible.
256 280 */
257 281 void *vmalloc_32_user(unsigned long size)
258 282 {
259   - return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
  283 + /*
  284 + * We'll have to sort out the ZONE_DMA bits for 64-bit,
  285 + * but for now this can simply use vmalloc_user() directly.
  286 + */
  287 + return vmalloc_user(size);
260 288 }
261 289 EXPORT_SYMBOL(vmalloc_32_user);
262 290  
... ... @@ -1215,6 +1243,21 @@
1215 1243 return 0;
1216 1244 }
1217 1245 EXPORT_SYMBOL(remap_pfn_range);
  1246 +
  1247 +int remap_vmalloc_range(struct vm_area_struct *vma, void *addr,
  1248 + unsigned long pgoff)
  1249 +{
  1250 + unsigned int size = vma->vm_end - vma->vm_start;
  1251 +
  1252 + if (!(vma->vm_flags & VM_USERMAP))
  1253 + return -EINVAL;
  1254 +
  1255 + vma->vm_start = (unsigned long)(addr + (pgoff << PAGE_SHIFT));
  1256 + vma->vm_end = vma->vm_start + size;
  1257 +
  1258 + return 0;
  1259 +}
  1260 +EXPORT_SYMBOL(remap_vmalloc_range);
1218 1261  
1219 1262 void swap_unplug_io_fn(struct backing_dev_info *bdi, struct page *page)
1220 1263 {