Skip to contentSkip to conversation

iosignalfd

PATCH Superseded Gregory Haskins 3 participants 23 messages Jul 6, 2009 – Jul 8, 2009

Subsystems (3)

v9 of 10 Superseded Latest is v10 →

lore
Share & tools
lore
#0 lore raw

v9 cover iosignalfd

(Applies to kvm.git/master:c5b13264e)

This is v9 of the series. For more details, please see the header to patch 2/2.

This series has been tested against the kvm-eventfd unit test, and appears to be functioning properly. You can download this test here:

ftp://ftp.novell.com/dev/ghaskins/kvm-eventfd.tar.bz2

(Note: unit test has been updated to accomodate new feature-set)

Please consider for inclusion to kvm.git

[
Changelog:

v9:
*) Rebased onto Michael's new iodev locking scheme *) Removed group+item nesting in favor of using iodev facility *) Removed iodev-limit patch since we no longer create
our own devices. The limit feature itself may be useful but it is now out of scope from iosignalfd and thus should be addressed separately.
*) Rebased to kvm.git/master:c5b13264e

v8:
*) Addressed Avi's review comments:
*) Simplified the unregister_dev logic in patch 1/3 *) Implemented a per-vm io-device limit (patch 2/3) *) Removed spurious whitespace hunk
*) changed the data-match from a void* to a u64 *) check group-length violations before wildcarding

v7:
*) Implemented a resource limit (CONFIG_KVM_MAX_IOSIGNALFD_ITEMS)
to limit malicious/broken userspace from consuming arbitrary kernel memory.
*) Rebased to kvm.git/master:c27b64a0, which already includes
Marcelo's irq-lock rework.

v6:
*) Removed "FIXME?" comment on choice over RCU vs SRCU after
discussion/numbers from Paul. I think RCU is fine to use for now based on the conversation. We can always convert it later if need be.
*) Fixed the "group" free path to eliminate an RCU related race *) Fixed a memory/eventfd leak on shutdown for any iosignalfd's
which were still active at the time the guest shuts down.
*) Beefed up comments
*) Rebased to kvm.git/master:0281e88f + irq locking rework and
verified that kvm-eventfd unit test still passes.

v5:
*) Removed "cookie" field, which was a misunderstanding on my
part on what Avi wanted for a data-match feature
*) Added a new "trigger" data-match feature which I think is
much closer to what we need.
*) We retain the dev_count field in the io_bus infrastructure
and instead back-fill the array on removal.
*) Various minor cleanups
*) Rebased to kvm.git/master:25deed73

v4:
*) Fixed a bug in the original 2/4 where the PIT failure case
would potentially leave the io_bus components registered.
*) Condensed the v3 2/4 and 3/4 into one patch (2/2) since
the patches became interdependent with the fix described above
*) Rebased to kvm.git/master:74dfca0a

v3:
*) fixed patch 2/4 to handle error cases instead of BUG_ON *) implemented same HAVE_EVENTFD protection mechanism as
irqfd to prevent compilation errors on unsupported arches
*) completed testing
*) rebased to kvm.git/master:7391a6d5

v2:
*) added optional data-matching capability (via cookie field) *) changed name from iofd to iosignalfd
*) added io_bus unregister function
*) implemented deassign feature

v1:
*) original release (integrated into irqfd v7 series as "iofd")
]

---

Gregory Haskins (2):
KVM: add iosignalfd support
KVM: make io_bus interface more robust

 arch/x86/kvm/i8254.c      |   22 +++-
 arch/x86/kvm/i8259.c      |    9 +
 arch/x86/kvm/x86.c        |    1 
 include/linux/kvm.h       |   15 ++
 include/linux/kvm_host.h  |   20 ++-
 virt/kvm/coalesced_mmio.c |    8 +
 virt/kvm/eventfd.c        |  280 +++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/ioapic.c         |    8 +
 virt/kvm/kvm_main.c       |   52 +++++++-
 9 files changed, 396 insertions(+), 19 deletions(-)
Signature · 1 line
Signature
#1 lore raw

PATCH v9 1/2 KVM: make io_bus interface more robust

Today kvm_io_bus_regsiter_dev() returns void and will internally BUG_ON if it fails. We want to create dynamic MMIO/PIO entries driven from userspace later in the series, so we need to enhance the code to be more robust with the following changes:

1) Add a return value to the registration function
2) Fix up all the callsites to check the return code, handle any failures, and percolate the error up to the caller.
3) Add an unregister function that collapses holes in the array

---

 arch/x86/kvm/i8254.c      |   22 ++++++++++++++++++++--
 arch/x86/kvm/i8259.c      |    9 ++++++++-
 include/linux/kvm_host.h  |   10 +++++++---
 virt/kvm/coalesced_mmio.c |    8 ++++++--
 virt/kvm/ioapic.c         |    8 ++++++--
 virt/kvm/kvm_main.c       |   41 ++++++++++++++++++++++++++++++++++++-----
 6 files changed, 83 insertions(+), 15 deletions(-)
arch/x86/kvm/i8254.c +20 -2
index 8c3ac30..298312d 100644
@@ -591,6 +591,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 {
 	struct kvm_pit *pit;
 	struct kvm_kpit_state *pit_state;
+	int ret;
 
 	pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
 	if (!pit)
@@ -625,14 +626,31 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 	kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
 
 	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
-	__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+	ret = __kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+	if (ret < 0)
+		goto fail;
 
 	if (flags & KVM_PIT_SPEAKER_DUMMY) {
 		kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
-		__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev);
+		ret = __kvm_io_bus_register_dev(&kvm->pio_bus,
+						&pit->speaker_dev);
+		if (ret < 0)
+			goto fail;
 	}
 
 	return pit;
+
+fail:
+	if (flags & KVM_PIT_SPEAKER_DUMMY)
+		__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->speaker_dev);
+
+	__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->dev);
+
+	if (pit->irq_source_id >= 0)
+		kvm_free_irq_source_id(kvm, pit->irq_source_id);
+
+	kfree(pit);
+	return NULL;
 }
 
 void kvm_free_pit(struct kvm *kvm)
arch/x86/kvm/i8259.c +8 -1
index 1d1bb75..670e426 100644
@@ -536,6 +536,8 @@ static const struct kvm_io_device_ops picdev_ops = {
 struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 {
 	struct kvm_pic *s;
+	int ret;
+
 	s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
 	if (!s)
 		return NULL;
@@ -552,6 +554,11 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 	 * Initialize PIO device
 	 */
 	kvm_iodevice_init(&s->dev, &picdev_ops);
-	kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	if (ret < 0) {
+		kfree(s);
+		return NULL;
+	}
+
 	return s;
 }
include/linux/kvm_host.h +7 -3
index 8e04a34..306bc67 100644
@@ -64,10 +64,14 @@ int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, int len,
 		     const void *val);
 int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len,
 		    void *val);
-void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+			       struct kvm_io_device *dev);
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+			    struct kvm_io_device *dev);
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+				 struct kvm_io_device *dev);
+void kvm_io_bus_unregister_dev(struct kvm *kvm, struct kvm_io_bus *bus,
 			       struct kvm_io_device *dev);
-void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
-			     struct kvm_io_device *dev);
 
 struct kvm_vcpu {
 	struct kvm *kvm;
virt/kvm/coalesced_mmio.c +6 -2
index 0352f81..04d69cd 100644
@@ -92,6 +92,7 @@ static const struct kvm_io_device_ops coalesced_mmio_ops = {
 int kvm_coalesced_mmio_init(struct kvm *kvm)
 {
 	struct kvm_coalesced_mmio_dev *dev;
+	int ret;
 
 	dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
 	if (!dev)
@@ -100,9 +101,12 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)
 	kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
 	dev->kvm = kvm;
 	kvm->coalesced_mmio_dev = dev;
-	kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
 
-	return 0;
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
+	if (ret < 0)
+		kfree(dev);
+
+	return ret;
 }
 
 int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
virt/kvm/ioapic.c +6 -2
index 92496ff..048836d 100644
@@ -340,6 +340,7 @@ static const struct kvm_io_device_ops ioapic_mmio_ops = {
 int kvm_ioapic_init(struct kvm *kvm)
 {
 	struct kvm_ioapic *ioapic;
+	int ret;
 
 	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
 	if (!ioapic)
@@ -348,7 +349,10 @@ int kvm_ioapic_init(struct kvm *kvm)
 	kvm_ioapic_reset(ioapic);
 	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
 	ioapic->kvm = kvm;
-	kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
-	return 0;
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
+	if (ret < 0)
+		kfree(ioapic);
+
+	return ret;
 }
 
virt/kvm/kvm_main.c +36 -5

57 lines not on this page · raw message

#2 lore raw

Re: [KVM PATCH v9 1/2] KVM: make io_bus interface more robust

Looks good to me. One thing that's kind of ugly is the cleanup in i8254, see below. And a couple of other style comments.

Quoted 48 lines · Gregory Haskins

Today kvm_io_bus_regsiter_dev() returns void and will internally BUG_ON if it fails. We want to create dynamic MMIO/PIO entries driven from userspace later in the series, so we need to enhance the code to be more robust with the following changes:

1) Add a return value to the registration function
2) Fix up all the callsites to check the return code, handle any failures, and percolate the error up to the caller.
3) Add an unregister function that collapses holes in the array

---

 arch/x86/kvm/i8254.c      |   22 ++++++++++++++++++++--
 arch/x86/kvm/i8259.c      |    9 ++++++++-
 include/linux/kvm_host.h  |   10 +++++++---
 virt/kvm/coalesced_mmio.c |    8 ++++++--
 virt/kvm/ioapic.c         |    8 ++++++--
 virt/kvm/kvm_main.c       |   41 ++++++++++++++++++++++++++++++++++++-----
 6 files changed, 83 insertions(+), 15 deletions(-)
arch/x86/kvm/i8254.c +7 -2
index 8c3ac30..298312d 100644
@@ -591,6 +591,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 {
 	struct kvm_pit *pit;
 	struct kvm_kpit_state *pit_state;
+	int ret;
 
 	pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
 	if (!pit)
@@ -625,14 +626,31 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 	kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
 
 	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
-	__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+	ret = __kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+	if (ret < 0)
+		goto fail;
 
 	if (flags & KVM_PIT_SPEAKER_DUMMY) {
 		kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
-		__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev);
+		ret = __kvm_io_bus_register_dev(&kvm->pio_bus,
+						&pit->speaker_dev);
+		if (ret < 0)

arch/x86/kvm/i8254.c struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) · line 647

Quoted 10 lines
arch/x86/kvm/i8254.c +7 -0
+			goto fail;
 	}
 
 	return pit;
+
+fail:
+	if (flags & KVM_PIT_SPEAKER_DUMMY)
+		__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->speaker_dev);
+
+	__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->dev);

The above works because we scan the whole array; so it's safe to call unregister on a device that we didn't register, and even on a device we didn't init. But IMO it's cleaner not to assume this and do cleanup properly. No?

Quoted 23 lines
arch/x86/kvm/i8254.c +6 -0
+
+	if (pit->irq_source_id >= 0)
+		kvm_free_irq_source_id(kvm, pit->irq_source_id);
+
+	kfree(pit);
+	return NULL;
 }
 
 void kvm_free_pit(struct kvm *kvm)
arch/x86/kvm/i8259.c +2 -0
index 1d1bb75..670e426 100644
@@ -536,6 +536,8 @@ static const struct kvm_io_device_ops picdev_ops = {
 struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 {
 	struct kvm_pic *s;
+	int ret;
+
 	s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
 	if (!s)
 		return NULL;

arch/x86/kvm/i8259.c struct kvm_pic *kvm_create_pic(struct kvm *kvm) · line 558

Quoted 6 lines
arch/x86/kvm/i8259.c +2 -1
@@ -552,6 +554,11 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 	 * Initialize PIO device
 	 */
 	kvm_iodevice_init(&s->dev, &picdev_ops);
-	kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	if (ret < 0) {

I thought the function returns 0 on success?
If so can we just if (ret) all over?

arch/x86/kvm/i8259.c struct kvm_pic *kvm_create_pic(struct kvm *kvm) · line 562

Quoted 4 lines
arch/x86/kvm/i8259.c +4 -0
+		kfree(s);
+		return NULL;
+	}
+

kill empty line

Quoted 37 lines
arch/x86/kvm/i8259.c +0 -0
 	return s;
 }
include/linux/kvm_host.h +7 -3
index 8e04a34..306bc67 100644
@@ -64,10 +64,14 @@ int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, int len,
 		     const void *val);
 int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len,
 		    void *val);
-void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+			       struct kvm_io_device *dev);
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+			    struct kvm_io_device *dev);
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+				 struct kvm_io_device *dev);
+void kvm_io_bus_unregister_dev(struct kvm *kvm, struct kvm_io_bus *bus,
 			       struct kvm_io_device *dev);
-void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
-			     struct kvm_io_device *dev);
 
 struct kvm_vcpu {
 	struct kvm *kvm;
virt/kvm/coalesced_mmio.c +1 -0
index 0352f81..04d69cd 100644
@@ -92,6 +92,7 @@ static const struct kvm_io_device_ops coalesced_mmio_ops = {
 int kvm_coalesced_mmio_init(struct kvm *kvm)
 {
 	struct kvm_coalesced_mmio_dev *dev;
+	int ret;
 
 	dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
 	if (!dev)

virt/kvm/coalesced_mmio.c int kvm_coalesced_mmio_init(struct kvm *kvm) · line 108

Quoted 10 lines
virt/kvm/coalesced_mmio.c +4 -2
@@ -100,9 +101,12 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)
 	kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
 	dev->kvm = kvm;
 	kvm->coalesced_mmio_dev = dev;
-	kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
 
-	return 0;
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
+	if (ret < 0)
+		kfree(dev);
+

kill empty line

Quoted 17 lines
virt/kvm/coalesced_mmio.c +1 -0
+	return ret;
 }
 
 int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,
virt/kvm/ioapic.c +1 -0
index 92496ff..048836d 100644
@@ -340,6 +340,7 @@ static const struct kvm_io_device_ops ioapic_mmio_ops = {
 int kvm_ioapic_init(struct kvm *kvm)
 {
 	struct kvm_ioapic *ioapic;
+	int ret;
 
 	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
 	if (!ioapic)

virt/kvm/ioapic.c int kvm_ioapic_init(struct kvm *kvm) · line 354

Quoted 8 lines
virt/kvm/ioapic.c +3 -2
@@ -348,7 +349,10 @@ int kvm_ioapic_init(struct kvm *kvm)
 	kvm_ioapic_reset(ioapic);
 	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
 	ioapic->kvm = kvm;
-	kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
-	return 0;
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
+	if (ret < 0)
+		kfree(ioapic);

kill empty line

Quoted 9 lines
virt/kvm/ioapic.c +2 -0
+
+	return ret;
 }
 
virt/kvm/kvm_main.c +0 -0
index 05b6bc7..11595c7 100644

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2537

Quoted 6 lines
virt/kvm/kvm_main.c +1 -1
@@ -2533,21 +2533,52 @@ int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
 	return -EOPNOTSUPP;
 }
 
-void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
 			     struct kvm_io_device *dev)

Let's document return value?

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2543

Quoted 7 lines
virt/kvm/kvm_main.c +3 -1
 {
+	int ret;
+
 	down_write(&kvm->slots_lock);
-	__kvm_io_bus_register_dev(bus, dev);
+	ret = __kvm_io_bus_register_dev(bus, dev);
 	up_write(&kvm->slots_lock);

kill empty line? this one is kind of iffy

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2552

Quoted 12 lines
virt/kvm/kvm_main.c +5 -3
+
+	return ret;
 }
 
 /* An unlocked version. Caller must have write lock on slots_lock. */
-void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
-			     struct kvm_io_device *dev)
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+			      struct kvm_io_device *dev)
 {
-	BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
+	if (bus->dev_count > (NR_IOBUS_DEVS-1))

as long as we are touching this: (NR_IOBUS_DEVS-1) -> NR_IOBUS_DEVS - 1?

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2555

Quoted 3 lines
virt/kvm/kvm_main.c +1 -0
+		return -ENOSPC;
 
 	bus->devs[bus->dev_count++] = dev;

kill empty line

Quoted 11 lines
virt/kvm/kvm_main.c +11 -0
+
+	return 0;
+}
+
+void kvm_io_bus_unregister_dev(struct kvm *kvm,
+			       struct kvm_io_bus *bus,
+			       struct kvm_io_device *dev)
+{
+	down_write(&kvm->slots_lock);
+	__kvm_io_bus_unregister_dev(bus, dev);
+	up_write(&kvm->slots_lock);

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2576

Quoted 10 lines
virt/kvm/kvm_main.c +10 -0
+}
+
+/* An unlocked version. Caller must have write lock on slots_lock. */
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+				 struct kvm_io_device *dev)
+{
+	int i;
+
+	for (i = 0; i < bus->dev_count; i++) {
+

kill empty line

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2581

Quoted 5 lines
virt/kvm/kvm_main.c +5 -0
+		if (bus->devs[i] == dev) {
+			bus->devs[i] = bus->devs[--bus->dev_count];
+			break;
+		}
+	}

no {} around single statement

Quoted 3 lines
virt/kvm/kvm_main.c +0 -0
 }
 
 static struct notifier_block kvm_cpu_notifier = {
#3 lore raw

Re: [KVM PATCH v9 1/2] KVM: make io_bus interface more robust

Quoted 56 lines · Michael S. Tsirkin

Looks good to me. One thing that's kind of ugly is the cleanup in i8254, see below. And a couple of other style comments.

Quoted 51 lines · Gregory Haskins

Today kvm_io_bus_regsiter_dev() returns void and will internally BUG_ON if it fails. We want to create dynamic MMIO/PIO entries driven from userspace later in the series, so we need to enhance the code to be more robust with the following changes:

1) Add a return value to the registration function
2) Fix up all the callsites to check the return code, handle any failures, and percolate the error up to the caller.
3) Add an unregister function that collapses holes in the array

---

 arch/x86/kvm/i8254.c      |   22 ++++++++++++++++++++--
 arch/x86/kvm/i8259.c      |    9 ++++++++-
 include/linux/kvm_host.h  |   10 +++++++---
 virt/kvm/coalesced_mmio.c |    8 ++++++--
 virt/kvm/ioapic.c         |    8 ++++++--
 virt/kvm/kvm_main.c       |   41 ++++++++++++++++++++++++++++++++++++-----
 6 files changed, 83 insertions(+), 15 deletions(-)
arch/x86/kvm/i8254.c +8 -2
index 8c3ac30..298312d 100644
@@ -591,6 +591,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 {
 	struct kvm_pit *pit;
 	struct kvm_kpit_state *pit_state;
+	int ret;
 
 	pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
 	if (!pit)
@@ -625,14 +626,31 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
 	kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
 
 	kvm_iodevice_init(&pit->dev, &pit_dev_ops);
-	__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+	ret = __kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
+	if (ret < 0)
+		goto fail;
 
 	if (flags & KVM_PIT_SPEAKER_DUMMY) {
 		kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
-		__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev);
+		ret = __kvm_io_bus_register_dev(&kvm->pio_bus,
+						&pit->speaker_dev);
+		if (ret < 0)
+			goto fail;
 	}
 
Quoted 14 lines

arch/x86/kvm/i8254.c struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags) · line 655

Quoted 8 lines
arch/x86/kvm/i8254.c +6 -0
 	return pit;
+
+fail:
+	if (flags & KVM_PIT_SPEAKER_DUMMY)
+		__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->speaker_dev);
+
+	__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->dev);
 

The above works because we scan the whole array; so it's safe to call unregister on a device that we didn't register, and even on a device we didn't init. But IMO it's cleaner not to assume this and do cleanup properly. No?

Ack (this was a left-over from when the code was structured differently)

Quoted 9 lines
Quoted 9 lines
arch/x86/kvm/i8254.c +6 -0
+
+	if (pit->irq_source_id >= 0)
+		kvm_free_irq_source_id(kvm, pit->irq_source_id);
+
+	kfree(pit);
+	return NULL;
 }
 
Quoted 12 lines

arch/x86/kvm/i8259.c static const struct kvm_io_device_ops picdev_ops = { · line 541

Quoted 12 lines

void kvm_free_pit(struct kvm *kvm)

arch/x86/kvm/i8259.c +2 -0
index 1d1bb75..670e426 100644
@@ -536,6 +536,8 @@ static const struct kvm_io_device_ops picdev_ops = {
 struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 {
 	struct kvm_pic *s;
+	int ret;
+
 

[A]

Quoted 6 lines
Quoted 6 lines
arch/x86/kvm/i8259.c +0 -0
 	s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
 	if (!s)
arch/x86/kvm/i8259.c +0 -0
 		return NULL;
@@ -552,6 +554,11 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 	 * Initialize PIO device
 	 */
Quoted 10 lines

arch/x86/kvm/i8259.c struct kvm_pic *kvm_create_pic(struct kvm *kvm)

Quoted 5 lines
arch/x86/kvm/i8259.c +2 -1
 	kvm_iodevice_init(&s->dev, &picdev_ops);
-	kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	if (ret < 0) {
 

I thought the function returns 0 on success?
If so can we just if (ret) all over?

I guess, but what does that churn buy us?

Quoted 8 lines

arch/x86/kvm/i8259.c struct kvm_pic *kvm_create_pic(struct kvm *kvm)

Quoted 5 lines
arch/x86/kvm/i8259.c +4 -0
+		kfree(s);
+		return NULL;
+	}
+
 

kill empty line

Are they docking your pay for every whitespace that goes into KVM or something ;)

These patches pass checkpatch.pl and I happen to like the extra whitespace for readability. I agree that a random isolated whitespace hunk, or double whitespace in a row are probably inadvertent and should be pointed out. But these little one liners in the middle of code I generally do on purpose (for instance, [A]). I suppose its personal preference either way, so I guess unless Avi objects lets just each have our own style in that regard.

Quoted 43 lines
Quoted 43 lines
arch/x86/kvm/i8259.c +0 -0
 	return s;
 }
include/linux/kvm_host.h +7 -3
index 8e04a34..306bc67 100644
@@ -64,10 +64,14 @@ int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, int len,
 		     const void *val);
 int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len,
 		    void *val);
-void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+			       struct kvm_io_device *dev);
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+			    struct kvm_io_device *dev);
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+				 struct kvm_io_device *dev);
+void kvm_io_bus_unregister_dev(struct kvm *kvm, struct kvm_io_bus *bus,
 			       struct kvm_io_device *dev);
-void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
-			     struct kvm_io_device *dev);
 
 struct kvm_vcpu {
 	struct kvm *kvm;
virt/kvm/coalesced_mmio.c +1 -1
index 0352f81..04d69cd 100644
@@ -92,6 +92,7 @@ static const struct kvm_io_device_ops coalesced_mmio_ops = {
 int kvm_coalesced_mmio_init(struct kvm *kvm)
 {
 	struct kvm_coalesced_mmio_dev *dev;
+	int ret;
 
 	dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
 	if (!dev)
@@ -100,9 +101,12 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)
 	kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
 	dev->kvm = kvm;
 	kvm->coalesced_mmio_dev = dev;
-	kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
 
Quoted 2 lines

virt/kvm/coalesced_mmio.c int kvm_coalesced_mmio_init(struct kvm *kvm) · line 105

Quoted 2 lines
virt/kvm/coalesced_mmio.c +0 -1
-	return 0;
 

[B]

Quoted 8 lines

virt/kvm/coalesced_mmio.c int kvm_coalesced_mmio_init(struct kvm *kvm) · line 111

Quoted 5 lines
virt/kvm/coalesced_mmio.c +4 -0
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
+	if (ret < 0)
+		kfree(dev);
+
 

kill empty line

Why do you object here especially when there is precedence with something like the space before the return with [B]? I think big mono-blocks of code are ugly and harder to read, personally.

Quoted 15 lines
Quoted 15 lines
virt/kvm/coalesced_mmio.c +1 -0
+	return ret;
 }

int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,

virt/kvm/ioapic.c +1 -0
index 92496ff..048836d 100644
@@ -340,6 +340,7 @@ static const struct kvm_io_device_ops ioapic_mmio_ops = {
 int kvm_ioapic_init(struct kvm *kvm)
 {
 	struct kvm_ioapic *ioapic;
+	int ret;
 
Quoted 15 lines

virt/kvm/ioapic.c int kvm_ioapic_init(struct kvm *kvm) · line 355

Quoted 12 lines
virt/kvm/ioapic.c +3 -2
 	ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
 	if (!ioapic)
@@ -348,7 +349,10 @@ int kvm_ioapic_init(struct kvm *kvm)
 	kvm_ioapic_reset(ioapic);
 	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
 	ioapic->kvm = kvm;
-	kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
-	return 0;
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
+	if (ret < 0)
+		kfree(ioapic);
 

kill empty line

Ditto for all of these.

Quoted 13 lines
Quoted 13 lines
virt/kvm/ioapic.c +2 -0
+
+	return ret;
 }
virt/kvm/kvm_main.c +0 -0
index 05b6bc7..11595c7 100644
@@ -2533,21 +2533,52 @@ int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
 	return -EOPNOTSUPP;
 }
 
Quoted 7 lines

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2547

Quoted 4 lines
virt/kvm/kvm_main.c +1 -1
-void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
+int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
 			     struct kvm_io_device *dev)
 

Let's document return value?

Ok

Quoted 79 lines

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2547

Quoted 9 lines
virt/kvm/kvm_main.c +3 -1
 {
+	int ret;
+
 	down_write(&kvm->slots_lock);
-	__kvm_io_bus_register_dev(bus, dev);
+	ret = __kvm_io_bus_register_dev(bus, dev);
 	up_write(&kvm->slots_lock);
 

kill empty line? this one is kind of iffy

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2554

Quoted 13 lines
virt/kvm/kvm_main.c +5 -3
+
+	return ret;
 }
 
 /* An unlocked version. Caller must have write lock on slots_lock. */
-void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
-			     struct kvm_io_device *dev)
+int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
+			      struct kvm_io_device *dev)
 {
-	BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
+	if (bus->dev_count > (NR_IOBUS_DEVS-1))
 

as long as we are touching this: (NR_IOBUS_DEVS-1) -> NR_IOBUS_DEVS - 1?

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2555

Quoted 4 lines
virt/kvm/kvm_main.c +1 -0
+		return -ENOSPC;
 
 	bus->devs[bus->dev_count++] = dev;

kill empty line

Quoted 12 lines
virt/kvm/kvm_main.c +11 -0
+
+	return 0;
+}
+
+void kvm_io_bus_unregister_dev(struct kvm *kvm,
+			       struct kvm_io_bus *bus,
+			       struct kvm_io_device *dev)
+{
+	down_write(&kvm->slots_lock);
+	__kvm_io_bus_unregister_dev(bus, dev);
+	up_write(&kvm->slots_lock);

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2576

Quoted 10 lines
virt/kvm/kvm_main.c +10 -0
+}
+
+/* An unlocked version. Caller must have write lock on slots_lock. */
+void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
+				 struct kvm_io_device *dev)
+{
+	int i;
+
+	for (i = 0; i < bus->dev_count; i++) {
+

kill empty line

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2581

Quoted 6 lines
virt/kvm/kvm_main.c +5 -0
+		if (bus->devs[i] == dev) {
+			bus->devs[i] = bus->devs[--bus->dev_count];
+			break;
+		}
+	}

no {} around single statement

Quoted 4 lines

}

static struct notifier_block kvm_cpu_notifier = {

#4 lore raw

Re: [KVM PATCH v9 1/2] KVM: make io_bus interface more robust

Quoted 5 lines · Gregory Haskins

These patches pass checkpatch.pl and I happen to like the extra whitespace for readability. I agree that a random isolated whitespace hunk, or double whitespace in a row are probably inadvertent and should be pointed out. But these little one liners in the middle of code I generally do on purpose (for instance, [A]).

Where it's on purpose, it's on purpose. I am just trying to convey a rather obvious point that each line of code should have a purpose in life, and that includes empty lines :)

Quoted 2 lines

I suppose its personal preference either way, so I guess unless Avi objects lets just each have our own style in that regard.

I think Avi already said we don't need to standardize everything. I hope at least some of the comments were helpful.

Quoted 14 lines
Quoted 13 lines

arch/x86/kvm/i8259.c struct kvm_pic *kvm_create_pic(struct kvm *kvm) · line 559

Quoted 8 lines
arch/x86/kvm/i8259.c +2 -1
@@ -552,6 +554,11 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
 	 * Initialize PIO device
 	 */
 	kvm_iodevice_init(&s->dev, &picdev_ops);
-	kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
+	if (ret < 0) {
 

I thought the function returns 0 on success?
If so can we just if (ret) all over?

Quoted 1 line

I guess, but what does that churn buy us?

It's not that important really. I think we need to document the return value, and check it according to how it is documented. The reason I commented, I see < 0 and ask "what if it is > 0"? I look it up and it turns out it's never > 0. So why check < 0?

Quoted 10 lines
Quoted 8 lines

virt/kvm/coalesced_mmio.c int kvm_coalesced_mmio_init(struct kvm *kvm) · line 111

Quoted 5 lines
virt/kvm/coalesced_mmio.c +4 -0
+	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
+	if (ret < 0)
+		kfree(dev);
+
 

kill empty line

Why do you object here especially when there is precedence

How do you mean, precedence?

Quoted 3 lines

with
something like the space before the return with [B]? I think big mono-blocks of code are ugly and harder to read, personally.

I don't intend to keep arguing and I agree it's a question of style. But since you ask why I'll try to answer. I think an
empty line should help delimit a block of code with some common meaning, like a paragraph. But if overused it loses meaning and stops being helpful.

E.g., it does not make sense to put it between every 2 lines of code in a function. It also does not make sense to put it after } which is already delimiting a block in a visible way; it does not make sense to put it around a multiline comment which is delimited by /**/. It does not make sense to put it around an idented block which is already delimited by indentation.

Quoted 8 lines
Quoted 8 lines

virt/kvm/kvm_main.c int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) · line 2581

Quoted 6 lines
virt/kvm/kvm_main.c +5 -0
+		if (bus->devs[i] == dev) {
+			bus->devs[i] = bus->devs[--bus->dev_count];
+			break;
+		}
+	}

no {} around single statement

This is actually part of style IMO, it is just hard for a perl script to catch :).

Quoted 8 lines
Quoted 6 lines
Quoted 6 lines

}

static struct notifier_block kvm_cpu_notifier = {

#5 lore raw

Re: [KVM PATCH v9 1/2] KVM: make io_bus interface more robust

Quoted 11 lines · Michael S. Tsirkin
Quoted 3 lines · Gregory Haskins

I suppose its personal preference either way, so I guess unless Avi objects lets just each have our own style in that regard.

I think Avi already said we don't need to standardize everything. I hope at least some of the comments were helpful.

Yes, it was very helpful and I really *do* appreciate the time you take to review the code. I think you will see that aside from the things we agree are whitespace style, I addressed your feedback in v10. The one notable omission (and this was not intentional) was that I forgot to document the return value like you requested. If a v11 is needed after review comments, I will update it then. Otherwise, Ill just submit a trivial doc patch after v10 is accepted.

Thanks again, Michael,
-Greg

#6 lore raw

PATCH v9 2/2 KVM: add iosignalfd support

In reply to Gregory Haskins

iosignalfd is a mechanism to register PIO/MMIO regions to trigger an eventfd signal when written to by a guest. Host userspace can register any arbitrary IO address with a corresponding eventfd and then pass the eventfd to a specific end-point of interest for handling.

Normal IO requires a blocking round-trip since the operation may cause side-effects in the emulated model or may return data to the caller. Therefore, an IO in KVM traps from the guest to the host, causes a VMX/SVM "heavy-weight" exit back to userspace, and is ultimately serviced by qemu's device model synchronously before returning control back to the vcpu.

However, there is a subclass of IO which acts purely as a trigger for other IO (such as to kick off an out-of-band DMA request, etc). For these patterns, the synchronous call is particularly expensive since we really only want to simply get our notification transmitted asychronously and return as quickly as possible. All the sychronous infrastructure to ensure proper data-dependencies are met in the normal IO case are just unecessary overhead for signalling. This adds additional computational load on the system, as well as latency to the signalling path.

Therefore, we provide a mechanism for registration of an in-kernel trigger point that allows the VCPU to only require a very brief, lightweight exit just long enough to signal an eventfd. This also means that any clients compatible with the eventfd interface (which includes userspace and kernelspace equally well) can now register to be notified. The end result should be a more flexible and higher performance notification API for the backend KVM hypervisor and perhipheral components.

To test this theory, we built a test-harness called "doorbell". This module has a function called "doorbell_ring()" which simply increments a counter for each time the doorbell is signaled. It supports signalling from either an eventfd, or an ioctl().

We then wired up two paths to the doorbell: One via QEMU via a registered io region and through the doorbell ioctl(). The other is direct via iosignalfd.

You can download this test harness here:

ftp://ftp.novell.com/dev/ghaskins/doorbell.tar.bz2

The measured results are as follows:

qemu-mmio:       110000 iops, 9.09us rtt
iosignalfd-mmio: 200100 iops, 5.00us rtt
iosignalfd-pio:  367300 iops, 2.72us rtt

I didn't measure qemu-pio, because I have to figure out how to register a PIO region with qemu's device model, and I got lazy. However, for now we can extrapolate based on the data from the NULLIO runs of +2.56us for MMIO, and -350ns for HC, we get:

qemu-pio:      153139 iops, 6.53us rtt
iosignalfd-hc: 412585 iops, 2.37us rtt

these are just for fun, for now, until I can gather more data.

Here is a graph for your convenience:

http://developer.novell.com/wiki/images/7/76/Iofd-chart.png

The conclusion to draw is that we save about 4us by skipping the userspace hop.

--------------------

---

 arch/x86/kvm/x86.c       |    1 
 include/linux/kvm.h      |   15 ++
 include/linux/kvm_host.h |   10 +-
 virt/kvm/eventfd.c       |  280 ++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/kvm_main.c      |   11 ++
 5 files changed, 313 insertions(+), 4 deletions(-)
arch/x86/kvm/x86.c +1 -0
index 0e74d98..6e4b2f5 100644
@@ -1204,6 +1204,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_IRQ_INJECT_STATUS:
 	case KVM_CAP_ASSIGN_DEV_IRQ:
 	case KVM_CAP_IRQFD:
+	case KVM_CAP_IOSIGNALFD:
 	case KVM_CAP_PIT2:
 		r = 1;
 		break;
include/linux/kvm.h +15 -0
index 76c6408..236f12d 100644
@@ -307,6 +307,19 @@ struct kvm_guest_debug {
 	struct kvm_guest_debug_arch arch;
 };
 
+#define KVM_IOSIGNALFD_FLAG_TRIGGER   (1 << 0) /* trigger is valid */
+#define KVM_IOSIGNALFD_FLAG_PIO       (1 << 1) /* is a pio (otherwise mmio) */
+#define KVM_IOSIGNALFD_FLAG_DEASSIGN  (1 << 2)
+
+struct kvm_iosignalfd {
+	__u64 trigger;
+	__u64 addr;        /* legal pio/mmio address */
+	__u32 len;         /* 1, 2, 4, or 8 bytes    */
+	__s32 fd;
+	__u32 flags;
+	__u8  pad[36];
+};
+
 #define KVM_TRC_SHIFT           16
 /*
  * kvm trace categories
@@ -409,6 +422,7 @@ struct kvm_guest_debug {
 #define KVM_CAP_PIT2 33
 #endif
 #define KVM_CAP_SET_BOOT_CPU_ID 34
+#define KVM_CAP_IOSIGNALFD 35
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -517,6 +531,7 @@ struct kvm_irqfd {
 #define KVM_IRQFD                  _IOW(KVMIO, 0x76, struct kvm_irqfd)
 #define KVM_CREATE_PIT2		   _IOW(KVMIO, 0x77, struct kvm_pit_config)
 #define KVM_SET_BOOT_CPU_ID        _IO(KVMIO, 0x78)
+#define KVM_IOSIGNALFD             _IOW(KVMIO, 0x79, struct kvm_iosignalfd)
 
 /*
  * ioctls for vcpu fds
include/linux/kvm_host.h +8 -2
index 306bc67..5099416 100644
@@ -154,6 +154,7 @@ struct kvm {
 		spinlock_t        lock;
 		struct list_head  items;
 	} irqfds;
+	struct list_head iosignalfds;
 #endif
 	struct kvm_vm_stat stat;
 	struct kvm_arch arch;
@@ -532,19 +533,24 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
 
 #ifdef CONFIG_HAVE_KVM_EVENTFD
 
-void kvm_irqfd_init(struct kvm *kvm);
+void kvm_eventfd_init(struct kvm *kvm);
 int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
 void kvm_irqfd_release(struct kvm *kvm);
+int kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args);
 
 #else
 
-static inline void kvm_irqfd_init(struct kvm *kvm) {}
+static inline void kvm_eventfd_init(struct kvm *kvm) {}
 static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
 {
 	return -EINVAL;
 }
 
 static inline void kvm_irqfd_release(struct kvm *kvm) {}
+static inline int kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	return -ENOSYS;
+}
 
 #endif /* CONFIG_HAVE_KVM_EVENTFD */
 
virt/kvm/eventfd.c +279 -1

304 lines not on this page · raw message

virt/kvm/kvm_main.c +10 -1
index 11595c7..5ac381b 100644
@@ -979,7 +979,7 @@ static struct kvm *kvm_create_vm(void)
 	spin_lock_init(&kvm->mmu_lock);
 	spin_lock_init(&kvm->requests_lock);
 	kvm_io_bus_init(&kvm->pio_bus);
-	kvm_irqfd_init(kvm);
+	kvm_eventfd_init(kvm);
 	mutex_init(&kvm->lock);
 	mutex_init(&kvm->irq_lock);
 	kvm_io_bus_init(&kvm->mmio_bus);
@@ -2271,6 +2271,15 @@ static long kvm_vm_ioctl(struct file *filp,
 		r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
 		break;
 	}
+	case KVM_IOSIGNALFD: {
+		struct kvm_iosignalfd data;
+
+		r = -EFAULT;
+		if (copy_from_user(&data, argp, sizeof data))
+			goto out;
+		r = kvm_iosignalfd(kvm, &data);
+		break;
+	}
 #ifdef CONFIG_KVM_APIC_ARCHITECTURE
 	case KVM_SET_BOOT_CPU_ID:
 		r = 0;
#7 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Some comments below. Sorry, I know it's late in the series, but previously I've been too confused with complicated locking to notice anything else :(.

Quoted 93 lines · Gregory Haskins

iosignalfd is a mechanism to register PIO/MMIO regions to trigger an eventfd signal when written to by a guest. Host userspace can register any arbitrary IO address with a corresponding eventfd and then pass the eventfd to a specific end-point of interest for handling.

Normal IO requires a blocking round-trip since the operation may cause side-effects in the emulated model or may return data to the caller. Therefore, an IO in KVM traps from the guest to the host, causes a VMX/SVM "heavy-weight" exit back to userspace, and is ultimately serviced by qemu's device model synchronously before returning control back to the vcpu.

However, there is a subclass of IO which acts purely as a trigger for other IO (such as to kick off an out-of-band DMA request, etc). For these patterns, the synchronous call is particularly expensive since we really only want to simply get our notification transmitted asychronously and return as quickly as possible. All the sychronous infrastructure to ensure proper data-dependencies are met in the normal IO case are just unecessary overhead for signalling. This adds additional computational load on the system, as well as latency to the signalling path.

Therefore, we provide a mechanism for registration of an in-kernel trigger point that allows the VCPU to only require a very brief, lightweight exit just long enough to signal an eventfd. This also means that any clients compatible with the eventfd interface (which includes userspace and kernelspace equally well) can now register to be notified. The end result should be a more flexible and higher performance notification API for the backend KVM hypervisor and perhipheral components.

To test this theory, we built a test-harness called "doorbell". This module has a function called "doorbell_ring()" which simply increments a counter for each time the doorbell is signaled. It supports signalling from either an eventfd, or an ioctl().

We then wired up two paths to the doorbell: One via QEMU via a registered io region and through the doorbell ioctl(). The other is direct via iosignalfd.

You can download this test harness here:

ftp://ftp.novell.com/dev/ghaskins/doorbell.tar.bz2

The measured results are as follows:

qemu-mmio:       110000 iops, 9.09us rtt
iosignalfd-mmio: 200100 iops, 5.00us rtt
iosignalfd-pio:  367300 iops, 2.72us rtt

I didn't measure qemu-pio, because I have to figure out how to register a PIO region with qemu's device model, and I got lazy. However, for now we can extrapolate based on the data from the NULLIO runs of +2.56us for MMIO, and -350ns for HC, we get:

qemu-pio:      153139 iops, 6.53us rtt
iosignalfd-hc: 412585 iops, 2.37us rtt

these are just for fun, for now, until I can gather more data.

Here is a graph for your convenience:

http://developer.novell.com/wiki/images/7/76/Iofd-chart.png

The conclusion to draw is that we save about 4us by skipping the userspace hop.

--------------------

---

 arch/x86/kvm/x86.c       |    1 
 include/linux/kvm.h      |   15 ++
 include/linux/kvm_host.h |   10 +-
 virt/kvm/eventfd.c       |  280 ++++++++++++++++++++++++++++++++++++++++++++++
 virt/kvm/kvm_main.c      |   11 ++
 5 files changed, 313 insertions(+), 4 deletions(-)
arch/x86/kvm/x86.c +1 -0
index 0e74d98..6e4b2f5 100644
@@ -1204,6 +1204,7 @@ int kvm_dev_ioctl_check_extension(long ext)
 	case KVM_CAP_IRQ_INJECT_STATUS:
 	case KVM_CAP_ASSIGN_DEV_IRQ:
 	case KVM_CAP_IRQFD:
+	case KVM_CAP_IOSIGNALFD:
 	case KVM_CAP_PIT2:
 		r = 1;
 		break;
include/linux/kvm.h +0 -0
index 76c6408..236f12d 100644

include/linux/kvm.h struct kvm_guest_debug { · line 310

Quoted 4 lines
include/linux/kvm.h +1 -0
@@ -307,6 +307,19 @@ struct kvm_guest_debug {
 	struct kvm_guest_debug_arch arch;
 };
 
+#define KVM_IOSIGNALFD_FLAG_TRIGGER   (1 << 0) /* trigger is valid */

can we rename trigger -> value?

include/linux/kvm.h struct kvm_guest_debug { · line 315

Quoted 5 lines
include/linux/kvm.h +5 -0
+#define KVM_IOSIGNALFD_FLAG_PIO       (1 << 1) /* is a pio (otherwise mmio) */
+#define KVM_IOSIGNALFD_FLAG_DEASSIGN  (1 << 2)
+
+struct kvm_iosignalfd {
+	__u64 trigger;

for length <8, it's the 8*len least significant bits that are used, right? That's a bit ugly ... Maybe just put an 8 byte array here instead, then the first len bytes are valid.

Quoted 88 lines
include/linux/kvm.h +9 -0
+	__u64 addr;        /* legal pio/mmio address */
+	__u32 len;         /* 1, 2, 4, or 8 bytes    */
+	__s32 fd;
+	__u32 flags;
+	__u8  pad[36];
+};
+
 #define KVM_TRC_SHIFT           16
 /*
  * kvm trace categories
@@ -409,6 +422,7 @@ struct kvm_guest_debug {
 #define KVM_CAP_PIT2 33
 #endif
 #define KVM_CAP_SET_BOOT_CPU_ID 34
+#define KVM_CAP_IOSIGNALFD 35
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
@@ -517,6 +531,7 @@ struct kvm_irqfd {
 #define KVM_IRQFD                  _IOW(KVMIO, 0x76, struct kvm_irqfd)
 #define KVM_CREATE_PIT2		   _IOW(KVMIO, 0x77, struct kvm_pit_config)
 #define KVM_SET_BOOT_CPU_ID        _IO(KVMIO, 0x78)
+#define KVM_IOSIGNALFD             _IOW(KVMIO, 0x79, struct kvm_iosignalfd)
 
 /*
  * ioctls for vcpu fds
include/linux/kvm_host.h +8 -2
index 306bc67..5099416 100644
@@ -154,6 +154,7 @@ struct kvm {
 		spinlock_t        lock;
 		struct list_head  items;
 	} irqfds;
+	struct list_head iosignalfds;
 #endif
 	struct kvm_vm_stat stat;
 	struct kvm_arch arch;
@@ -532,19 +533,24 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
 
 #ifdef CONFIG_HAVE_KVM_EVENTFD
 
-void kvm_irqfd_init(struct kvm *kvm);
+void kvm_eventfd_init(struct kvm *kvm);
 int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
 void kvm_irqfd_release(struct kvm *kvm);
+int kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args);
 
 #else
 
-static inline void kvm_irqfd_init(struct kvm *kvm) {}
+static inline void kvm_eventfd_init(struct kvm *kvm) {}
 static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
 {
 	return -EINVAL;
 }
 
 static inline void kvm_irqfd_release(struct kvm *kvm) {}
+static inline int kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	return -ENOSYS;
+}
 
 #endif /* CONFIG_HAVE_KVM_EVENTFD */
 
virt/kvm/eventfd.c +4 -0
index 4092b8d..c03b619 100644
@@ -21,6 +21,7 @@
  */
 
 #include <linux/kvm_host.h>
+#include <linux/kvm.h>
 #include <linux/workqueue.h>
 #include <linux/syscalls.h>
 #include <linux/wait.h>
@@ -28,6 +29,9 @@
 #include <linux/file.h>
 #include <linux/list.h>
 #include <linux/eventfd.h>
+#include <linux/kernel.h>
+
+#include "iodev.h"
 
 /*
  * --------------------------------------------------------------------

virt/kvm/eventfd.c fail: · line 245

Quoted 9 lines
virt/kvm/eventfd.c +2 -1
@@ -234,10 +238,12 @@ fail:
 }
 
 void
-kvm_irqfd_init(struct kvm *kvm)
+kvm_eventfd_init(struct kvm *kvm)
 {
 	spin_lock_init(&kvm->irqfds.lock);
 	INIT_LIST_HEAD(&kvm->irqfds.items);
+

don't need this empty line

Quoted 5 lines
virt/kvm/eventfd.c +1 -0
+	INIT_LIST_HEAD(&kvm->iosignalfds);
 }
 
 /*

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 341

Quoted 9 lines
virt/kvm/eventfd.c +6 -0
@@ -327,3 +333,275 @@ static void __exit irqfd_module_exit(void)
 
 module_init(irqfd_module_init);
 module_exit(irqfd_module_exit);
+
+/*
+ * --------------------------------------------------------------------
+ * iosignalfd: translate a PIO/MMIO memory write to an eventfd signal.
+ *
+ * userspace can register a PIO/MMIO address with an eventfd for recieving

recieving -> receiving

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 349

Quoted 8 lines
virt/kvm/eventfd.c +8 -0
+ * notification when the memory has been touched.
+ * --------------------------------------------------------------------
+ */
+
+struct _iosignalfd {
+	struct list_head     list;
+	u64                  addr;
+	size_t               length;

"int length" should be enough: the value is 1, 2, 4 or 8. and put wildcard near it if you want to save some space

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 351

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+	struct eventfd_ctx  *eventfd;
+	u64                  match;

match -> value

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 353

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+	struct kvm_io_device dev;
+	int                  wildcard:1;

don't use bitfields

Quoted 12 lines
virt/kvm/eventfd.c +12 -0
+};
+
+static inline struct _iosignalfd *
+to_iosignalfd(struct kvm_io_device *dev)
+{
+	return container_of(dev, struct _iosignalfd, dev);
+}
+
+static void
+iosignalfd_release(struct _iosignalfd *p)
+{
+	eventfd_ctx_put(p->eventfd);

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 375

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	list_del(&p->list);
+	kfree(p);
+}
+
+static bool
+iosignalfd_in_range(struct _iosignalfd *p, gpa_t addr, int len, const void *val)
+{
+	u64 _val;
+
+	if (!(addr == p->addr && len == p->length))

de-morgan's laws can help simplify this

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 1 line
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Quoted 18 lines
virt/kvm/eventfd.c +18 -0
+		return false;
+
+	if (p->wildcard)
+		/* all else equal, wildcard is always a hit */
+		return true;
+
+	/* otherwise, we have to actually compare the data */
+
+	BUG_ON(!IS_ALIGNED((unsigned long)val, len));
+
+	switch (len) {
+	case 1:
+		_val = *(u8 *)val;
+		break;
+	case 2:
+		_val = *(u16 *)val;
+		break;
+	case 4:

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 404

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+		_val = *(u32 *)val;
+		break;
+	case 8:
+		_val = *(u64 *)val;
+		break;
+	default:
+		return false;
+	}
+
+	return _val == p->match ? true : false;

Life be simpler if we use an 8 byte array for match and just do memcmp here.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 409

Quoted 5 lines
virt/kvm/eventfd.c +5 -0
+}
+
+/*
+ * MMIO/PIO writes trigger an event if the addr/val match
+ */

single line comment can look like this:
/* MMIO/PIO writes trigger an event if the addr/val match */

Quoted 22 lines
virt/kvm/eventfd.c +22 -0
+static int
+iosignalfd_write(struct kvm_io_device *this, gpa_t addr, int len,
+		 const void *val)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+
+	if (!iosignalfd_in_range(p, addr, len, val))
+		return -EOPNOTSUPP;
+
+	eventfd_signal(p->eventfd, 1);
+	return 0;
+}
+
+/*
+ * This function is called as KVM is completely shutting down.  We do not
+ * need to worry about locking just nuke anything we have as quickly as possible
+ */
+static void
+iosignalfd_destructor(struct kvm_io_device *this)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 441

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	iosignalfd_release(p);
+}
+
+static const struct kvm_io_device_ops iosignalfd_ops = {
+	.write      = iosignalfd_write,
+	.destructor = iosignalfd_destructor,
+};
+
+static bool
+iosignalfd_overlap(struct _iosignalfd *lhs, struct _iosignalfd *rhs)

this checks both region overlap and data collision. better split into two helpers?

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 447

Quoted 6 lines
virt/kvm/eventfd.c +6 -0
+{
+	/*
+	 * Check for completely non-overlapping regions.  We can simply
+	 * return "false" for non-overlapping regions and be done with
+	 * it.
+	 */

done with it -> ignore the value

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 449

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+	if ((rhs->addr + rhs->length) <= lhs->addr)
+		return false;

rhs->addr + rhs->length <= lhs->addr
is not less clear, as precedence for simple math
follows the familiar rules from school.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 451

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+
+	if ((lhs->addr + lhs->length) <= rhs->addr)

this math can overflow.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 452

Quoted 1 line
virt/kvm/eventfd.c +1 -0
+		return false;

or shorter:
if (rhs->addr + rhs->length <= lhs->addr ||
lhs->addr + lhs->length <= rhs->addr)

           return true;

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void)

Quoted 4 lines
virt/kvm/eventfd.c +4 -0
+
+	/*
+	 * If we get here, we know there is *some* overlap, but we don't
+	 * yet know how much.

how much?

Quoted 1 line

Make sure its a "precise" overlap, or

precise overlap -> address/len pairs match

virt/kvm/eventfd.c

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+	 * its rejected as incompatible
+	 */

"rejected" does not seem to make sense in the context of a boolean function

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 464

Quoted 6 lines
virt/kvm/eventfd.c +6 -0
+	if (lhs->addr != rhs->addr)
+		return true;
+
+	if (lhs->length != rhs->length)
+		return true;
+

or shorter:

	if (lhs->addr != rhs->addr || lhs->length != rhs->length)
           return true;
Quoted 7 lines
virt/kvm/eventfd.c +7 -0
+	/*
+	 * If we get here, the request should be a precise overlap
+	 * between rhs+lhs.  The only thing left to check is for
+	 * data-match overlap.  If the data match is distinctly different
+	 * we can allow the two to co-exist.  Any kind of wild-card
+	 * consitutes an incompatible range, so reject any wild-cards,
+	 * or if the match token is identical.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 479

Quoted 10 lines
virt/kvm/eventfd.c +8 -0
+	 */
+	if (lhs->wildcard || rhs->wildcard || lhs->match == rhs->match)
+		return true;
+
+	return false;
+}
 
 
+
+/* assumes kvm->slots_lock write-lock held */

it seems you only need read lock?

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 486

Quoted 7 lines
virt/kvm/eventfd.c +7 -0
+static bool
+iosignalfd_check_collision(struct kvm *kvm, struct _iosignalfd *p)
+{
+	struct _iosignalfd *_p;
+
+	list_for_each_entry(_p, &kvm->iosignalfds, list)
+		if (iosignalfd_overlap(_p, p))

This looks wrong: let's assume I want one signal with length 1 and one with length 2 at address 0. They never trigger together, so it should be ok to have 2 such devices.

Quoted 17 lines
virt/kvm/eventfd.c +17 -0
+			return true;
+
+	return false;
+}
+
+static int
+kvm_assign_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	int                       pio = args->flags & KVM_IOSIGNALFD_FLAG_PIO;
+	struct kvm_io_bus        *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+	struct _iosignalfd       *p;
+	struct eventfd_ctx       *eventfd;
+	int                       ret;
+
+	switch (args->len) {
+	case 1:
+	case 2:

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 513

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	case 4:
+	case 8:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	eventfd = eventfd_ctx_fdget(args->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);

since this eventfd is kept around indefinitely, we should keep the file * around as well, so that this eventfd is accounted for properly with # of open files limit set by the admin.

Quoted 5 lines
virt/kvm/eventfd.c +5 -0
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		ret = -ENOMEM;
+		goto fail;

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 528

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	}
+
+	INIT_LIST_HEAD(&p->list);
+	p->addr    = args->addr;
+	p->length  = args->len;
+	p->eventfd = eventfd;
+
+	/*
+	 * A trigger address is optional, otherwise this is a wildcard
+	 */

A single line comment can look like this:

	/* A trigger address is optional, otherwise this is a wildcard */

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 530

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+	if (args->flags & KVM_IOSIGNALFD_FLAG_TRIGGER)
+		p->match = args->trigger;

For len < 8, high bits in trigger are ignored. it's better to check that they are 0, less confusing if the user e.g. gets the endian-ness wrong.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 536

Quoted 7 lines
virt/kvm/eventfd.c +6 -0
+	else
+		p->wildcard = true;
+
 
+	down_write(&kvm->slots_lock);
+
+	/* Verify that there isnt a match already */

Better to put documentation to where function is declared, not where it is used.

Quoted 7 lines
virt/kvm/eventfd.c +7 -0
+	if (iosignalfd_check_collision(kvm, p)) {
+		ret = -EEXIST;
+		goto unlock_fail;
+	}
+
+	kvm_iodevice_init(&p->dev, &iosignalfd_ops);
+

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 553

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	ret = __kvm_io_bus_register_dev(bus, &p->dev);
+	if (ret < 0)
+		goto unlock_fail;
+
+	list_add_tail(&p->list, &kvm->iosignalfds);
+
+	up_write(&kvm->slots_lock);
+
+	return 0;
+

we probably do not need an empty line after each line of code here

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 560

Quoted 7 lines
virt/kvm/eventfd.c +7 -0
+unlock_fail:
+	up_write(&kvm->slots_lock);
+fail:
+	/*
+	 * it would have never made it to the list in the failure path, so
+	 * we dont need to worry about removing it
+	 */

of course: you goto fail before list_add
can just kill this comment

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 565

Quoted 5 lines
virt/kvm/eventfd.c +5 -0
+	kfree(p);
+
+	eventfd_ctx_put(eventfd);
+
+	return ret;

we probably do not need an empty line after each line of code here

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 369

Quoted 3 lines
virt/kvm/eventfd.c +3 -0
+}
+
+

two empty lines

Quoted 7 lines
virt/kvm/eventfd.c +7 -0
+static int
+kvm_deassign_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	int                       pio = args->flags & KVM_IOSIGNALFD_FLAG_PIO;
+	struct kvm_io_bus        *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+	struct _iosignalfd       *p, *tmp;
+	struct eventfd_ctx       *eventfd;

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 585

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	int                       ret = 0;
+
+	eventfd = eventfd_ctx_fdget(args->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	down_write(&kvm->slots_lock);
+
+	list_for_each_entry_safe(p, tmp, &kvm->iosignalfds, list) {
+

kill empty line

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 587

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+		if (p->eventfd != eventfd)
+			continue;

So for deassign, you ignore all arguments besides fd? Is this intentional? Looks strange - think of multiple addresses triggering a single eventfd. But if so, it's better to have a different ioctl with just the fields we need.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 590

Quoted 3 lines
virt/kvm/eventfd.c +3 -0
+
+		__kvm_io_bus_unregister_dev(bus, &p->dev);
+		iosignalfd_release(p);

a single deassign removed multiple irqfds? Looks ugly.

virt/kvm/eventfd.c

Quoted 2 lines
virt/kvm/eventfd.c +2 -0
+	}
+

kill empty line

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 566

Quoted 6 lines
virt/kvm/eventfd.c +6 -0
+	up_write(&kvm->slots_lock);
+
+	eventfd_ctx_put(eventfd);
+
+	return ret;
+}

return error status if no device was found?

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 604

Quoted 6 lines
virt/kvm/eventfd.c +6 -0
+
+int
+kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	if (args->flags & KVM_IOSIGNALFD_FLAG_DEASSIGN)
+		return kvm_deassign_iosignalfd(kvm, args);

Better check that only known flag values are present. Otherwise when you add more flags things just break silently.

Quoted 17 lines
virt/kvm/eventfd.c +3 -0
+
+	return kvm_assign_iosignalfd(kvm, args);
+}
virt/kvm/kvm_main.c +1 -1
index 11595c7..5ac381b 100644
@@ -979,7 +979,7 @@ static struct kvm *kvm_create_vm(void)
 	spin_lock_init(&kvm->mmu_lock);
 	spin_lock_init(&kvm->requests_lock);
 	kvm_io_bus_init(&kvm->pio_bus);
-	kvm_irqfd_init(kvm);
+	kvm_eventfd_init(kvm);
 	mutex_init(&kvm->lock);
 	mutex_init(&kvm->irq_lock);
 	kvm_io_bus_init(&kvm->mmio_bus);

virt/kvm/kvm_main.c static long kvm_vm_ioctl(struct file *filp, · line 2277

Quoted 7 lines
virt/kvm/kvm_main.c +4 -0
@@ -2271,6 +2271,15 @@ static long kvm_vm_ioctl(struct file *filp,
 		r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
 		break;
 	}
+	case KVM_IOSIGNALFD: {
+		struct kvm_iosignalfd data;
+
+		r = -EFAULT;

this trick is nice, it saves a line of code for the closing brace but why waste it on an empty line above then?

Quoted 8 lines
virt/kvm/kvm_main.c +5 -0
+		if (copy_from_user(&data, argp, sizeof data))
+			goto out;
+		r = kvm_iosignalfd(kvm, &data);
+		break;
+	}
 #ifdef CONFIG_KVM_APIC_ARCHITECTURE
 	case KVM_SET_BOOT_CPU_ID:
 		r = 0;
#8 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

(adding Davide, there's a small comment for you in the middle, search for eventfd)

Quoted 10 lines · Michael S. Tsirkin

include/linux/kvm.h struct kvm_guest_debug { · line 311

Quoted 7 lines
include/linux/kvm.h +1 -0
@@ -307,6 +307,19 @@ struct kvm_guest_debug {
  	struct kvm_guest_debug_arch arch;
  };
 
+#define KVM_IOSIGNALFD_FLAG_TRIGGER   (1<<  0) /* trigger is valid */
 

can we rename trigger -> value?

Or maybe data_match?

Speaking of renames, how about IOSIGNALFD -> IOEVENTFD? I have some vague uneasiness seeing signals all the time.

Quoted 12 lines

include/linux/kvm.h struct kvm_guest_debug {

Quoted 6 lines
include/linux/kvm.h +5 -0
+#define KVM_IOSIGNALFD_FLAG_PIO       (1<<  1) /* is a pio (otherwise mmio) */
+#define KVM_IOSIGNALFD_FLAG_DEASSIGN  (1<<  2)
+
+struct kvm_iosignalfd {
+	__u64 trigger;
 

for length<8, it's the 8*len least significant bits that are used, right? That's a bit ugly ... Maybe just put an 8 byte array here instead, then the first len bytes are valid.

We're matching the value as the guest wrote it. I think this is fine.

Quoted 6 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void)

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+	struct kvm_io_device dev;
+	int                  wildcard:1;
 

don't use bitfields

Yeah, bool is better.

Quoted 6 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 2 lines
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Why would you want that?

Quoted 25 lines
Quoted 25 lines
virt/kvm/eventfd.c +24 -0
+		return false;
+
+	if (p->wildcard)
+		/* all else equal, wildcard is always a hit */
+		return true;
+
+	/* otherwise, we have to actually compare the data */
+
+	BUG_ON(!IS_ALIGNED((unsigned long)val, len));
+
+	switch (len) {
+	case 1:
+		_val = *(u8 *)val;
+		break;
+	case 2:
+		_val = *(u16 *)val;
+		break;
+	case 4:
+		_val = *(u32 *)val;
+		break;
+	case 8:
+		_val = *(u64 *)val;
+		break;
+	default:
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 404

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+		return false;
+	}
+
+	return _val == p->match ? true : false;

Life be simpler if we use an 8 byte array for match and just do memcmp here.

My plan is to change the io_dev interface to pass a u64.

Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 513

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+
+	eventfd = eventfd_ctx_fdget(args->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);

since this eventfd is kept around indefinitely, we should keep the file * around as well, so that this eventfd is accounted for properly with # of open files limit set by the admin.

Won't all eventfd_ctx_get() uses suffer from that?

Davide, I think this is better handled in eventfd. Or else we can ignore it and trust whoever holds the eventfd_ctx to limit the mount of objects.

Quoted 12 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 604

Quoted 7 lines
virt/kvm/eventfd.c +6 -0
+
+int
+kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	if (args->flags&  KVM_IOSIGNALFD_FLAG_DEASSIGN)
+		return kvm_deassign_iosignalfd(kvm, args);

Better check that only known flag values are present. Otherwise when you add more flags things just break silently.

Good comment and something that we miss a lot.

Quoted 9 lines

virt/kvm/kvm_main.c static long kvm_vm_ioctl(struct file *filp, · line 2277

Quoted 5 lines
virt/kvm/kvm_main.c +4 -0
+	case KVM_IOSIGNALFD: {
+		struct kvm_iosignalfd data;
+
+		r = -EFAULT;

this trick is nice, it saves a line of code for the closing brace but why waste it on an empty line above then?

Traditionally C code separates declarations from code.

Signature · 1 line
error compiling committee.c: too many arguments to function
#9 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 8 lines · Avi Kivity
Quoted 6 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 2 lines
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Why would you want that?

Donnu. Why would anyone want to catch 8 byte writes at all? Seriously, why add artificial limitations?
IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

Signature · 1 line
MST
#10 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 9 lines · Michael S. Tsirkin
Quoted 7 lines · Avi Kivity
Quoted 7 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 3 lines
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Quoted 5 lines
Quoted 2 lines

Why would you want that?

Donnu. Why would anyone want to catch 8 byte writes at all?

One of the natural write sizes.

Quoted 4 lines

Seriously, why add artificial limitations? IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

They should not conflict, but a two byte write need not hit a one byte registration.

Signature · 1 line
error compiling committee.c: too many arguments to function
#11 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 18 lines · Avi Kivity
Quoted 9 lines · Michael S. Tsirkin
Quoted 7 lines · Avi Kivity
Quoted 7 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 3 lines
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Quoted 5 lines
Quoted 2 lines

Why would you want that?

Donnu. Why would anyone want to catch 8 byte writes at all?

One of the natural write sizes.

Quoted 7 lines
Quoted 4 lines

Seriously, why add artificial limitations? IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

They should not conflict, but a two byte write need not hit a one byte registration.

Yes. That's exactly what I'm saying. I think it should be possible to create 2 fds:

addr = 0
len = 1
addr = 0
len = 2
and at most one will ever trigger.

But current code will not let you create the second one.

Signature · 1 line
MST
#12 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 13 lines · Michael S. Tsirkin
Quoted 9 lines
Quoted 6 lines

Seriously, why add artificial limitations? IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

They should not conflict, but a two byte write need not hit a one byte registration.

Yes. That's exactly what I'm saying. I think it should be possible to create 2 fds:

Quoted 8 lines

addr = 0
len = 1
addr = 0
len = 2
and at most one will ever trigger.

But current code will not let you create the second one.

I agree then. Good catch.

Signature · 1 line
error compiling committee.c: too many arguments to function
#13 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

In reply to Michael S. Tsirkin
Quoted 37 lines · Michael S. Tsirkin
Quoted 23 lines · Avi Kivity
Quoted 12 lines · Michael S. Tsirkin
Quoted 9 lines · Avi Kivity
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 4 lines
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Quoted 6 lines
Quoted 3 lines

Why would you want that?

Donnu. Why would anyone want to catch 8 byte writes at all?

One of the natural write sizes.

Quoted 8 lines
Quoted 5 lines

Seriously, why add artificial limitations? IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

They should not conflict, but a two byte write need not hit a one byte registration.

Yes. That's exactly what I'm saying. I think it should be possible to create 2 fds:

Quoted 9 lines

addr = 0
len = 1
addr = 0
len = 2
and at most one will ever trigger.

But current code will not let you create the second one.

Note that this was by design to keep the code simple since we don't have a (known) use case for overlap. At the very least, you have to address how data subsets are handled. But do we really need that functionality?

-Greg

#14 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 44 lines · Gregory Haskins
Quoted 43 lines · Michael S. Tsirkin
Quoted 23 lines · Avi Kivity
Quoted 12 lines · Michael S. Tsirkin
Quoted 9 lines · Avi Kivity
Quoted 9 lines

Review

Quoted 4 lines
(quoted diff) +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Quoted 6 lines
Quoted 3 lines

Why would you want that?

Donnu. Why would anyone want to catch 8 byte writes at all?

One of the natural write sizes.

Quoted 8 lines
Quoted 5 lines

Seriously, why add artificial limitations? IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

They should not conflict, but a two byte write need not hit a one byte registration.

Yes. That's exactly what I'm saying. I think it should be possible to create 2 fds:

addr = 0
len = 1
addr = 0
len = 2
and at most one will ever trigger.

Quoted 9 lines
Quoted 3 lines

But current code will not let you create the second one.

Note that this was by design to keep the code simple since we don't have a (known) use case for overlap. At the very least, you have to address how data subsets are handled. But do we really need that functionality?

-Greg

Hey, forget about overlap. Overlap does not exist as a concept. You now spend a lot of effort to detect it. Kill all that code, and just do this on assignment:

list_for_each(...)

	if (rhs->add == lhs->addr && rhs->len == lhs->len &&
	    (rhs->wildcard || lhs->wildcard || rhs->data == lhs->data))
		return -EEXIST;
Signature · 1 line
MST
#15 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 68 lines · Michael S. Tsirkin
Quoted 58 lines · Gregory Haskins
Quoted 46 lines · Michael S. Tsirkin
Quoted 30 lines · Avi Kivity
Quoted 15 lines · Michael S. Tsirkin
Quoted 11 lines · Avi Kivity
Quoted 11 lines

Review

Quoted 5 lines
(quoted diff) +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

Quoted 8 lines
Quoted 4 lines

Why would you want that?

Donnu. Why would anyone want to catch 8 byte writes at all?

One of the natural write sizes.

Quoted 10 lines
Quoted 6 lines

Seriously, why add artificial limitations? IMO, addr=0,len=1 and addr=0,len=2 should not conflict.

They should not conflict, but a two byte write need not hit a one byte registration.

Yes. That's exactly what I'm saying. I think it should be possible to create 2 fds:

Quoted 10 lines

addr = 0
len = 1
addr = 0
len = 2
and at most one will ever trigger.

But current code will not let you create the second one.

Quoted 7 lines

Note that this was by design to keep the code simple since we don't have a (known) use case for overlap. At the very least, you have to address how data subsets are handled. But do we really need that functionality?

-Greg

Quoted 10 lines

Hey, forget about overlap. Overlap does not exist as a concept. You now spend a lot of effort to detect it. Kill all that code, and just do this on assignment:

list_for_each(...)

	if (rhs->add == lhs->addr && rhs->len == lhs->len &&
	    (rhs->wildcard || lhs->wildcard || rhs->data == lhs->data))
		return -EEXIST;

I like it. Will do for v10.

Thanks Michael,
-Greg

#16 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

In reply to Avi Kivity
Quoted 9 lines · Avi Kivity

(adding Davide, there's a small comment for you in the middle, search for eventfd)

Quoted 5 lines · Michael S. Tsirkin
Quoted 5 lines
include/linux/kvm.h +0 -0
@@ -307,6 +307,19 @@ struct kvm_guest_debug {
      struct kvm_guest_debug_arch arch;
  };
 
Quoted 7 lines
Quoted 5 lines

Review struct kvm_guest_debug { · line 311

Quoted 2 lines
(quoted diff) +1 -0
+#define KVM_IOSIGNALFD_FLAG_TRIGGER   (1<<  0) /* trigger is valid */
 

can we rename trigger -> value?

Or maybe data_match?

Yeah, at the least I should be consistent with trigger/match

Quoted 3 lines

Speaking of renames, how about IOSIGNALFD -> IOEVENTFD? I have some vague uneasiness seeing signals all the time.

Sure, that works for me.

-Greg

#17 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

In reply to Michael S. Tsirkin
Quoted 7 lines · Michael S. Tsirkin

Some comments below. Sorry, I know it's late in the series, but previously I've been too confused with complicated locking to notice anything else :(.

On Mon, Jul 06, 2009 at 04:33:21PM -0400, Gregory Haskins wrote:

Quoted 11 lines

include/linux/kvm.h struct kvm_guest_debug { · line 315

Quoted 6 lines
include/linux/kvm.h +5 -0
+#define KVM_IOSIGNALFD_FLAG_PIO       (1 << 1) /* is a pio (otherwise mmio) */
+#define KVM_IOSIGNALFD_FLAG_DEASSIGN  (1 << 2)
+
+struct kvm_iosignalfd {
+	__u64 trigger;

for length <8, it's the 8*len least significant bits that are used, right? That's a bit ugly ... Maybe just put an 8 byte array here instead, then the first len bytes are valid.

The original series uses an array that I kmalloc'ed to size, or left it NULL for a wildcard. Avi didn't like this and requested a u64 for all values. I don't care either way, but since you two are asking for conflicting designs, I will let you debate.

Quoted 13 lines

virt/kvm/eventfd.c fail: · line 245

Quoted 10 lines

void

virt/kvm/eventfd.c +2 -1
-kvm_irqfd_init(struct kvm *kvm)
+kvm_eventfd_init(struct kvm *kvm)
 {
 	spin_lock_init(&kvm->irqfds.lock);
 	INIT_LIST_HEAD(&kvm->irqfds.items);
+

don't need this empty line

Ack

Quoted 7 lines
Quoted 7 lines
virt/kvm/eventfd.c +1 -0
+	INIT_LIST_HEAD(&kvm->iosignalfds);
 }
 
 /*
@@ -327,3 +333,275 @@ static void __exit irqfd_module_exit(void)
 
Quoted 13 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 341

Quoted 9 lines
virt/kvm/eventfd.c +6 -0
 module_init(irqfd_module_init);
 module_exit(irqfd_module_exit);
+
+/*
+ * --------------------------------------------------------------------
+ * iosignalfd: translate a PIO/MMIO memory write to an eventfd signal.
+ *
+ * userspace can register a PIO/MMIO address with an eventfd for recieving

recieving -> receiving

Ack

/me is embarrassed

Quoted 4 lines
Quoted 4 lines
virt/kvm/eventfd.c +4 -0
+ * notification when the memory has been touched.
+ * --------------------------------------------------------------------
+ */
+
Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 349

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+struct _iosignalfd {
+	struct list_head     list;
+	u64                  addr;
+	size_t               length;

"int length" should be enough: the value is 1, 2, 4 or 8. and put wildcard near it if you want to save some space

Ok

Quoted 7 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 351

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+	struct eventfd_ctx  *eventfd;
+	u64                  match;

match -> value

Ok

Quoted 6 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 353

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+	struct kvm_io_device dev;
+	int                  wildcard:1;

don't use bitfields

bool?

Quoted 28 lines
Quoted 14 lines
virt/kvm/eventfd.c +12 -0
+};
+
+static inline struct _iosignalfd *
+to_iosignalfd(struct kvm_io_device *dev)
+{
+	return container_of(dev, struct _iosignalfd, dev);
+}
+
+static void
+iosignalfd_release(struct _iosignalfd *p)
+{
+	eventfd_ctx_put(p->eventfd);

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 375

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	list_del(&p->list);
+	kfree(p);
+}
+
+static bool
+iosignalfd_in_range(struct _iosignalfd *p, gpa_t addr, int len, const void *val)
+{
+	u64 _val;
+
+	if (!(addr == p->addr && len == p->length))

de-morgan's laws can help simplify this

Quoted 6 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 376

Quoted 2 lines
virt/kvm/eventfd.c +1 -0
+		/* address-range must be precise for a hit */

So there's apparently no way to specify that
you want 1,2, or 4 byte writes at address X?

No, they can be any legal size (1, 2, 4, or 8). The only limitation is that any overlap of two or more registrations have to be uniform in addr/len.

Quoted 25 lines
Quoted 25 lines
virt/kvm/eventfd.c +24 -0
+		return false;
+
+	if (p->wildcard)
+		/* all else equal, wildcard is always a hit */
+		return true;
+
+	/* otherwise, we have to actually compare the data */
+
+	BUG_ON(!IS_ALIGNED((unsigned long)val, len));
+
+	switch (len) {
+	case 1:
+		_val = *(u8 *)val;
+		break;
+	case 2:
+		_val = *(u16 *)val;
+		break;
+	case 4:
+		_val = *(u32 *)val;
+		break;
+	case 8:
+		_val = *(u64 *)val;
+		break;
+	default:
Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 404

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+		return false;
+	}
+
+	return _val == p->match ? true : false;

Life be simpler if we use an 8 byte array for match and just do memcmp here.

You would need to use an n-byte array, technically (to avoid endian issues). As mentioned earlier, I already did it that way in earlier versions but Avi wanted to see it this current (u64 based) way.

Quoted 11 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 409

Quoted 6 lines
virt/kvm/eventfd.c +5 -0
+}
+
+/*
+ * MMIO/PIO writes trigger an event if the addr/val match
+ */

single line comment can look like this:
/* MMIO/PIO writes trigger an event if the addr/val match */

Ack

Quoted 28 lines
Quoted 28 lines
virt/kvm/eventfd.c +28 -0
+static int
+iosignalfd_write(struct kvm_io_device *this, gpa_t addr, int len,
+		 const void *val)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+
+	if (!iosignalfd_in_range(p, addr, len, val))
+		return -EOPNOTSUPP;
+
+	eventfd_signal(p->eventfd, 1);
+	return 0;
+}
+
+/*
+ * This function is called as KVM is completely shutting down.  We do not
+ * need to worry about locking just nuke anything we have as quickly as possible
+ */
+static void
+iosignalfd_destructor(struct kvm_io_device *this)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+
+	iosignalfd_release(p);
+}
+
+static const struct kvm_io_device_ops iosignalfd_ops = {
+	.write      = iosignalfd_write,
+	.destructor = iosignalfd_destructor,
Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 441

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+};
+
+static bool
+iosignalfd_overlap(struct _iosignalfd *lhs, struct _iosignalfd *rhs)

this checks both region overlap and data collision. better split into two helpers?

Why?

Quoted 11 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 447

Quoted 7 lines
virt/kvm/eventfd.c +6 -0
+{
+	/*
+	 * Check for completely non-overlapping regions.  We can simply
+	 * return "false" for non-overlapping regions and be done with
+	 * it.
+	 */

done with it -> ignore the value

I think that is a valid expression (at least here in the states), but ok. Note that "false" means we are accepting the request, not ignoring any value. I will construct a better comment either way.

Quoted 9 lines

Review static void __exit irqfd_module_exit(void) · line 449

Quoted 3 lines
(quoted diff) +2 -0
+	if ((rhs->addr + rhs->length) <= lhs->addr)
+		return false;

rhs->addr + rhs->length <= lhs->addr
is not less clear, as precedence for simple math
follows the familiar rules from school.

Yes, but the "eye compiler" isn't as efficient as a machine driven tool. ;) The annotation is for the readers benefit (or at least me), not technical/mathematical correctness.

But whatever, I'll take it out.

Quoted 7 lines

Review static void __exit irqfd_module_exit(void) · line 451

Quoted 3 lines
(quoted diff) +2 -0
+
+	if ((lhs->addr + lhs->length) <= rhs->addr)

this math can overflow.

Well, we should probably have vetted that during assign since addr+length that overflows is not a valid region. I will put a check in for that.

Review

Quoted 9 lines

Review static void __exit irqfd_module_exit(void) · line 452

Quoted 2 lines
(quoted diff) +1 -0
+		return false;

or shorter:

(quoted diff) +0 -0
 	if (rhs->addr + rhs->length <= lhs->addr ||
 	    lhs->addr + lhs->length <= rhs->addr)
           return true;

Ok

Quoted 8 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void)

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+
+	/*
+	 * If we get here, we know there is *some* overlap, but we don't
+	 * yet know how much.

how much?

Well, as stated we don't know yet.

Quoted 7 lines
Quoted 3 lines

Make sure its a "precise" overlap, or

precise overlap -> address/len pairs match

Precisely.

Quoted 8 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+	 * its rejected as incompatible
+	 */

"rejected" does not seem to make sense in the context of a boolean function

Why? true = rejected, false = accepted. Seems boolean to me. Whats wrong with that?

Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 464

Quoted 7 lines
virt/kvm/eventfd.c +6 -0
+	if (lhs->addr != rhs->addr)
+		return true;
+
+	if (lhs->length != rhs->length)
+		return true;
+

or shorter:

Quoted 3 lines
	if (lhs->addr != rhs->addr || lhs->length != rhs->length)
           return true;

Ok

Quoted 19 lines
Quoted 16 lines
virt/kvm/eventfd.c +13 -0
+	/*
+	 * If we get here, the request should be a precise overlap
+	 * between rhs+lhs.  The only thing left to check is for
+	 * data-match overlap.  If the data match is distinctly different
+	 * we can allow the two to co-exist.  Any kind of wild-card
+	 * consitutes an incompatible range, so reject any wild-cards,
+	 * or if the match token is identical.
+	 */
+	if (lhs->wildcard || rhs->wildcard || lhs->match == rhs->match)
+		return true;
+
+	return false;
+}
Quoted 7 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+/* assumes kvm->slots_lock write-lock held */

it seems you only need read lock?

The caller needs write-lock, so we just inherit that state. I can update the comment though (I just ran a find/replace on "kvm->lock held" while updating to your new interface, thus the vague comment)

Quoted 4 lines
Quoted 4 lines
virt/kvm/eventfd.c +4 -0
+static bool
+iosignalfd_check_collision(struct kvm *kvm, struct _iosignalfd *p)
+{
+	struct _iosignalfd *_p;
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 486

Quoted 4 lines
virt/kvm/eventfd.c +3 -0
+
+	list_for_each_entry(_p, &kvm->iosignalfds, list)
+		if (iosignalfd_overlap(_p, p))

This looks wrong: let's assume I want one signal with length 1 and one with length 2 at address 0. They never trigger together, so it should be ok to have 2 such devices.

We have previously decided to not support mis-matched overlaps. It's more complicated to handle, and there isn't a compelling use-case for it that I am aware of.

Quoted 25 lines
Quoted 25 lines
virt/kvm/eventfd.c +24 -0
+			return true;
+
+	return false;
+}
+
+static int
+kvm_assign_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	int                       pio = args->flags & KVM_IOSIGNALFD_FLAG_PIO;
+	struct kvm_io_bus        *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+	struct _iosignalfd       *p;
+	struct eventfd_ctx       *eventfd;
+	int                       ret;
+
+	switch (args->len) {
+	case 1:
+	case 2:
+	case 4:
+	case 8:
+		break;
+	default:
+		return -EINVAL;
+	}
+
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 513

Quoted 4 lines
virt/kvm/eventfd.c +3 -0
+	eventfd = eventfd_ctx_fdget(args->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);

since this eventfd is kept around indefinitely, we should keep the file * around as well, so that this eventfd is accounted for properly with # of open files limit set by the admin.

I agree. The fact that I am missing that is a side-effect to the recent change in eventfd-upstream. If I acquire both a file* and ctx* and hold them, it should work around the issue, but perhaps we should let the eventfd interface handle this.

Quoted 92 lines
Quoted 7 lines
virt/kvm/eventfd.c +5 -0
+
+	p = kzalloc(sizeof(*p), GFP_KERNEL);
+	if (!p) {
+		ret = -ENOMEM;
+		goto fail;

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 528

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	}
+
+	INIT_LIST_HEAD(&p->list);
+	p->addr    = args->addr;
+	p->length  = args->len;
+	p->eventfd = eventfd;
+
+	/*
+	 * A trigger address is optional, otherwise this is a wildcard
+	 */

A single line comment can look like this:

	/* A trigger address is optional, otherwise this is a wildcard */

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 530

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+	if (args->flags & KVM_IOSIGNALFD_FLAG_TRIGGER)
+		p->match = args->trigger;

For len < 8, high bits in trigger are ignored. it's better to check that they are 0, less confusing if the user e.g. gets the endian-ness wrong.

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 536

Quoted 10 lines
virt/kvm/eventfd.c +6 -0
+	else
+		p->wildcard = true;
+
 
 
 
+	down_write(&kvm->slots_lock);
+
+	/* Verify that there isnt a match already */

Better to put documentation to where function is declared, not where it is used.

Quoted 8 lines
virt/kvm/eventfd.c +7 -0
+	if (iosignalfd_check_collision(kvm, p)) {
+		ret = -EEXIST;
+		goto unlock_fail;
+	}
+
+	kvm_iodevice_init(&p->dev, &iosignalfd_ops);
+

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 553

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	ret = __kvm_io_bus_register_dev(bus, &p->dev);
+	if (ret < 0)
+		goto unlock_fail;
+
+	list_add_tail(&p->list, &kvm->iosignalfds);
+
+	up_write(&kvm->slots_lock);
+
+	return 0;
+

we probably do not need an empty line after each line of code here

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 560

Quoted 8 lines
virt/kvm/eventfd.c +7 -0
+unlock_fail:
+	up_write(&kvm->slots_lock);
+fail:
+	/*
+	 * it would have never made it to the list in the failure path, so
+	 * we dont need to worry about removing it
+	 */

of course: you goto fail before list_add
can just kill this comment

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 565

Quoted 6 lines
virt/kvm/eventfd.c +5 -0
+	kfree(p);
+
+	eventfd_ctx_put(eventfd);
+
+	return ret;

we probably do not need an empty line after each line of code here

Quoted 7 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 369

Quoted 4 lines
virt/kvm/eventfd.c +3 -0
+}
+
+

two empty lines

Ack

Quoted 23 lines
Quoted 9 lines
virt/kvm/eventfd.c +7 -0
+static int
+kvm_deassign_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	int                       pio = args->flags & KVM_IOSIGNALFD_FLAG_PIO;
+	struct kvm_io_bus        *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus;
+	struct _iosignalfd       *p, *tmp;
+	struct eventfd_ctx       *eventfd;

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 585

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	int                       ret = 0;
+
+	eventfd = eventfd_ctx_fdget(args->fd);
+	if (IS_ERR(eventfd))
+		return PTR_ERR(eventfd);
+
+	down_write(&kvm->slots_lock);
+
+	list_for_each_entry_safe(p, tmp, &kvm->iosignalfds, list) {
+

kill empty line

Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 587

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+		if (p->eventfd != eventfd)
+			continue;

So for deassign, you ignore all arguments besides fd? Is this intentional? Looks strange - think of multiple addresses triggering a single eventfd. But if so, it's better to have a different ioctl with just the fields we need.

Hmm... I suspect the check for a range-match got lost along the way. I agree we should probably qualify this with more than just the eventfd.

Quoted 8 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 590

Quoted 5 lines
virt/kvm/eventfd.c +3 -0
+
+		__kvm_io_bus_unregister_dev(bus, &p->dev);
+		iosignalfd_release(p);

a single deassign removed multiple irqfds? Looks ugly.

Avi requested this general concept.

Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +2 -0
+	}
+

kill empty line

Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 566

Quoted 7 lines
virt/kvm/eventfd.c +6 -0
+	up_write(&kvm->slots_lock);
+
+	eventfd_ctx_put(eventfd);
+
+	return ret;
+}

return error status if no device was found?

Ack

Quoted 13 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 604

Quoted 8 lines
virt/kvm/eventfd.c +6 -0
+
+int
+kvm_iosignalfd(struct kvm *kvm, struct kvm_iosignalfd *args)
+{
+	if (args->flags & KVM_IOSIGNALFD_FLAG_DEASSIGN)
+		return kvm_deassign_iosignalfd(kvm, args);

Better check that only known flag values are present. Otherwise when you add more flags things just break silently.

Ok

Quoted 40 lines
Quoted 18 lines
virt/kvm/eventfd.c +3 -0
+
+	return kvm_assign_iosignalfd(kvm, args);
+}
virt/kvm/kvm_main.c +1 -1
index 11595c7..5ac381b 100644
@@ -979,7 +979,7 @@ static struct kvm *kvm_create_vm(void)
 	spin_lock_init(&kvm->mmu_lock);
 	spin_lock_init(&kvm->requests_lock);
 	kvm_io_bus_init(&kvm->pio_bus);
-	kvm_irqfd_init(kvm);
+	kvm_eventfd_init(kvm);
 	mutex_init(&kvm->lock);
 	mutex_init(&kvm->irq_lock);
 	kvm_io_bus_init(&kvm->mmio_bus);

virt/kvm/kvm_main.c static long kvm_vm_ioctl(struct file *filp, · line 2278

Quoted 8 lines
virt/kvm/kvm_main.c +4 -0
@@ -2271,6 +2271,15 @@ static long kvm_vm_ioctl(struct file *filp,
 		r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
 		break;
 	}
+	case KVM_IOSIGNALFD: {
+		struct kvm_iosignalfd data;
+
+		r = -EFAULT;
 

this trick is nice, it saves a line of code for the closing brace but why waste it on an empty line above then?

Quoted 9 lines
virt/kvm/kvm_main.c +5 -0
+		if (copy_from_user(&data, argp, sizeof data))
+			goto out;
+		r = kvm_iosignalfd(kvm, &data);
+		break;
+	}
 #ifdef CONFIG_KVM_APIC_ARCHITECTURE
 	case KVM_SET_BOOT_CPU_ID:

r = 0;

#18 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 20 lines · Gregory Haskins
Quoted 7 lines · Michael S. Tsirkin

Some comments below. Sorry, I know it's late in the series, but previously I've been too confused with complicated locking to notice anything else :(.

On Mon, Jul 06, 2009 at 04:33:21PM -0400, Gregory Haskins wrote:

Quoted 11 lines

include/linux/kvm.h struct kvm_guest_debug { · line 315

Quoted 6 lines
include/linux/kvm.h +5 -0
+#define KVM_IOSIGNALFD_FLAG_PIO       (1 << 1) /* is a pio (otherwise mmio) */
+#define KVM_IOSIGNALFD_FLAG_DEASSIGN  (1 << 2)
+
+struct kvm_iosignalfd {
+	__u64 trigger;

for length <8, it's the 8*len least significant bits that are used, right? That's a bit ugly ... Maybe just put an 8 byte array here instead, then the first len bytes are valid.

Quoted 4 lines

The original series uses an array that I kmalloc'ed to size, or left it NULL for a wildcard. Avi didn't like this and requested a u64 for all values. I don't care either way, but since you two are asking for conflicting designs, I will let you debate.

It turns out the io bus will be changed in the future. Let's just document the usage, and check that unused bits are zeroed.

Quoted 8 lines
Quoted 6 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 353

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+	struct kvm_io_device dev;
+	int                  wildcard:1;

don't use bitfields

bool?

sure

Quoted 51 lines
Quoted 11 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 409

Quoted 6 lines
virt/kvm/eventfd.c +5 -0
+}
+
+/*
+ * MMIO/PIO writes trigger an event if the addr/val match
+ */

single line comment can look like this:
/* MMIO/PIO writes trigger an event if the addr/val match */

Ack

Quoted 28 lines
Quoted 28 lines
virt/kvm/eventfd.c +28 -0
+static int
+iosignalfd_write(struct kvm_io_device *this, gpa_t addr, int len,
+		 const void *val)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+
+	if (!iosignalfd_in_range(p, addr, len, val))
+		return -EOPNOTSUPP;
+
+	eventfd_signal(p->eventfd, 1);
+	return 0;
+}
+
+/*
+ * This function is called as KVM is completely shutting down.  We do not
+ * need to worry about locking just nuke anything we have as quickly as possible
+ */
+static void
+iosignalfd_destructor(struct kvm_io_device *this)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+
+	iosignalfd_release(p);
+}
+
+static const struct kvm_io_device_ops iosignalfd_ops = {
+	.write      = iosignalfd_write,
+	.destructor = iosignalfd_destructor,
Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 441

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+};
+
+static bool
+iosignalfd_overlap(struct _iosignalfd *lhs, struct _iosignalfd *rhs)

this checks both region overlap and data collision. better split into two helpers?

Quoted 1 line

Why?

Because it says iosignalfd_overlap but that's not what it does?

Quoted 11 lines
Quoted 11 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 447

Quoted 7 lines
virt/kvm/eventfd.c +6 -0
+{
+	/*
+	 * Check for completely non-overlapping regions.  We can simply
+	 * return "false" for non-overlapping regions and be done with
+	 * it.
+	 */

done with it -> ignore the value

Quoted 1 line

I think that is a valid expression (at least here in the states),

I'm always interested in improving my english :) here's what I thought:

"done with it" says we skip the rest of the function. "ignore the value" says skip the value check. So I was trying to say let's be more specific.

Isn't that what it means?

Quoted 3 lines

but
ok. Note that "false" means we are accepting the request, not ignoring any value. I will construct a better comment either way.

Maybe name a function in a way that makes this explicit?

Quoted 10 lines
Quoted 7 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+	if ((lhs->addr + lhs->length) <= rhs->addr)

this math can overflow.

Well, we should probably have vetted that during assign since addr+length that overflows is not a valid region. I will put a check in for that.

add = ~0x0ULL, len = 1 should be valid.
You'll have to make the math not overflow.

Quoted 9 lines
Quoted 8 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void)

Quoted 5 lines
virt/kvm/eventfd.c +4 -0
+
+	/*
+	 * If we get here, we know there is *some* overlap, but we don't
+	 * yet know how much.

how much?

Well, as stated we don't know yet.

So why tell me :)?
What I mean is this statement (especially the the part of the statement after the comma) does not add useful information.

Quoted 9 lines
Quoted 7 lines
Quoted 3 lines

Make sure its a "precise" overlap, or

precise overlap -> address/len pairs match

Precisely.

so say so :)

Quoted 10 lines
Quoted 8 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+	 * its rejected as incompatible
+	 */

"rejected" does not seem to make sense in the context of a boolean function

Why? true = rejected, false = accepted. Seems boolean to me.

How should I know that? Rename it to iosignalfd_rejected?

Quoted 2 lines

Whats
wrong with that?

If you want to return 0 on success, != 0 on failure, make the function int.

Quoted 11 lines
Quoted 7 lines

Review

Quoted 3 lines
(quoted diff) +2 -0
+
+/* assumes kvm->slots_lock write-lock held */

it seems you only need read lock?

The caller needs write-lock, so we just inherit that state. I can update the comment though (I just ran a find/replace on "kvm->lock held" while updating to your new interface, thus the vague comment)

I guess so.

Quoted 14 lines
Quoted 4 lines
Quoted 4 lines
virt/kvm/eventfd.c +4 -0
+static bool
+iosignalfd_check_collision(struct kvm *kvm, struct _iosignalfd *p)
+{
+	struct _iosignalfd *_p;
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 486

Quoted 4 lines
virt/kvm/eventfd.c +3 -0
+
+	list_for_each_entry(_p, &kvm->iosignalfds, list)
+		if (iosignalfd_overlap(_p, p))

This looks wrong: let's assume I want one signal with length 1 and one with length 2 at address 0. They never trigger together, so it should be ok to have 2 such devices.

Quoted 3 lines

We have previously decided to not support mis-matched overlaps. It's more complicated to handle, and there isn't a compelling use-case for it that I am aware of.

That's not what I propose. By all means len = X should only catch len = X and not len = X - 1.

However, I think it makes sense to
allow both len = 2 and len = 1 at the same address even though they seem to overlap. And all you really need to do is simplify the code: replace the tricky overlap logic with simple

if (rhs->addr == lhs->addr && rhs->len == lhs->len)
reject
else
accept

(+add wildcard thing)

Quoted 22 lines
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 587

Quoted 3 lines
virt/kvm/eventfd.c +2 -0
+		if (p->eventfd != eventfd)
+			continue;

So for deassign, you ignore all arguments besides fd? Is this intentional? Looks strange - think of multiple addresses triggering a single eventfd. But if so, it's better to have a different ioctl with just the fields we need.

Hmm... I suspect the check for a range-match got lost along the way. I agree we should probably qualify this with more than just the eventfd.

Quoted 8 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 590

Quoted 5 lines
virt/kvm/eventfd.c +3 -0
+
+		__kvm_io_bus_unregister_dev(bus, &p->dev);
+		iosignalfd_release(p);

a single deassign removed multiple irqfds? Looks ugly.

Quoted 1 line

Avi requested this general concept.

Really? Avi, could you explain? I would think each assign needs to be matched with 1 deassign. No?

Signature · 1 line
MST
#19 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 8 lines · Michael S. Tsirkin
Quoted 8 lines
Quoted 8 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 432

Quoted 5 lines
virt/kvm/eventfd.c +3 -0
+
+		__kvm_io_bus_unregister_dev(bus,&p->dev);
+		iosignalfd_release(p);

a single deassign removed multiple irqfds? Looks ugly.

Quoted 6 lines
Quoted 2 lines

Avi requested this general concept.

Really? Avi, could you explain? I would think each assign needs to be matched with 1 deassign. No?

Doesn't it follow naturally? How can a single deassign remove multiple fds (unless all were registered with exactly the same arguments)?

Maybe we should instead detect that the duplicate iosignaldfds are registered.

Note that we do need to allow the same fd to be multiple times, but not with exactly the same address/match etc.

Signature · 1 line
error compiling committee.c: too many arguments to function
#20 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

Quoted 9 lines · Avi Kivity
Quoted 8 lines · Michael S. Tsirkin
Quoted 8 lines
Quoted 8 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 432

Quoted 5 lines
virt/kvm/eventfd.c +3 -0
+
+		__kvm_io_bus_unregister_dev(bus,&p->dev);
+		iosignalfd_release(p);

a single deassign removed multiple irqfds? Looks ugly.

Quoted 8 lines
Quoted 6 lines
Quoted 2 lines

Avi requested this general concept.

Really? Avi, could you explain? I would think each assign needs to be matched with 1 deassign. No?

Doesn't it follow naturally?

Yes.

Quoted 7 lines

How can a single deassign remove multiple
fds (unless all were registered with exactly the same arguments)? Maybe we should instead detect that the duplicate iosignaldfds are registered.

Note that we do need to allow the same fd to be multiple times, but not with exactly the same address/match etc.

Signature · 1 line
MST
#21 lore raw

Re: [KVM PATCH v9 2/2] KVM: add iosignalfd support

In reply to Michael S. Tsirkin
Quoted 102 lines · Michael S. Tsirkin
Quoted 22 lines · Gregory Haskins
Quoted 8 lines · Michael S. Tsirkin

Some comments below. Sorry, I know it's late in the series, but previously I've been too confused with complicated locking to notice anything else :(.

On Mon, Jul 06, 2009 at 04:33:21PM -0400, Gregory Haskins wrote:

Quoted 12 lines

include/linux/kvm.h struct kvm_guest_debug { · line 315

Quoted 7 lines
include/linux/kvm.h +5 -0
+#define KVM_IOSIGNALFD_FLAG_PIO       (1 << 1) /* is a pio (otherwise mmio) */
+#define KVM_IOSIGNALFD_FLAG_DEASSIGN  (1 << 2)
+
+struct kvm_iosignalfd {
+	__u64 trigger;

for length <8, it's the 8*len least significant bits that are used, right? That's a bit ugly ... Maybe just put an 8 byte array here instead, then the first len bytes are valid.

Quoted 5 lines

The original series uses an array that I kmalloc'ed to size, or left it NULL for a wildcard. Avi didn't like this and requested a u64 for all values. I don't care either way, but since you two are asking for conflicting designs, I will let you debate.

It turns out the io bus will be changed in the future. Let's just document the usage, and check that unused bits are zeroed.

Quoted 9 lines
Quoted 7 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 353

Quoted 4 lines
virt/kvm/eventfd.c +2 -0
+	struct kvm_io_device dev;
+	int                  wildcard:1;

don't use bitfields

bool?

sure

Quoted 54 lines
Quoted 12 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 409

Quoted 7 lines
virt/kvm/eventfd.c +5 -0
+}
+
+/*
+ * MMIO/PIO writes trigger an event if the addr/val match
+ */

single line comment can look like this:
/* MMIO/PIO writes trigger an event if the addr/val match */

Ack

Quoted 39 lines
Quoted 24 lines
virt/kvm/eventfd.c +22 -0
+static int
+iosignalfd_write(struct kvm_io_device *this, gpa_t addr, int len,
+		 const void *val)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+
+	if (!iosignalfd_in_range(p, addr, len, val))
+		return -EOPNOTSUPP;
+
+	eventfd_signal(p->eventfd, 1);
+	return 0;
+}
+
+/*
+ * This function is called as KVM is completely shutting down.  We do not
+ * need to worry about locking just nuke anything we have as quickly as possible
+ */
+static void
+iosignalfd_destructor(struct kvm_io_device *this)
+{
+	struct _iosignalfd *p = to_iosignalfd(this);
+

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 441

Quoted 10 lines
virt/kvm/eventfd.c +10 -0
+	iosignalfd_release(p);
+}
+
+static const struct kvm_io_device_ops iosignalfd_ops = {
+	.write      = iosignalfd_write,
+	.destructor = iosignalfd_destructor,
+};
+
+static bool
+iosignalfd_overlap(struct _iosignalfd *lhs, struct _iosignalfd *rhs)

this checks both region overlap and data collision. better split into two helpers?

Quoted 5 lines
Quoted 2 lines

Why?

Because it says iosignalfd_overlap but that's not what it does?

It would seem to me that that is exactly what it does. Given that I wrote it, I'm sure my perspective is skewed, so let me turn it around on you. Why do you think "overlap" is inaccurate?

Quoted 13 lines
Quoted 13 lines
Quoted 13 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 447

Quoted 9 lines
virt/kvm/eventfd.c +6 -0
+{
+	/*
+	 * Check for completely non-overlapping regions.  We can simply
+	 * return "false" for non-overlapping regions and be done with
+	 * it.
+	 */

done with it -> ignore the value

Quoted 4 lines
Quoted 2 lines

I think that is a valid expression (at least here in the states),

I'm always interested in improving my english :)

I'm sure its slang and not proper english, so don't take it too seriously ;)

Quoted 8 lines

here's what I thought:

"done with it" says we skip the rest of the function. "ignore the value" says skip the value check. So I was trying to say let's be more specific.

Isn't that what it means?

Yes, you are right. I thought you were saying the comment was somehow wrong. But I see now you are just clarifying it.

Quoted 9 lines
Quoted 5 lines

but
ok. Note that "false" means we are accepting the request, not ignoring any value. I will construct a better comment either way.

Maybe name a function in a way that makes this explicit?

Sure

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +2 -0
+
+	if ((lhs->addr + lhs->length) <= rhs->addr)

this math can overflow.

Quoted 9 lines
Quoted 4 lines

Well, we should probably have vetted that during assign since addr+length that overflows is not a valid region. I will put a check in for that.

add = ~0x0ULL, len = 1 should be valid.
You'll have to make the math not overflow.

Yes, understood.

Quoted 9 lines
Quoted 9 lines
Quoted 9 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void)

Quoted 6 lines
virt/kvm/eventfd.c +4 -0
+
+	/*
+	 * If we get here, we know there is *some* overlap, but we don't
+	 * yet know how much.

how much?

Quoted 7 lines
Quoted 2 lines

Well, as stated we don't know yet.

So why tell me :)?
What I mean is this statement (especially the the part of the statement after the comma) does not add useful information.

What I was trying to convey is that the next section of code tries to narrow the amount of overlap down further. If it bothers you, I will just remove the comment.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines

Make sure its a "precise" overlap, or

Quoted 9 lines
Quoted 6 lines
Quoted 4 lines

precise overlap -> address/len pairs match

Precisely.

so say so :)

Ok

Quoted 10 lines
Quoted 10 lines
Quoted 10 lines

Review

Quoted 5 lines
(quoted diff) +2 -0
+	 * its rejected as incompatible
+	 */

"rejected" does not seem to make sense in the context of a boolean function

Quoted 5 lines
Quoted 2 lines

Why? true = rejected, false = accepted. Seems boolean to me.

How should I know that? Rename it to iosignalfd_rejected?

Dunno.. Seems clear to me already: collision = true if overlap = true. collision = reject the request to create a new object on grounds that we already have one in that spot. I don't really care what we call it, but I don't currently see a superior way to describe what I am doing that isn't just a synonym.

Quoted 9 lines
Quoted 4 lines

Whats
wrong with that?

If you want to return 0 on success, != 0 on failure, make the function int.

I don't want that. I want to know true or false on whether we have a collision. A collision is defined by whether there is overlap with any existing object.

Quoted 43 lines
Quoted 8 lines
Quoted 8 lines

Review

Quoted 4 lines
(quoted diff) +2 -0
+
+/* assumes kvm->slots_lock write-lock held */

it seems you only need read lock?

Quoted 4 lines

The caller needs write-lock, so we just inherit that state. I can update the comment though (I just ran a find/replace on "kvm->lock held" while updating to your new interface, thus the vague comment)

I guess so.

Quoted 14 lines
Quoted 4 lines
Quoted 4 lines
virt/kvm/eventfd.c +4 -0
+static bool
+iosignalfd_check_collision(struct kvm *kvm, struct _iosignalfd *p)
+{
+	struct _iosignalfd *_p;
Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 486

Quoted 5 lines
virt/kvm/eventfd.c +3 -0
+
+	list_for_each_entry(_p, &kvm->iosignalfds, list)
+		if (iosignalfd_overlap(_p, p))

This looks wrong: let's assume I want one signal with length 1 and one with length 2 at address 0. They never trigger together, so it should be ok to have 2 such devices.

Quoted 4 lines

We have previously decided to not support mis-matched overlaps. It's more complicated to handle, and there isn't a compelling use-case for it that I am aware of.

That's not what I propose. By all means len = X should only catch len = X and not len = X - 1.

However, I think it makes sense to
allow both len = 2 and len = 1 at the same address even though they seem to overlap. And all you really need to do is simplify the code: replace the tricky overlap logic with simple

Quoted 7 lines

if (rhs->addr == lhs->addr && rhs->len == lhs->len)
reject
else
accept

(+add wildcard thing)

Hmm..ok. I can't imagine anyone using that, but it seems simple enough to implement.

Quoted 32 lines
Quoted 25 lines
Quoted 11 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 587

Quoted 5 lines
virt/kvm/eventfd.c +2 -0
+		if (p->eventfd != eventfd)
+			continue;

So for deassign, you ignore all arguments besides fd? Is this intentional? Looks strange - think of multiple addresses triggering a single eventfd. But if so, it's better to have a different ioctl with just the fields we need.

Hmm... I suspect the check for a range-match got lost along the way. I agree we should probably qualify this with more than just the eventfd.

Quoted 10 lines

virt/kvm/eventfd.c static void __exit irqfd_module_exit(void) · line 590

Quoted 7 lines
virt/kvm/eventfd.c +3 -0
+
+		__kvm_io_bus_unregister_dev(bus, &p->dev);
+		iosignalfd_release(p);

a single deassign removed multiple irqfds? Looks ugly.

Quoted 2 lines

Avi requested this general concept.

Really? Avi, could you explain? I would think each assign needs to be matched with 1 deassign. No?

#22 lore raw
In reply to Gregory Haskins
Quoted 5 lines · Gregory Haskins

(Applies to kvm.git/master:c5b13264e)

This is v9 of the series. For more details, please see the header to patch 2/2.

Quoted 9 lines

This series has been tested against the kvm-eventfd unit test, and appears to be functioning properly. You can download this test here:

ftp://ftp.novell.com/dev/ghaskins/kvm-eventfd.tar.bz2

(Note: unit test has been updated to accomodate new feature-set)

Please consider for inclusion to kvm.git

Looks good to me, but would appreciate a second opinion from Michael or anyone else who wants to review.

Signature · 1 line
error compiling committee.c: too many arguments to function