Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

KVM: destruct kvm_io_device while unregistering it from kvm_io_bus

Current usage of kvm_io_device requires users to destruct it with an extra
call of kvm_iodevice_destructor after the device gets unregistered from
kvm_io_bus. This is not necessary and can cause errors if a user forgot
to make the extra call.

Simplify the usage by combining kvm_iodevice_destructor into
kvm_io_bus_unregister_dev. This reduces LOCs a bit for users and can
avoid the leakage of destructing the device explicitly.

Signed-off-by: Wei Wang <wei.w.wang@intel.com>
Reviewed-by: Sean Christopherson <seanjc@google.com>
Link: https://lore.kernel.org/r/20230207123713.3905-2-wei.w.wang@intel.com
Signed-off-by: Sean Christopherson <seanjc@google.com>

authored by

Wei Wang and committed by
Sean Christopherson
5ea5ca3c 5f643e46

+17 -22
-6
include/kvm/iodev.h
··· 55 55 : -EOPNOTSUPP; 56 56 } 57 57 58 - static inline void kvm_iodevice_destructor(struct kvm_io_device *dev) 59 - { 60 - if (dev->ops->destructor) 61 - dev->ops->destructor(dev); 62 - } 63 - 64 58 #endif /* __KVM_IODEV_H__ */
+2 -7
virt/kvm/coalesced_mmio.c
··· 186 186 coalesced_mmio_in_range(dev, zone->addr, zone->size)) { 187 187 r = kvm_io_bus_unregister_dev(kvm, 188 188 zone->pio ? KVM_PIO_BUS : KVM_MMIO_BUS, &dev->dev); 189 - 190 - kvm_iodevice_destructor(&dev->dev); 191 - 192 189 /* 193 190 * On failure, unregister destroys all devices on the 194 - * bus _except_ the target device, i.e. coalesced_zones 195 - * has been modified. Bail after destroying the target 196 - * device, there's no need to restart the walk as there 197 - * aren't any zones left. 191 + * bus, including the target device. There's no need 192 + * to restart the walk as there aren't any zones left. 198 193 */ 199 194 if (r) 200 195 break;
-1
virt/kvm/eventfd.c
··· 931 931 bus = kvm_get_bus(kvm, bus_idx); 932 932 if (bus) 933 933 bus->ioeventfd_count--; 934 - ioeventfd_release(p); 935 934 ret = 0; 936 935 break; 937 936 }
+15 -8
virt/kvm/kvm_main.c
··· 5297 5297 } 5298 5298 #endif /* CONFIG_KVM_GENERIC_HARDWARE_ENABLING */ 5299 5299 5300 + static void kvm_iodevice_destructor(struct kvm_io_device *dev) 5301 + { 5302 + if (dev->ops->destructor) 5303 + dev->ops->destructor(dev); 5304 + } 5305 + 5300 5306 static void kvm_io_bus_destroy(struct kvm_io_bus *bus) 5301 5307 { 5302 5308 int i; ··· 5526 5520 int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, 5527 5521 struct kvm_io_device *dev) 5528 5522 { 5529 - int i, j; 5523 + int i; 5530 5524 struct kvm_io_bus *new_bus, *bus; 5531 5525 5532 5526 lockdep_assert_held(&kvm->slots_lock); ··· 5556 5550 rcu_assign_pointer(kvm->buses[bus_idx], new_bus); 5557 5551 synchronize_srcu_expedited(&kvm->srcu); 5558 5552 5559 - /* Destroy the old bus _after_ installing the (null) bus. */ 5553 + /* 5554 + * If NULL bus is installed, destroy the old bus, including all the 5555 + * attached devices. Otherwise, destroy the caller's device only. 5556 + */ 5560 5557 if (!new_bus) { 5561 5558 pr_err("kvm: failed to shrink bus, removing it completely\n"); 5562 - for (j = 0; j < bus->dev_count; j++) { 5563 - if (j == i) 5564 - continue; 5565 - kvm_iodevice_destructor(bus->range[j].dev); 5566 - } 5559 + kvm_io_bus_destroy(bus); 5560 + return -ENOMEM; 5567 5561 } 5568 5562 5563 + kvm_iodevice_destructor(dev); 5569 5564 kfree(bus); 5570 - return new_bus ? 0 : -ENOMEM; 5565 + return 0; 5571 5566 } 5572 5567 5573 5568 struct kvm_io_device *kvm_io_bus_get_dev(struct kvm *kvm, enum kvm_bus bus_idx,