# 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
|