diff options
author | Arnd Bergmann <arnd@arndb.de> | 2009-10-22 08:19:27 -0400 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-12-03 02:32:20 -0500 |
commit | 6ff5894cdfe7103083bd15b31002434ccd351039 (patch) | |
tree | 0e958c3b85712e2d1d320f4841e88ef8bdac8ea7 /virt/kvm | |
parent | afbcf7ab8d1bc8c2d04792f6d9e786e0adeb328d (diff) |
KVM: Enable 32bit dirty log pointers on 64bit host
With big endian userspace, we can't quite figure out if a pointer
is 32 bit (shifted >> 32) or 64 bit when we read a 64 bit pointer.
This is what happens with dirty logging. To get the pointer interpreted
correctly, we thus need Arnd's patch to implement a compat layer for
the ioctl:
A better way to do this is to add a separate compat_ioctl() method that
converts this for you.
Based on initial patch from Arnd Bergmann.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'virt/kvm')
-rw-r--r-- | virt/kvm/kvm_main.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index cac69c4415df..bd44fb48ac43 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c | |||
@@ -43,6 +43,7 @@ | |||
43 | #include <linux/swap.h> | 43 | #include <linux/swap.h> |
44 | #include <linux/bitops.h> | 44 | #include <linux/bitops.h> |
45 | #include <linux/spinlock.h> | 45 | #include <linux/spinlock.h> |
46 | #include <linux/compat.h> | ||
46 | 47 | ||
47 | #include <asm/processor.h> | 48 | #include <asm/processor.h> |
48 | #include <asm/io.h> | 49 | #include <asm/io.h> |
@@ -1542,6 +1543,52 @@ out: | |||
1542 | return r; | 1543 | return r; |
1543 | } | 1544 | } |
1544 | 1545 | ||
1546 | #ifdef CONFIG_COMPAT | ||
1547 | struct compat_kvm_dirty_log { | ||
1548 | __u32 slot; | ||
1549 | __u32 padding1; | ||
1550 | union { | ||
1551 | compat_uptr_t dirty_bitmap; /* one bit per page */ | ||
1552 | __u64 padding2; | ||
1553 | }; | ||
1554 | }; | ||
1555 | |||
1556 | static long kvm_vm_compat_ioctl(struct file *filp, | ||
1557 | unsigned int ioctl, unsigned long arg) | ||
1558 | { | ||
1559 | struct kvm *kvm = filp->private_data; | ||
1560 | int r; | ||
1561 | |||
1562 | if (kvm->mm != current->mm) | ||
1563 | return -EIO; | ||
1564 | switch (ioctl) { | ||
1565 | case KVM_GET_DIRTY_LOG: { | ||
1566 | struct compat_kvm_dirty_log compat_log; | ||
1567 | struct kvm_dirty_log log; | ||
1568 | |||
1569 | r = -EFAULT; | ||
1570 | if (copy_from_user(&compat_log, (void __user *)arg, | ||
1571 | sizeof(compat_log))) | ||
1572 | goto out; | ||
1573 | log.slot = compat_log.slot; | ||
1574 | log.padding1 = compat_log.padding1; | ||
1575 | log.padding2 = compat_log.padding2; | ||
1576 | log.dirty_bitmap = compat_ptr(compat_log.dirty_bitmap); | ||
1577 | |||
1578 | r = kvm_vm_ioctl_get_dirty_log(kvm, &log); | ||
1579 | if (r) | ||
1580 | goto out; | ||
1581 | break; | ||
1582 | } | ||
1583 | default: | ||
1584 | r = kvm_vm_ioctl(filp, ioctl, arg); | ||
1585 | } | ||
1586 | |||
1587 | out: | ||
1588 | return r; | ||
1589 | } | ||
1590 | #endif | ||
1591 | |||
1545 | static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | 1592 | static int kvm_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) |
1546 | { | 1593 | { |
1547 | struct page *page[1]; | 1594 | struct page *page[1]; |
@@ -1576,7 +1623,9 @@ static int kvm_vm_mmap(struct file *file, struct vm_area_struct *vma) | |||
1576 | static struct file_operations kvm_vm_fops = { | 1623 | static struct file_operations kvm_vm_fops = { |
1577 | .release = kvm_vm_release, | 1624 | .release = kvm_vm_release, |
1578 | .unlocked_ioctl = kvm_vm_ioctl, | 1625 | .unlocked_ioctl = kvm_vm_ioctl, |
1579 | .compat_ioctl = kvm_vm_ioctl, | 1626 | #ifdef CONFIG_COMPAT |
1627 | .compat_ioctl = kvm_vm_compat_ioctl, | ||
1628 | #endif | ||
1580 | .mmap = kvm_vm_mmap, | 1629 | .mmap = kvm_vm_mmap, |
1581 | }; | 1630 | }; |
1582 | 1631 | ||