[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [linux-2.6.18-xen] xen/privcmd: convert single shot check to be per-page



# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1262765650 0
# Node ID f6017e7c6615687365ae7e66dd673898285d884d
# Parent  e5d3ccab348c7b3012bb5167c843fea2195c6002
xen/privcmd: convert single shot check to be per-page

For the sake of not breaking the ia64 build, old behavior is being
retained when HAVE_ARCH_PRIVCMD_MMAP. Hopefully someone able to
test ia64 can fix this up in the not too distant future.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
---
 drivers/xen/privcmd/privcmd.c |   74 +++++++++++++++++++++++++++---------------
 1 files changed, 48 insertions(+), 26 deletions(-)

diff -r e5d3ccab348c -r f6017e7c6615 drivers/xen/privcmd/privcmd.c
--- a/drivers/xen/privcmd/privcmd.c     Mon Jan 04 10:37:14 2010 +0000
+++ b/drivers/xen/privcmd/privcmd.c     Wed Jan 06 08:14:10 2010 +0000
@@ -34,7 +34,22 @@ static struct proc_dir_entry *capabiliti
 static struct proc_dir_entry *capabilities_intf;
 
 #ifndef HAVE_ARCH_PRIVCMD_MMAP
-static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
+static int enforce_singleshot_mapping_fn(pte_t *pte, pgtable_t token,
+                                        unsigned long addr, void *data)
+{
+       return pte_none(*pte) ? 0 : -EBUSY;
+}
+
+static inline int enforce_singleshot_mapping(struct vm_area_struct *vma,
+                                            unsigned long addr,
+                                            unsigned long npages)
+{
+       return apply_to_page_range(vma->vm_mm, addr, npages << PAGE_SHIFT,
+                                  enforce_singleshot_mapping_fn, NULL) == 0;
+}
+#else
+#define enforce_singleshot_mapping(vma, addr, npages) \
+       privcmd_enforce_singleshot_mapping(vma)
 #endif
 
 static long privcmd_ioctl(struct file *file,
@@ -110,6 +125,9 @@ static long privcmd_ioctl(struct file *f
                if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
                        return -EFAULT;
 
+               if (mmapcmd.num <= 0)
+                       return -EINVAL;
+
                p = mmapcmd.entry;
                for (i = 0; i < mmapcmd.num;) {
                        int nr = min(mmapcmd.num - i, MMAP_NR_PER_PAGE);
@@ -137,8 +155,7 @@ static long privcmd_ioctl(struct file *f
 
                vma = find_vma(mm, msg->va);
                rc = -EINVAL;
-               if (!vma || (msg->va != vma->vm_start) ||
-                   !privcmd_enforce_singleshot_mapping(vma))
+               if (!vma || (msg->va != vma->vm_start))
                        goto mmap_out;
 
                va = vma->vm_start;
@@ -151,7 +168,6 @@ static long privcmd_ioctl(struct file *f
                        while (i<nr) {
 
                                /* Do not allow range to wrap the address 
space. */
-                               rc = -EINVAL;
                                if ((msg->npages > (LONG_MAX >> PAGE_SHIFT)) ||
                                    ((unsigned long)(msg->npages << PAGE_SHIFT) 
>= -va))
                                        goto mmap_out;
@@ -161,6 +177,23 @@ static long privcmd_ioctl(struct file *f
                                    ((msg->va+(msg->npages<<PAGE_SHIFT)) > 
vma->vm_end))
                                        goto mmap_out;
 
+                               va += msg->npages << PAGE_SHIFT;
+                               msg++;
+                               i++;
+                       }
+               }
+
+               if (!enforce_singleshot_mapping(vma, vma->vm_start,
+                                               (va - vma->vm_start) >> 
PAGE_SHIFT))
+                       goto mmap_out;
+
+               va = vma->vm_start;
+               i = 0;
+               list_for_each(l, &pagelist) {
+                       int nr = i + min(mmapcmd.num - i, MMAP_NR_PER_PAGE);
+
+                       msg = (privcmd_mmap_entry_t*)(l + 1);
+                       while (i < nr) {
                                if ((rc = direct_remap_pfn_range(
                                             vma,
                                             msg->va & PAGE_MASK,
@@ -206,7 +239,9 @@ static long privcmd_ioctl(struct file *f
                        return -EFAULT;
 
                nr_pages = m.num;
-               if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
+               addr = m.addr;
+               if (m.num <= 0 || nr_pages > (LONG_MAX >> PAGE_SHIFT) ||
+                   addr != m.addr || nr_pages > (-addr >> PAGE_SHIFT))
                        return -EINVAL;
 
                p = m.arr;
@@ -231,24 +266,16 @@ static long privcmd_ioctl(struct file *f
 
                down_write(&mm->mmap_sem);
 
-               vma = find_vma(mm, m.addr);
+               vma = find_vma(mm, addr);
                ret = -EINVAL;
                if (!vma ||
-                   (m.addr != vma->vm_start) ||
-                   ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
-                   !privcmd_enforce_singleshot_mapping(vma)) {
-                       if (!(vma &&
-                             (m.addr >= vma->vm_start) &&
-                             ((m.addr + (nr_pages << PAGE_SHIFT)) <= 
vma->vm_end) &&
-                             (nr_pages == 1) &&
-                             !privcmd_enforce_singleshot_mapping(vma))) {
-                               up_write(&mm->mmap_sem);
-                               goto mmapbatch_out;
-                       }
-               }
-
-               p = m.arr;
-               addr = m.addr;
+                   addr < vma->vm_start ||
+                   addr + (nr_pages << PAGE_SHIFT) > vma->vm_end ||
+                   !enforce_singleshot_mapping(vma, addr, nr_pages)) {
+                       up_write(&mm->mmap_sem);
+                       goto mmapbatch_out;
+               }
+
                i = 0;
                ret = 0;
                list_for_each(l, &pagelist) {
@@ -331,11 +358,6 @@ static int privcmd_mmap(struct file * fi
 
        return 0;
 }
-
-static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
-{
-       return (xchg(&vma->vm_private_data, (void *)1) == NULL);
-}
 #endif
 
 static const struct file_operations privcmd_file_ops = {

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.