mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 22:51:35 +00:00
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>
This commit is contained in:
parent
cd9ae5fe47
commit
f848a5a8dc
@ -2644,6 +2644,7 @@ int kvm_dev_ioctl_check_extension(long ext)
|
||||
case KVM_CAP_IRQ_INJECT_STATUS:
|
||||
case KVM_CAP_IRQFD:
|
||||
case KVM_CAP_IOEVENTFD:
|
||||
case KVM_CAP_IOEVENTFD_NO_LENGTH:
|
||||
case KVM_CAP_PIT2:
|
||||
case KVM_CAP_PIT_STATE2:
|
||||
case KVM_CAP_SET_IDENTITY_MAP_ADDR:
|
||||
|
@ -529,7 +529,7 @@ enum {
|
||||
struct kvm_ioeventfd {
|
||||
__u64 datamatch;
|
||||
__u64 addr; /* legal pio/mmio address */
|
||||
__u32 len; /* 1, 2, 4, or 8 bytes */
|
||||
__u32 len; /* 1, 2, 4, or 8 bytes; or 0 to ignore length */
|
||||
__s32 fd;
|
||||
__u32 flags;
|
||||
__u8 pad[36];
|
||||
@ -743,6 +743,7 @@ struct kvm_ppc_smmu_info {
|
||||
#define KVM_CAP_IOAPIC_POLARITY_IGNORED 97
|
||||
#define KVM_CAP_ENABLE_CAP_VM 98
|
||||
#define KVM_CAP_S390_IRQCHIP 99
|
||||
#define KVM_CAP_IOEVENTFD_NO_LENGTH 100
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
@ -600,7 +600,15 @@ ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val)
|
||||
{
|
||||
u64 _val;
|
||||
|
||||
if (!(addr == p->addr && len == p->length))
|
||||
if (addr != p->addr)
|
||||
/* address must be precise for a hit */
|
||||
return false;
|
||||
|
||||
if (!p->length)
|
||||
/* length = 0 means only look at the address, so always a hit */
|
||||
return true;
|
||||
|
||||
if (len != p->length)
|
||||
/* address-range must be precise for a hit */
|
||||
return false;
|
||||
|
||||
@ -671,9 +679,11 @@ ioeventfd_check_collision(struct kvm *kvm, struct _ioeventfd *p)
|
||||
|
||||
list_for_each_entry(_p, &kvm->ioeventfds, list)
|
||||
if (_p->bus_idx == p->bus_idx &&
|
||||
_p->addr == p->addr && _p->length == p->length &&
|
||||
(_p->wildcard || p->wildcard ||
|
||||
_p->datamatch == p->datamatch))
|
||||
_p->addr == p->addr &&
|
||||
(!_p->length || !p->length ||
|
||||
(_p->length == p->length &&
|
||||
(_p->wildcard || p->wildcard ||
|
||||
_p->datamatch == p->datamatch))))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@ -697,8 +707,9 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
|
||||
int ret;
|
||||
|
||||
bus_idx = ioeventfd_bus_from_flags(args->flags);
|
||||
/* must be natural-word sized */
|
||||
/* must be natural-word sized, or 0 to ignore length */
|
||||
switch (args->len) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
@ -716,6 +727,12 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)
|
||||
if (args->flags & ~KVM_IOEVENTFD_VALID_FLAG_MASK)
|
||||
return -EINVAL;
|
||||
|
||||
/* ioeventfd with no length can't be combined with DATAMATCH */
|
||||
if (!args->len &&
|
||||
args->flags & (KVM_IOEVENTFD_FLAG_PIO |
|
||||
KVM_IOEVENTFD_FLAG_DATAMATCH))
|
||||
return -EINVAL;
|
||||
|
||||
eventfd = eventfd_ctx_fdget(args->fd);
|
||||
if (IS_ERR(eventfd))
|
||||
return PTR_ERR(eventfd);
|
||||
|
Loading…
Reference in New Issue
Block a user