diff options
| author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-12-23 14:35:24 -0200 | 
|---|---|---|
| committer | Marcelo Tosatti <mtosatti@redhat.com> | 2010-03-01 12:35:45 -0300 | 
| commit | e93f8a0f821e290ac5149830110a5f704db7a1fc (patch) | |
| tree | f88a5e97286031a8105d63a069a4131b74dab113 /virt | |
| parent | a983fb238728e1123177e8058d4f644b949a7d05 (diff) | |
| download | linux-e93f8a0f821e290ac5149830110a5f704db7a1fc.tar.bz2 | |
KVM: convert io_bus to SRCU
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'virt')
| -rw-r--r-- | virt/kvm/coalesced_mmio.c | 4 | ||||
| -rw-r--r-- | virt/kvm/eventfd.c | 8 | ||||
| -rw-r--r-- | virt/kvm/ioapic.c | 4 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 106 | 
4 files changed, 73 insertions, 49 deletions
| diff --git a/virt/kvm/coalesced_mmio.c b/virt/kvm/coalesced_mmio.c index d68e6c68e0ff..a736a93ca7b7 100644 --- a/virt/kvm/coalesced_mmio.c +++ b/virt/kvm/coalesced_mmio.c @@ -110,7 +110,9 @@ int kvm_coalesced_mmio_init(struct kvm *kvm)  	dev->kvm = kvm;  	kvm->coalesced_mmio_dev = dev; -	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &dev->dev); +	down_write(&kvm->slots_lock); +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &dev->dev); +	up_write(&kvm->slots_lock);  	if (ret < 0)  		goto out_free_dev; diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index a9d3fc6c681c..315a586ec4d5 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c @@ -463,7 +463,7 @@ static int  kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)  {  	int                       pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; -	struct kvm_io_bus        *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; +	enum kvm_bus              bus_idx = pio ? KVM_PIO_BUS : KVM_MMIO_BUS;  	struct _ioeventfd        *p;  	struct eventfd_ctx       *eventfd;  	int                       ret; @@ -518,7 +518,7 @@ kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)  	kvm_iodevice_init(&p->dev, &ioeventfd_ops); -	ret = __kvm_io_bus_register_dev(bus, &p->dev); +	ret = kvm_io_bus_register_dev(kvm, bus_idx, &p->dev);  	if (ret < 0)  		goto unlock_fail; @@ -542,7 +542,7 @@ static int  kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)  {  	int                       pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; -	struct kvm_io_bus        *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; +	enum kvm_bus              bus_idx = pio ? KVM_PIO_BUS : KVM_MMIO_BUS;  	struct _ioeventfd        *p, *tmp;  	struct eventfd_ctx       *eventfd;  	int                       ret = -ENOENT; @@ -565,7 +565,7 @@ kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args)  		if (!p->wildcard && p->datamatch != args->datamatch)  			continue; -		__kvm_io_bus_unregister_dev(bus, &p->dev); +		kvm_io_bus_unregister_dev(kvm, bus_idx, &p->dev);  		ioeventfd_release(p);  		ret = 0;  		break; diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c index 38a2d20b89de..f326a6f301cc 100644 --- a/virt/kvm/ioapic.c +++ b/virt/kvm/ioapic.c @@ -372,7 +372,9 @@ int kvm_ioapic_init(struct kvm *kvm)  	kvm_ioapic_reset(ioapic);  	kvm_iodevice_init(&ioapic->dev, &ioapic_mmio_ops);  	ioapic->kvm = kvm; -	ret = kvm_io_bus_register_dev(kvm, &kvm->mmio_bus, &ioapic->dev); +	down_write(&kvm->slots_lock); +	ret = kvm_io_bus_register_dev(kvm, KVM_MMIO_BUS, &ioapic->dev); +	up_write(&kvm->slots_lock);  	if (ret < 0)  		kfree(ioapic); diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c680f7b64c6f..659bc12ad16a 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -85,6 +85,8 @@ static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,  static int hardware_enable_all(void);  static void hardware_disable_all(void); +static void kvm_io_bus_destroy(struct kvm_io_bus *bus); +  static bool kvm_rebooting;  static bool largepages_enabled = true; @@ -367,7 +369,7 @@ static int kvm_init_mmu_notifier(struct kvm *kvm)  static struct kvm *kvm_create_vm(void)  { -	int r = 0; +	int r = 0, i;  	struct kvm *kvm = kvm_arch_create_vm();  #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET  	struct page *page; @@ -391,6 +393,14 @@ static struct kvm *kvm_create_vm(void)  		goto out_err;  	if (init_srcu_struct(&kvm->srcu))  		goto out_err; +	for (i = 0; i < KVM_NR_BUSES; i++) { +		kvm->buses[i] = kzalloc(sizeof(struct kvm_io_bus), +					GFP_KERNEL); +		if (!kvm->buses[i]) { +			cleanup_srcu_struct(&kvm->srcu); +			goto out_err; +		} +	}  #ifdef KVM_COALESCED_MMIO_PAGE_OFFSET  	page = alloc_page(GFP_KERNEL | __GFP_ZERO); @@ -416,11 +426,9 @@ static struct kvm *kvm_create_vm(void)  	atomic_inc(&kvm->mm->mm_count);  	spin_lock_init(&kvm->mmu_lock);  	spin_lock_init(&kvm->requests_lock); -	kvm_io_bus_init(&kvm->pio_bus);  	kvm_eventfd_init(kvm);  	mutex_init(&kvm->lock);  	mutex_init(&kvm->irq_lock); -	kvm_io_bus_init(&kvm->mmio_bus);  	init_rwsem(&kvm->slots_lock);  	atomic_set(&kvm->users_count, 1);  	spin_lock(&kvm_lock); @@ -435,6 +443,8 @@ out:  out_err:  	hardware_disable_all();  out_err_nodisable: +	for (i = 0; i < KVM_NR_BUSES; i++) +		kfree(kvm->buses[i]);  	kfree(kvm->memslots);  	kfree(kvm);  	return ERR_PTR(r); @@ -480,6 +490,7 @@ void kvm_free_physmem(struct kvm *kvm)  static void kvm_destroy_vm(struct kvm *kvm)  { +	int i;  	struct mm_struct *mm = kvm->mm;  	kvm_arch_sync_events(kvm); @@ -487,8 +498,8 @@ static void kvm_destroy_vm(struct kvm *kvm)  	list_del(&kvm->vm_list);  	spin_unlock(&kvm_lock);  	kvm_free_irq_routing(kvm); -	kvm_io_bus_destroy(&kvm->pio_bus); -	kvm_io_bus_destroy(&kvm->mmio_bus); +	for (i = 0; i < KVM_NR_BUSES; i++) +		kvm_io_bus_destroy(kvm->buses[i]);  	kvm_coalesced_mmio_free(kvm);  #if defined(CONFIG_MMU_NOTIFIER) && defined(KVM_ARCH_WANT_MMU_NOTIFIER)  	mmu_notifier_unregister(&kvm->mmu_notifier, kvm->mm); @@ -1949,12 +1960,7 @@ static struct notifier_block kvm_reboot_notifier = {  	.priority = 0,  }; -void kvm_io_bus_init(struct kvm_io_bus *bus) -{ -	memset(bus, 0, sizeof(*bus)); -} - -void kvm_io_bus_destroy(struct kvm_io_bus *bus) +static void kvm_io_bus_destroy(struct kvm_io_bus *bus)  {  	int i; @@ -1963,13 +1969,15 @@ void kvm_io_bus_destroy(struct kvm_io_bus *bus)  		kvm_iodevice_destructor(pos);  	} +	kfree(bus);  }  /* kvm_io_bus_write - called under kvm->slots_lock */ -int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr, +int kvm_io_bus_write(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr,  		     int len, const void *val)  {  	int i; +	struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]);  	for (i = 0; i < bus->dev_count; i++)  		if (!kvm_iodevice_write(bus->devs[i], addr, len, val))  			return 0; @@ -1977,59 +1985,71 @@ int kvm_io_bus_write(struct kvm_io_bus *bus, gpa_t addr,  }  /* kvm_io_bus_read - called under kvm->slots_lock */ -int kvm_io_bus_read(struct kvm_io_bus *bus, gpa_t addr, int len, void *val) +int kvm_io_bus_read(struct kvm *kvm, enum kvm_bus bus_idx, gpa_t addr, +		    int len, void *val)  {  	int i; +	struct kvm_io_bus *bus = rcu_dereference(kvm->buses[bus_idx]); +  	for (i = 0; i < bus->dev_count; i++)  		if (!kvm_iodevice_read(bus->devs[i], addr, len, val))  			return 0;  	return -EOPNOTSUPP;  } -int kvm_io_bus_register_dev(struct kvm *kvm, struct kvm_io_bus *bus, -			     struct kvm_io_device *dev) +/* Caller must have write lock on slots_lock. */ +int kvm_io_bus_register_dev(struct kvm *kvm, enum kvm_bus bus_idx, +			    struct kvm_io_device *dev)  { -	int ret; - -	down_write(&kvm->slots_lock); -	ret = __kvm_io_bus_register_dev(bus, dev); -	up_write(&kvm->slots_lock); +	struct kvm_io_bus *new_bus, *bus; -	return ret; -} - -/* An unlocked version. Caller must have write lock on slots_lock. */ -int __kvm_io_bus_register_dev(struct kvm_io_bus *bus, -			      struct kvm_io_device *dev) -{ +	bus = kvm->buses[bus_idx];  	if (bus->dev_count > NR_IOBUS_DEVS-1)  		return -ENOSPC; -	bus->devs[bus->dev_count++] = dev; +	new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL); +	if (!new_bus) +		return -ENOMEM; +	memcpy(new_bus, bus, sizeof(struct kvm_io_bus)); +	new_bus->devs[new_bus->dev_count++] = dev; +	rcu_assign_pointer(kvm->buses[bus_idx], new_bus); +	synchronize_srcu_expedited(&kvm->srcu); +	kfree(bus);  	return 0;  } -void kvm_io_bus_unregister_dev(struct kvm *kvm, -			       struct kvm_io_bus *bus, -			       struct kvm_io_device *dev) +/* Caller must have write lock on slots_lock. */ +int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx, +			      struct kvm_io_device *dev)  { -	down_write(&kvm->slots_lock); -	__kvm_io_bus_unregister_dev(bus, dev); -	up_write(&kvm->slots_lock); -} +	int i, r; +	struct kvm_io_bus *new_bus, *bus; -/* 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; +	new_bus = kzalloc(sizeof(struct kvm_io_bus), GFP_KERNEL); +	if (!new_bus) +		return -ENOMEM; -	for (i = 0; i < bus->dev_count; i++) -		if (bus->devs[i] == dev) { -			bus->devs[i] = bus->devs[--bus->dev_count]; +	bus = kvm->buses[bus_idx]; +	memcpy(new_bus, bus, sizeof(struct kvm_io_bus)); + +	r = -ENOENT; +	for (i = 0; i < new_bus->dev_count; i++) +		if (new_bus->devs[i] == dev) { +			r = 0; +			new_bus->devs[i] = new_bus->devs[--new_bus->dev_count];  			break;  		} + +	if (r) { +		kfree(new_bus); +		return r; +	} + +	rcu_assign_pointer(kvm->buses[bus_idx], new_bus); +	synchronize_srcu_expedited(&kvm->srcu); +	kfree(bus); +	return r;  }  static struct notifier_block kvm_cpu_notifier = { |