Skip to content

Commit 090b7af

Browse files
Gregory Haskinsavikivity
authored andcommitted
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 Signed-off-by: Gregory Haskins <[email protected]> Acked-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Avi Kivity <[email protected]>
1 parent fef07aa commit 090b7af

File tree

6 files changed

+79
-15
lines changed

6 files changed

+79
-15
lines changed

arch/x86/kvm/i8254.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -605,6 +605,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
605605
{
606606
struct kvm_pit *pit;
607607
struct kvm_kpit_state *pit_state;
608+
int ret;
608609

609610
pit = kzalloc(sizeof(struct kvm_pit), GFP_KERNEL);
610611
if (!pit)
@@ -639,14 +640,29 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags)
639640
kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
640641

641642
kvm_iodevice_init(&pit->dev, &pit_dev_ops);
642-
__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
643+
ret = __kvm_io_bus_register_dev(&kvm->pio_bus, &pit->dev);
644+
if (ret < 0)
645+
goto fail;
643646

644647
if (flags & KVM_PIT_SPEAKER_DUMMY) {
645648
kvm_iodevice_init(&pit->speaker_dev, &speaker_dev_ops);
646-
__kvm_io_bus_register_dev(&kvm->pio_bus, &pit->speaker_dev);
649+
ret = __kvm_io_bus_register_dev(&kvm->pio_bus,
650+
&pit->speaker_dev);
651+
if (ret < 0)
652+
goto fail_unregister;
647653
}
648654

649655
return pit;
656+
657+
fail_unregister:
658+
__kvm_io_bus_unregister_dev(&kvm->pio_bus, &pit->dev);
659+
660+
fail:
661+
if (pit->irq_source_id >= 0)
662+
kvm_free_irq_source_id(kvm, pit->irq_source_id);
663+
664+
kfree(pit);
665+
return NULL;
650666
}
651667

652668
void kvm_free_pit(struct kvm *kvm)

arch/x86/kvm/i8259.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,6 +539,8 @@ static const struct kvm_io_device_ops picdev_ops = {
539539
struct kvm_pic *kvm_create_pic(struct kvm *kvm)
540540
{
541541
struct kvm_pic *s;
542+
int ret;
543+
542544
s = kzalloc(sizeof(struct kvm_pic), GFP_KERNEL);
543545
if (!s)
544546
return NULL;
@@ -555,6 +557,11 @@ struct kvm_pic *kvm_create_pic(struct kvm *kvm)
555557
* Initialize PIO device
556558
*/
557559
kvm_iodevice_init(&s->dev, &picdev_ops);
558-
kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
560+
ret = kvm_io_bus_register_dev(kvm, &kvm->pio_bus, &s->dev);
561+
if (ret < 0) {
562+
kfree(s);
563+
return NULL;
564+
}
565+
559566
return s;
560567
}

include/linux/kvm_host.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,14 @@ int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, int len,
6464
const void *val);
6565
int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len,
6666
void *val);
67-
void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
67+
int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
68+
struct kvm_io_device *dev);
69+
int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
70+
struct kvm_io_device *dev);
71+
void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
72+
struct kvm_io_device *dev);
73+
void kvm_io_bus_unregister_dev(struct kvm *kvm, struct kvm_io_bus *bus,
6874
struct kvm_io_device *dev);
69-
void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
70-
struct kvm_io_device *dev);
7175

7276
struct kvm_vcpu {
7377
struct kvm *kvm;

virt/kvm/coalesced_mmio.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ static const struct kvm_io_device_ops coalesced_mmio_ops = {
9292
int kvm_coalesced_mmio_init(struct kvm *kvm)
9393
{
9494
struct kvm_coalesced_mmio_dev *dev;
95+
int ret;
9596

9697
dev = kzalloc(sizeof(struct kvm_coalesced_mmio_dev), GFP_KERNEL);
9798
if (!dev)
@@ -100,9 +101,12 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)
100101
kvm_iodevice_init(&dev->dev, &coalesced_mmio_ops);
101102
dev->kvm = kvm;
102103
kvm->coalesced_mmio_dev = dev;
103-
kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
104104

105-
return 0;
105+
ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev);
106+
if (ret < 0)
107+
kfree(dev);
108+
109+
return ret;
106110
}
107111

108112
int kvm_vm_ioctl_register_coalesced_mmio(struct kvm *kvm,

virt/kvm/ioapic.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,7 @@ static const struct kvm_io_device_ops ioapic_mmio_ops = {
342342
int kvm_ioapic_init(struct kvm *kvm)
343343
{
344344
struct kvm_ioapic *ioapic;
345+
int ret;
345346

346347
ioapic = kzalloc(sizeof(struct kvm_ioapic), GFP_KERNEL);
347348
if (!ioapic)
@@ -350,7 +351,10 @@ int kvm_ioapic_init(struct kvm *kvm)
350351
kvm_ioapic_reset(ioapic);
351352
kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);
352353
ioapic->kvm = kvm;
353-
kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
354-
return 0;
354+
ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev);
355+
if (ret < 0)
356+
kfree(ioapic);
357+
358+
return ret;
355359
}
356360

virt/kvm/kvm_main.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2533,21 +2533,50 @@ int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val)
25332533
return -EOPNOTSUPP;
25342534
}
25352535

2536-
void kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
2536+
int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus,
25372537
struct kvm_io_device *dev)
25382538
{
2539+
int ret;
2540+
25392541
down_write(&kvm->slots_lock);
2540-
__kvm_io_bus_register_dev(bus, dev);
2542+
ret = __kvm_io_bus_register_dev(bus, dev);
25412543
up_write(&kvm->slots_lock);
2544+
2545+
return ret;
25422546
}
25432547

25442548
/* An unlocked version. Caller must have write lock on slots_lock. */
2545-
void __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
2546-
struct kvm_io_device *dev)
2549+
int __kvm_io_bus_register_dev(struct kvm_io_bus *bus,
2550+
struct kvm_io_device *dev)
25472551
{
2548-
BUG_ON(bus->dev_count > (NR_IOBUS_DEVS-1));
2552+
if (bus->dev_count > NR_IOBUS_DEVS-1)
2553+
return -ENOSPC;
25492554

25502555
bus->devs[bus->dev_count++] = dev;
2556+
2557+
return 0;
2558+
}
2559+
2560+
void kvm_io_bus_unregister_dev(struct kvm *kvm,
2561+
struct kvm_io_bus *bus,
2562+
struct kvm_io_device *dev)
2563+
{
2564+
down_write(&kvm->slots_lock);
2565+
__kvm_io_bus_unregister_dev(bus, dev);
2566+
up_write(&kvm->slots_lock);
2567+
}
2568+
2569+
/* An unlocked version. Caller must have write lock on slots_lock. */
2570+
void __kvm_io_bus_unregister_dev(struct kvm_io_bus *bus,
2571+
struct kvm_io_device *dev)
2572+
{
2573+
int i;
2574+
2575+
for (i = 0; i < bus->dev_count; i++)
2576+
if (bus->devs[i] == dev) {
2577+
bus->devs[i] = bus->devs[--bus->dev_count];
2578+
break;
2579+
}
25512580
}
25522581

25532582
static struct notifier_block kvm_cpu_notifier = {

0 commit comments

Comments
 (0)