Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/virt/kvm/kvm
Browse files Browse the repository at this point in the history
Pull KVM fix from Marcelo Tosatti:
 "Memory leak and oops on the x86 mmu code, and sanitization of the
  KVM_IRQFD ioctl."

* git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: MMU: fix shrinking page from the empty mmu
  KVM: fix fault page leak
  KVM: Sanitize KVM_IRQFD flags
  KVM: Add missing KVM_IRQFD API documentation
  KVM: Pass kvm_irqfd to functions
  • Loading branch information
torvalds committed Jul 5, 2012
2 parents 24eee62 + 85b7059 commit 6bc5154
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 13 deletions.
17 changes: 17 additions & 0 deletions Documentation/virtual/kvm/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,23 @@ The "pte_enc" field provides a value that can OR'ed into the hash
PTE's RPN field (ie, it needs to be shifted left by 12 to OR it
into the hash PTE second double word).

4.75 KVM_IRQFD

Capability: KVM_CAP_IRQFD
Architectures: x86
Type: vm ioctl
Parameters: struct kvm_irqfd (in)
Returns: 0 on success, -1 on error

Allows setting an eventfd to directly trigger a guest interrupt.
kvm_irqfd.fd specifies the file descriptor to use as the eventfd and
kvm_irqfd.gsi specifies the irqchip pin toggled by this event. When
an event is tiggered on the eventfd, an interrupt is injected into
the guest using the specified gsi pin. The irqfd is removed using
the KVM_IRQFD_FLAG_DEASSIGN flag, specifying both kvm_irqfd.fd
and kvm_irqfd.gsi.


5. The kvm_run structure
------------------------

Expand Down
3 changes: 3 additions & 0 deletions arch/x86/kvm/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -3934,6 +3934,9 @@ static void kvm_mmu_remove_some_alloc_mmu_pages(struct kvm *kvm,
{
struct kvm_mmu_page *page;

if (list_empty(&kvm->arch.active_mmu_pages))
return;

page = container_of(kvm->arch.active_mmu_pages.prev,
struct kvm_mmu_page, link);
kvm_mmu_prepare_zap_page(kvm, page, invalid_list);
Expand Down
4 changes: 2 additions & 2 deletions include/linux/kvm_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -815,7 +815,7 @@ static inline void kvm_free_irq_routing(struct kvm *kvm) {}
#ifdef CONFIG_HAVE_KVM_EVENTFD

void kvm_eventfd_init(struct kvm *kvm);
int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags);
int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args);
void kvm_irqfd_release(struct kvm *kvm);
void kvm_irq_routing_update(struct kvm *, struct kvm_irq_routing_table *);
int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);
Expand All @@ -824,7 +824,7 @@ int kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args);

static inline void kvm_eventfd_init(struct kvm *kvm) {}

static inline int kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
static inline int kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
{
return -EINVAL;
}
Expand Down
23 changes: 13 additions & 10 deletions virt/kvm/eventfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ static void irqfd_update(struct kvm *kvm, struct _irqfd *irqfd,
}

static int
kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
kvm_irqfd_assign(struct kvm *kvm, struct kvm_irqfd *args)
{
struct kvm_irq_routing_table *irq_rt;
struct _irqfd *irqfd, *tmp;
Expand All @@ -212,12 +212,12 @@ kvm_irqfd_assign(struct kvm *kvm, int fd, int gsi)
return -ENOMEM;

irqfd->kvm = kvm;
irqfd->gsi = gsi;
irqfd->gsi = args->gsi;
INIT_LIST_HEAD(&irqfd->list);
INIT_WORK(&irqfd->inject, irqfd_inject);
INIT_WORK(&irqfd->shutdown, irqfd_shutdown);

file = eventfd_fget(fd);
file = eventfd_fget(args->fd);
if (IS_ERR(file)) {
ret = PTR_ERR(file);
goto fail;
Expand Down Expand Up @@ -298,19 +298,19 @@ kvm_eventfd_init(struct kvm *kvm)
* shutdown any irqfd's that match fd+gsi
*/
static int
kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
kvm_irqfd_deassign(struct kvm *kvm, struct kvm_irqfd *args)
{
struct _irqfd *irqfd, *tmp;
struct eventfd_ctx *eventfd;

eventfd = eventfd_ctx_fdget(fd);
eventfd = eventfd_ctx_fdget(args->fd);
if (IS_ERR(eventfd))
return PTR_ERR(eventfd);

spin_lock_irq(&kvm->irqfds.lock);

list_for_each_entry_safe(irqfd, tmp, &kvm->irqfds.items, list) {
if (irqfd->eventfd == eventfd && irqfd->gsi == gsi) {
if (irqfd->eventfd == eventfd && irqfd->gsi == args->gsi) {
/*
* This rcu_assign_pointer is needed for when
* another thread calls kvm_irq_routing_update before
Expand Down Expand Up @@ -338,12 +338,15 @@ kvm_irqfd_deassign(struct kvm *kvm, int fd, int gsi)
}

int
kvm_irqfd(struct kvm *kvm, int fd, int gsi, int flags)
kvm_irqfd(struct kvm *kvm, struct kvm_irqfd *args)
{
if (flags & KVM_IRQFD_FLAG_DEASSIGN)
return kvm_irqfd_deassign(kvm, fd, gsi);
if (args->flags & ~KVM_IRQFD_FLAG_DEASSIGN)
return -EINVAL;

if (args->flags & KVM_IRQFD_FLAG_DEASSIGN)
return kvm_irqfd_deassign(kvm, args);

return kvm_irqfd_assign(kvm, fd, gsi);
return kvm_irqfd_assign(kvm, args);
}

/*
Expand Down
3 changes: 2 additions & 1 deletion virt/kvm/kvm_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -2047,7 +2047,7 @@ static long kvm_vm_ioctl(struct file *filp,
r = -EFAULT;
if (copy_from_user(&data, argp, sizeof data))
goto out;
r = kvm_irqfd(kvm, data.fd, data.gsi, data.flags);
r = kvm_irqfd(kvm, &data);
break;
}
case KVM_IOEVENTFD: {
Expand Down Expand Up @@ -2845,6 +2845,7 @@ void kvm_exit(void)
kvm_arch_hardware_unsetup();
kvm_arch_exit();
free_cpumask_var(cpus_hardware_enabled);
__free_page(fault_page);
__free_page(hwpoison_page);
__free_page(bad_page);
}
Expand Down

0 comments on commit 6bc5154

Please sign in to comment.