diff options
| author | Michael S. Tsirkin <mst@redhat.com> | 2014-03-31 14:50:38 -0400 |
|---|---|---|
| committer | Marcelo Tosatti <mtosatti@redhat.com> | 2014-04-17 13:01:42 -0400 |
| commit | f848a5a8dcb655553423f77cc98909a04e64173d (patch) | |
| tree | 02e212c8eeeb52e74876408bb5e7e5d2febae379 | |
| parent | cd9ae5fe47dfb9820976c3c38c70f4b07a5a1c36 (diff) | |
KVM: support any-length wildcard ioeventfd
It is sometimes benefitial to ignore IO size, and only match on address.
In hindsight this would have been a better default than matching length
when KVM_IOEVENTFD_FLAG_DATAMATCH is not set, In particular, this kind
of access can be optimized on VMX: there no need to do page lookups.
This can currently be done with many ioeventfds but in a suboptimal way.
However we can't change kernel/userspace ABI without risk of breaking
some applications.
Use len = 0 to mean "ignore length for matching" in a more optimal way.
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
| -rw-r--r-- | arch/x86/kvm/x86.c | 1 | ||||
| -rw-r--r-- | include/uapi/linux/kvm.h | 3 | ||||
| -rw-r--r-- | virt/kvm/eventfd.c | 27 |
3 files changed, 25 insertions, 6 deletions
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 8b8fc0b792ba..bc4aaf68190c 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
| @@ -2644,6 +2644,7 @@ int kvm_dev_ioctl_check_extension(long ext) | |||
| 2644 | case KVM_CAP_IRQ_INJECT_STATUS: | 2644 | case KVM_CAP_IRQ_INJECT_STATUS: |
| 2645 | case KVM_CAP_IRQFD: | 2645 | case KVM_CAP_IRQFD: |
| 2646 | case KVM_CAP_IOEVENTFD: | 2646 | case KVM_CAP_IOEVENTFD: |
| 2647 | case KVM_CAP_IOEVENTFD_NO_LENGTH: | ||
| 2647 | case KVM_CAP_PIT2: | 2648 | case KVM_CAP_PIT2: |
| 2648 | case KVM_CAP_PIT_STATE2: | 2649 | case KVM_CAP_PIT_STATE2: |
| 2649 | case KVM_CAP_SET_IDENTITY_MAP_ADDR: | 2650 | case KVM_CAP_SET_IDENTITY_MAP_ADDR: |
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index a8f4ee5d2e82..39098a61f41c 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h | |||
| @@ -529,7 +529,7 @@ enum { | |||
| 529 | struct kvm_ioeventfd { | 529 | struct kvm_ioeventfd { |
| 530 | __u64 datamatch; | 530 | __u64 datamatch; |
| 531 | __u64 addr; /* legal pio/mmio address */ | 531 | __u64 addr; /* legal pio/mmio address */ |
| 532 | __u32 len; /* 1, 2, 4, or 8 bytes */ | 532 | __u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */ |
| 533 | __s32 fd; | 533 | __s32 fd; |
| 534 | __u32 flags; | 534 | __u32 flags; |
| 535 | __u8 pad[36]; | 535 | __u8 pad[36]; |
| @@ -743,6 +743,7 @@ struct kvm_ppc_smmu_info { | |||
| 743 | #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97 | 743 | #define KVM_CAP_IOAPIC_POLARITY_IGNORED 97 |
| 744 | #define KVM_CAP_ENABLE_CAP_VM 98 | 744 | #define KVM_CAP_ENABLE_CAP_VM 98 |
| 745 | #define KVM_CAP_S390_IRQCHIP 99 | 745 | #define KVM_CAP_S390_IRQCHIP 99 |
| 746 | #define KVM_CAP_IOEVENTFD_NO_LENGTH 100 | ||
| 746 | 747 | ||
| 747 | #ifdef KVM_CAP_IRQ_ROUTING | 748 | #ifdef KVM_CAP_IRQ_ROUTING |
| 748 | 749 | ||
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 29c2a04e036e..2721996bb9c2 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c | |||
| @@ -600,7 +600,15 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val) | |||
| 600 | { | 600 | { |
| 601 | u64 _val; | 601 | u64 _val; |
| 602 | 602 | ||
| 603 | if (!(addr == p->addr && len == p->length)) | 603 | if (addr != p->addr) |
| 604 | /* address must be precise for a hit */ | ||
| 605 | return false; | ||
| 606 | |||
| 607 | if (!p->length) | ||
| 608 | /* length = 0 means only look at the address, so always a hit */ | ||
| 609 | return true; | ||
| 610 | |||
| 611 | if (len != p->length) | ||
| 604 | /* address-range must be precise for a hit */ | 612 | /* address-range must be precise for a hit */ |
| 605 | return false; | 613 | return false; |
| 606 | 614 | ||
| @@ -671,9 +679,11 @@ ioeventfd_check_collision(struct kvm *kvm, struct _ioeventfd *p) | |||
| 671 | 679 | ||
| 672 | list_for_each_entry(_p, &kvm->ioeventfds, list) | 680 | list_for_each_entry(_p, &kvm->ioeventfds, list) |
| 673 | if (_p->bus_idx == p->bus_idx && | 681 | if (_p->bus_idx == p->bus_idx && |
| 674 | _p->addr == p->addr && _p->length == p->length && | 682 | _p->addr == p->addr && |
| 675 | (_p->wildcard || p->wildcard || | 683 | (!_p->length || !p->length || |
| 676 | _p->datamatch == p->datamatch)) | 684 | (_p->length == p->length && |
| 685 | (_p->wildcard || p->wildcard || | ||
| 686 | _p->datamatch == p->datamatch)))) | ||
| 677 | return true; | 687 | return true; |
| 678 | 688 | ||
| 679 | return false; | 689 | return false; |
| @@ -697,8 +707,9 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) | |||
| 697 | int ret; | 707 | int ret; |
| 698 | 708 | ||
| 699 | bus_idx = ioeventfd_bus_from_flags(args->flags); | 709 | bus_idx = ioeventfd_bus_from_flags(args->flags); |
| 700 | /* must be natural-word sized */ | 710 | /* must be natural-word sized, or 0 to ignore length */ |
| 701 | switch (args->len) { | 711 | switch (args->len) { |
| 712 | case 0: | ||
| 702 | case 1: | 713 | case 1: |
| 703 | case 2: | 714 | case 2: |
| 704 | case 4: | 715 | case 4: |
| @@ -716,6 +727,12 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) | |||
| 716 | if (args->flags & ~KVM_IOEVENTFD_VALID_FLAG_MASK) | 727 | if (args->flags & ~KVM_IOEVENTFD_VALID_FLAG_MASK) |
| 717 | return -EINVAL; | 728 | return -EINVAL; |
| 718 | 729 | ||
| 730 | /* ioeventfd with no length can't be combined with DATAMATCH */ | ||
| 731 | if (!args->len && | ||
| 732 | args->flags & (KVM_IOEVENTFD_FLAG_PIO | | ||
| 733 | KVM_IOEVENTFD_FLAG_DATAMATCH)) | ||
| 734 | return -EINVAL; | ||
| 735 | |||
| 719 | eventfd = eventfd_ctx_fdget(args->fd); | 736 | eventfd = eventfd_ctx_fdget(args->fd); |
| 720 | if (IS_ERR(eventfd)) | 737 | if (IS_ERR(eventfd)) |
| 721 | return PTR_ERR(eventfd); | 738 | return PTR_ERR(eventfd); |
