]> xenbits.xensource.com Git - people/royger/linux-2.6.18-xen.git/commitdiff
privcmd: Handle paged-out areas of foreign guest memory in mmap().
authorKeir Fraser <keir.fraser@citrix.com>
Thu, 17 Dec 2009 06:37:49 +0000 (06:37 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Thu, 17 Dec 2009 06:37:49 +0000 (06:37 +0000)
Signed-off-by: Grzegorz Milos <Grzegorz.Milos@citrix.com>
drivers/xen/privcmd/privcmd.c

index 845406e463ae4b15f70f81843f3c7630bfba7a15..67346e75ce276a32321a163c6db1129f9606a1a1 100644 (file)
@@ -197,6 +197,7 @@ static long privcmd_ioctl(struct file *file,
                int i;
                LIST_HEAD(pagelist);
                struct list_head *l, *l2;
+               int paged_out = 0;
 
                if (!is_initial_xendomain())
                        return -EPERM;
@@ -236,8 +237,14 @@ static long privcmd_ioctl(struct file *file,
                    (m.addr != vma->vm_start) ||
                    ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
                    !privcmd_enforce_singleshot_mapping(vma)) {
-                       up_write(&mm->mmap_sem);
-                       goto mmapbatch_out;
+                       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;
@@ -246,13 +253,22 @@ static long privcmd_ioctl(struct file *file,
                ret = 0;
                list_for_each(l, &pagelist) {
                        int nr = i + min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
+                       int rc;
+
                        mfn = (unsigned long *)(l + 1);
 
                        while (i<nr) {
-                               if(direct_remap_pfn_range(vma, addr & PAGE_MASK,
-                                                         *mfn, PAGE_SIZE,
-                                                         vma->vm_page_prot, m.dom) < 0) {
-                                       *mfn |= 0xf0000000U;
+                               rc = direct_remap_pfn_range(vma, addr & PAGE_MASK,
+                                                           *mfn, PAGE_SIZE,
+                                                           vma->vm_page_prot, m.dom);
+                               if(rc < 0) {
+                                       if (rc == -ENOENT)
+                                       {
+                                               *mfn |= 0x80000000U;
+                                               paged_out = 1;
+                                       }
+                                       else
+                                               *mfn |= 0xf0000000U;
                                        ret++;
                                }
                                mfn++; i++; addr += PAGE_SIZE;
@@ -263,7 +279,10 @@ static long privcmd_ioctl(struct file *file,
                if (ret > 0) {
                        p = m.arr;
                        i = 0;
-                       ret = 0;
+                       if (paged_out)
+                               ret = -ENOENT;
+                       else
+                               ret = 0;
                        list_for_each(l, &pagelist) {
                                int nr = min(nr_pages - i, MMAPBATCH_NR_PER_PAGE);
                                mfn = (unsigned long *)(l + 1);