The patch titled mm: remap_vmalloc_range() has been added to the -mm tree. Its filename is mm-remap_vmalloc_range.patch See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find out what to do about this From: Nick Piggin <npiggin@xxxxxxx> Add a remap_vmalloc_range and get rid of as many remap_pfn_range and vm_insert_page loops as possible. remap_vmalloc_range can do a whole lot of nice range checking even if the caller gets it wrong (which it looks like one or two do). Signed-off-by: Nick Piggin <npiggin@xxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxx> --- arch/ia64/kernel/perfmon.c | 21 ----- drivers/media/video/cpia.c | 18 ---- drivers/media/video/em28xx/em28xx-video.c | 19 +--- drivers/media/video/et61x251/et61x251_core.c | 16 --- drivers/media/video/meye.c | 21 ----- drivers/media/video/ov511.c | 18 ---- drivers/media/video/pwc/pwc-if.c | 22 +---- drivers/media/video/se401.c | 18 ---- drivers/media/video/sn9c102/sn9c102_core.c | 16 --- drivers/media/video/stv680.c | 18 ---- drivers/media/video/usbvideo/usbvideo.c | 17 ---- drivers/media/video/usbvideo/vicam.c | 28 ++---- drivers/media/video/w9968cf.c | 16 --- drivers/media/video/zc0301/zc0301_core.c | 16 --- include/linux/vmalloc.h | 3 mm/vmalloc.c | 71 +++++++++++++++++ 16 files changed, 128 insertions(+), 210 deletions(-) diff -puN arch/ia64/kernel/perfmon.c~mm-remap_vmalloc_range arch/ia64/kernel/perfmon.c --- devel/arch/ia64/kernel/perfmon.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/arch/ia64/kernel/perfmon.c 2006-04-21 00:35:03.000000000 -0700 @@ -2237,25 +2237,6 @@ pfm_free_fd(int fd, struct file *file) put_unused_fd(fd); } -static int -pfm_remap_buffer(struct vm_area_struct *vma, unsigned long buf, unsigned long addr, unsigned long size) -{ - DPRINT(("CPU%d buf=0x%lx addr=0x%lx size=%ld\n", smp_processor_id(), buf, addr, size)); - - while (size > 0) { - unsigned long pfn = ia64_tpa(buf) >> PAGE_SHIFT; - - - if (remap_pfn_range(vma, addr, pfn, PAGE_SIZE, PAGE_READONLY)) - return -ENOMEM; - - addr += PAGE_SIZE; - buf += PAGE_SIZE; - size -= PAGE_SIZE; - } - return 0; -} - /* * allocate a sampling buffer and remaps it into the user address space of the task */ @@ -2343,7 +2324,7 @@ pfm_smpl_buffer_alloc(struct task_struct DPRINT(("aligned size=%ld, hdr=%p mapped @0x%lx\n", size, ctx->ctx_smpl_hdr, vma->vm_start)); /* can only be applied to current task, need to have the mm semaphore held when called */ - if (pfm_remap_buffer(vma, (unsigned long)smpl_buf, vma->vm_start, size)) { + if (remap_vmalloc_range(vma, smpl_buf, 0)) { DPRINT(("Can't remap buffer\n")); up_write(&task->mm->mmap_sem); goto error; diff -puN drivers/media/video/cpia.c~mm-remap_vmalloc_range drivers/media/video/cpia.c --- devel/drivers/media/video/cpia.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/cpia.c 2006-04-21 00:35:03.000000000 -0700 @@ -3750,9 +3750,7 @@ static int cpia_ioctl(struct inode *inod static int cpia_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *dev = file->private_data; - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; - unsigned long page, pos; struct cam_data *cam = dev->priv; int retval; @@ -3778,19 +3776,9 @@ static int cpia_mmap(struct file *file, } } - pos = (unsigned long)(cam->frame_buf); - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&cam->busy_lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + if (remap_vmalloc_range(vma, cam->frame_buf, 0)) { + mutex_unlock(&cam->busy_lock); + return -EAGAIN; } DBG("cpia_mmap: %ld\n", size); diff -puN drivers/media/video/em28xx/em28xx-video.c~mm-remap_vmalloc_range drivers/media/video/em28xx/em28xx-video.c --- devel/drivers/media/video/em28xx/em28xx-video.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/em28xx/em28xx-video.c 2006-04-21 00:35:03.000000000 -0700 @@ -34,6 +34,7 @@ #include <linux/version.h> #include <linux/video_decoder.h> #include <linux/mutex.h> +#include <linux/vmalloc.h> #include "em28xx.h" #include <media/tuner.h> @@ -586,9 +587,7 @@ static struct vm_operations_struct em28x */ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma) { - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; + unsigned long size = vma->vm_end - vma->vm_start; u32 i; struct em28xx *dev = filp->private_data; @@ -629,16 +628,10 @@ static int em28xx_v4l2_mmap(struct file vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ - pos = dev->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - em28xx_videodbg("mmap: vm_insert_page failed\n"); - mutex_unlock(&dev->fileop_lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; + if (remap_vmalloc_range(vma, dev->frame[i].bufmem, 0)) { + em28xx_videodbg("mmap: remap_vmalloc_range failed\n"); + mutex_unlock(&dev->fileop_lock); + return -EAGAIN; } vma->vm_ops = &em28xx_vm_ops; diff -puN drivers/media/video/et61x251/et61x251_core.c~mm-remap_vmalloc_range drivers/media/video/et61x251/et61x251_core.c --- devel/drivers/media/video/et61x251/et61x251_core.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/et61x251/et61x251_core.c 2006-04-21 00:35:03.000000000 -0700 @@ -1464,9 +1464,7 @@ static struct vm_operations_struct et61x static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma) { struct et61x251_device* cam = video_get_drvdata(video_devdata(filp)); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; + unsigned long size = vma->vm_end - vma->vm_start; u32 i; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -1503,15 +1501,9 @@ static int et61x251_mmap(struct file* fi vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; + if (remap_vmalloc_range(vma, cam->frame[i].bufmem, 0)) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; } vma->vm_ops = &et61x251_vm_ops; diff -puN drivers/media/video/meye.c~mm-remap_vmalloc_range drivers/media/video/meye.c --- devel/drivers/media/video/meye.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/meye.c 2006-04-21 00:35:03.000000000 -0700 @@ -1699,13 +1699,10 @@ static struct vm_operations_struct meye_ static int meye_mmap(struct file *file, struct vm_area_struct *vma) { - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - unsigned long page, pos; mutex_lock(&meye.lock); - if (size > gbuffers * gbufsize) { + if (size > gbuffers * gbufsize) { /* XXX: should be size + vm_pgoff? */ mutex_unlock(&meye.lock); return -EINVAL; } @@ -1722,20 +1719,10 @@ static int meye_mmap(struct file *file, for (i = 0; i < gbuffers; i++) meye.vma_use_count[i] = 0; } - pos = (unsigned long)meye.grab_fbuffer + offset; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&meye.lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + if (remap_vmalloc_range(vma, meye.grab_fbuffer, vma->vm_pgoff)) { + mutex_unlock(&meye.lock); + return -EAGAIN; } vma->vm_ops = &meye_vm_ops; diff -puN drivers/media/video/ov511.c~mm-remap_vmalloc_range drivers/media/video/ov511.c --- devel/drivers/media/video/ov511.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/ov511.c 2006-04-21 00:35:03.000000000 -0700 @@ -4616,10 +4616,8 @@ static int ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma) { struct video_device *vdev = file->private_data; - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start; struct usb_ov511 *ov = video_get_drvdata(vdev); - unsigned long page, pos; if (ov->dev == NULL) return -EIO; @@ -4634,19 +4632,9 @@ ov51x_v4l1_mmap(struct file *file, struc if (mutex_lock_interruptible(&ov->lock)) return -EINTR; - pos = (unsigned long)ov->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&ov->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + if (remap_vmalloc_range(vma, ov->fbuf, 0)) { + mutex_unlock(&ov->lock); + return -EAGAIN; } mutex_unlock(&ov->lock); diff -puN drivers/media/video/pwc/pwc-if.c~mm-remap_vmalloc_range drivers/media/video/pwc/pwc-if.c --- devel/drivers/media/video/pwc/pwc-if.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/pwc/pwc-if.c 2006-04-21 00:35:03.000000000 -0700 @@ -1602,28 +1602,16 @@ static int pwc_video_mmap(struct file *f { struct video_device *vdev = file->private_data; struct pwc_device *pdev; - unsigned long start = vma->vm_start; - unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; - Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); + /* XXX: should check ranges */ + Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, + vma->vm_start, vma->vm_end - vma->vm_start); pdev = vdev->priv; vma->vm_flags |= VM_IO; - pos = (unsigned long)pdev->image_data; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } + if (remap_vmalloc_range(vma, pdev->image_data, 0)) + return -EAGAIN; return 0; } diff -puN drivers/media/video/se401.c~mm-remap_vmalloc_range drivers/media/video/se401.c --- devel/drivers/media/video/se401.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/se401.c 2006-04-21 00:35:03.000000000 -0700 @@ -1153,9 +1153,7 @@ static int se401_mmap(struct file *file, { struct video_device *dev = file->private_data; struct usb_se401 *se401 = (struct usb_se401 *)dev; - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; mutex_lock(&se401->lock); @@ -1167,19 +1165,9 @@ static int se401_mmap(struct file *file, mutex_unlock(&se401->lock); return -EINVAL; } - pos = (unsigned long)se401->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&se401->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + if (remap_vmalloc_range(vma, se401->fbuf, 0)) { + mutex_unlock(&se401->lock); + return -EAGAIN; } mutex_unlock(&se401->lock); diff -puN drivers/media/video/sn9c102/sn9c102_core.c~mm-remap_vmalloc_range drivers/media/video/sn9c102/sn9c102_core.c --- devel/drivers/media/video/sn9c102/sn9c102_core.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/sn9c102/sn9c102_core.c 2006-04-21 00:35:03.000000000 -0700 @@ -1728,9 +1728,7 @@ static struct vm_operations_struct sn9c1 static int sn9c102_mmap(struct file* filp, struct vm_area_struct *vma) { struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp)); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; + unsigned long size = vma->vm_end - vma->vm_start; u32 i; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -1767,15 +1765,9 @@ static int sn9c102_mmap(struct file* fil vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; + if (remap_vmalloc_range(vma, cam->frame[i].bufmem, 0)) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; } vma->vm_ops = &sn9c102_vm_ops; diff -puN drivers/media/video/stv680.c~mm-remap_vmalloc_range drivers/media/video/stv680.c --- devel/drivers/media/video/stv680.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/stv680.c 2006-04-21 00:35:03.000000000 -0700 @@ -1254,9 +1254,7 @@ static int stv680_mmap (struct file *fil { struct video_device *dev = file->private_data; struct usb_stv *stv680 = video_get_drvdata(dev); - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; mutex_lock(&stv680->lock); @@ -1269,19 +1267,9 @@ static int stv680_mmap (struct file *fil mutex_unlock(&stv680->lock); return -EINVAL; } - pos = (unsigned long) stv680->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) { - mutex_unlock(&stv680->lock); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; + if (remap_vmalloc_range(vma, stv680->fbuf, 0)) { + mutex_unlock(&stv680->lock); + return -EAGAIN; } mutex_unlock(&stv680->lock); diff -puN drivers/media/video/usbvideo/usbvideo.c~mm-remap_vmalloc_range drivers/media/video/usbvideo/usbvideo.c --- devel/drivers/media/video/usbvideo/usbvideo.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/usbvideo/usbvideo.c 2006-04-21 00:35:03.000000000 -0700 @@ -1068,9 +1068,7 @@ EXPORT_SYMBOL(usbvideo_RegisterVideoDevi static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma) { struct uvd *uvd = file->private_data; - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; - unsigned long page, pos; if (!CAMERA_IS_OPERATIONAL(uvd)) return -EFAULT; @@ -1078,19 +1076,8 @@ static int usbvideo_v4l_mmap(struct file if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))) return -EINVAL; - pos = (unsigned long) uvd->fbuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } + if (remap_vmalloc_range(vma, uvd->fbuf, 0)) + return -EAGAIN; return 0; } diff -puN drivers/media/video/usbvideo/vicam.c~mm-remap_vmalloc_range drivers/media/video/usbvideo/vicam.c --- devel/drivers/media/video/usbvideo/vicam.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/usbvideo/vicam.c 2006-04-21 00:35:03.000000000 -0700 @@ -1029,8 +1029,6 @@ static int vicam_mmap(struct file *file, struct vm_area_struct *vma) { // TODO: allocate the raw frame buffer if necessary - unsigned long page, pos; - unsigned long start = vma->vm_start; unsigned long size = vma->vm_end-vma->vm_start; struct vicam_camera *cam = file->private_data; @@ -1039,25 +1037,17 @@ vicam_mmap(struct file *file, struct vm_ DBG("vicam_mmap: %ld\n", size); - /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes - * to the size the application requested for mmap and it was screwing apps up. - if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) - return -EINVAL; + /* We let mmap allocate as much as it wants because Linux was adding + * 2048 bytes to the size the application requested for mmap and it was + * screwing apps up. + * + * It shouldn't have been, so let's try this check again -np */ + if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE) + return -EINVAL; - pos = (unsigned long)cam->framebuf; - while (size > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - - start += PAGE_SIZE; - pos += PAGE_SIZE; - if (size > PAGE_SIZE) - size -= PAGE_SIZE; - else - size = 0; - } + if (remap_vmalloc_range(vma, cam->framebuf, 0)) + return -EAGAIN; return 0; } diff -puN drivers/media/video/w9968cf.c~mm-remap_vmalloc_range drivers/media/video/w9968cf.c --- devel/drivers/media/video/w9968cf.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/w9968cf.c 2006-04-21 00:35:03.000000000 -0700 @@ -2861,10 +2861,7 @@ static int w9968cf_mmap(struct file* fil struct w9968cf_device* cam = (struct w9968cf_device*) video_get_drvdata(video_devdata(filp)); unsigned long vsize = vma->vm_end - vma->vm_start, - psize = cam->nbuffers * cam->frame[0].size, - start = vma->vm_start, - pos = (unsigned long)cam->frame[0].buffer, - page; + psize = cam->nbuffers * cam->frame[0].size; if (cam->disconnected) { DBG(2, "Device not present") @@ -2881,15 +2878,8 @@ static int w9968cf_mmap(struct file* fil if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT)) return -EINVAL; - while (vsize > 0) { - page = vmalloc_to_pfn((void *)pos); - if (remap_pfn_range(vma, start, page + vma->vm_pgoff, - PAGE_SIZE, vma->vm_page_prot)) - return -EAGAIN; - start += PAGE_SIZE; - pos += PAGE_SIZE; - vsize -= PAGE_SIZE; - } + if (remap_vmalloc_range(vma, cam->frame[0].buffer, vma->vm_pgoff)) + return -EAGAIN; DBG(5, "mmap method successfully called") return 0; diff -puN drivers/media/video/zc0301/zc0301_core.c~mm-remap_vmalloc_range drivers/media/video/zc0301/zc0301_core.c --- devel/drivers/media/video/zc0301/zc0301_core.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/drivers/media/video/zc0301/zc0301_core.c 2006-04-21 00:35:03.000000000 -0700 @@ -929,9 +929,7 @@ static struct vm_operations_struct zc030 static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma) { struct zc0301_device* cam = video_get_drvdata(video_devdata(filp)); - unsigned long size = vma->vm_end - vma->vm_start, - start = vma->vm_start; - void *pos; + unsigned long size = vma->vm_end - vma->vm_start; u32 i; if (mutex_lock_interruptible(&cam->fileop_mutex)) @@ -968,15 +966,9 @@ static int zc0301_mmap(struct file* filp vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; - pos = cam->frame[i].bufmem; - while (size > 0) { /* size is page-aligned */ - if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { - mutex_unlock(&cam->fileop_mutex); - return -EAGAIN; - } - start += PAGE_SIZE; - pos += PAGE_SIZE; - size -= PAGE_SIZE; + if (remap_vmalloc_range(vma, cam->frame[i].bufmem, 0)) { + mutex_unlock(&cam->fileop_mutex); + return -EAGAIN; } vma->vm_ops = &zc0301_vm_ops; diff -puN include/linux/vmalloc.h~mm-remap_vmalloc_range include/linux/vmalloc.h --- devel/include/linux/vmalloc.h~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/include/linux/vmalloc.h 2006-04-21 00:35:03.000000000 -0700 @@ -45,6 +45,9 @@ extern void vfree(void *addr); extern void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot); extern void vunmap(void *addr); + +extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, + unsigned long pgoff); /* * Lowlevel-APIs (not for driver use!) diff -puN mm/vmalloc.c~mm-remap_vmalloc_range mm/vmalloc.c --- devel/mm/vmalloc.c~mm-remap_vmalloc_range 2006-04-21 00:35:03.000000000 -0700 +++ devel-akpm/mm/vmalloc.c 2006-04-21 00:35:03.000000000 -0700 @@ -257,6 +257,19 @@ struct vm_struct *get_vm_area_node(unsig } /* Caller must hold vmlist_lock */ +static struct vm_struct *__find_vm_area(void *addr) +{ + struct vm_struct *tmp; + + for (tmp = vmlist; tmp != NULL; tmp = tmp->next) { + if (tmp->addr == addr) + break; + } + + return tmp; +} + +/* Caller must hold vmlist_lock */ struct vm_struct *__remove_vm_area(void *addr) { struct vm_struct **p, *tmp; @@ -630,3 +643,61 @@ finished: read_unlock(&vmlist_lock); return buf - buf_start; } + +/** + * remap_vmalloc_range - map vmalloc pages to userspace + * + * @vma: vma to cover (map full range of vma) + * @addr: vmalloc memory + * @pgoff: number of pages into addr before first page to map + * @returns: 0 for success, -Exxx on failure + * + * This function checks that addr is a valid vmalloc'ed area, and + * that it is big enough to cover the vma. Will return failure if + * that criteria isn't met. + * + * Similar to remap_pfn_range (see mm/memory.c) + */ +int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, + unsigned long pgoff) +{ + struct vm_struct *area; + unsigned long uaddr = vma->vm_start; + unsigned long usize = vma->vm_end - vma->vm_start; + int ret; + + if ((PAGE_SIZE-1) & (unsigned long)addr) + return -EINVAL; + + read_lock(&vmlist_lock); + area = __find_vm_area(addr); + if (!area) + goto out_einval_locked; + + if (usize + (pgoff << PAGE_SHIFT) > area->size - PAGE_SIZE) + goto out_einval_locked; + read_unlock(&vmlist_lock); + + addr = (void *)((unsigned long)addr + (pgoff << PAGE_SHIFT)); + do { + struct page *page = vmalloc_to_page(addr); + ret = vm_insert_page(vma, uaddr, page); + if (ret) + return ret; + + uaddr += PAGE_SIZE; + addr = (void *)((unsigned long)addr+PAGE_SIZE); + usize -= PAGE_SIZE; + } while (usize > 0); + + /* Prevent "things" like memory migration? VM_flags need a cleanup... */ + vma->vm_flags |= VM_RESERVED; + + return ret; + +out_einval_locked: + read_unlock(&vmlist_lock); + return -EINVAL; +} +EXPORT_SYMBOL(remap_vmalloc_range); + _ Patches currently in -mm which might be from npiggin@xxxxxxx are mm-vm_bug_on.patch mm-remap_vmalloc_range.patch mm-remove-vmalloc_to_pfn.patch mm-remove-rvmalloc.patch mm-extra-remap_vmalloc_range-check.patch drivers-leave-vm_flags-alone.patch reiser4-releasepage-fix.patch - To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html