* [RFC][PATCH] reduce KVM stack usage
@ 2008-07-17 15:32 Dave Hansen
2008-07-17 15:40 ` Roland Dreier
2008-07-19 7:32 ` Avi Kivity
0 siblings, 2 replies; 5+ messages in thread
From: Dave Hansen @ 2008-07-17 15:32 UTC (permalink / raw)
To: Avi Kivity; +Cc: kvm-devel, Anthony Liguori, Roland Dreier
KVM uses a lot of kernel stack on x86, especially with gcc 3.x. It
likes to overflow it and make my poor machine go boom. This patch takes
the worst stack users and makes them use kmalloc(). It also saves ~30
bytes in kvm_arch_vm_ioctl() by using a union.
I haven't tested this at all yet. Just posting to get some comments.
Avi, you said that one of these was a hot path. Which one is that? I
kinda doubt you'll be able to see any impact anyway.
before:
0x000042d3 kvm_arch_vcpu_ioctl [kvm]: 2148
0x000012e3 kvm_vcpu_ioctl [kvm]: 1620
0x00004a83 kvm_arch_vm_ioctl [kvm]: 1332
0x0000d472 kvm_pv_mmu_op [kvm]: 536
0x0000d4eb kvm_pv_mmu_op [kvm]: 536
0x00000476 __kvm_set_memory_region [kvm]: 184
0x000007e3 __kvm_set_memory_region [kvm]: 184
0x00007eb3 kvm_task_switch_32 [kvm]: 128
0x0000b553 paging64_page_fault [kvm]: 112
0x0000bfa3 paging32_page_fault [kvm]: 112
0x0000e48b x86_emulate_insn [kvm]: 112
0x0000e785 x86_emulate_insn [kvm]: 112
after:
0x00000476 __kvm_set_memory_region [kvm]: 184
0x000007e3 __kvm_set_memory_region [kvm]: 184
0x00004c83 kvm_arch_vm_ioctl [kvm]: 164
0x000012e3 kvm_vcpu_ioctl [kvm]: 152
0x00008013 kvm_task_switch_32 [kvm]: 128
0x0000b6b3 paging64_page_fault [kvm]: 112
0x0000c103 paging32_page_fault [kvm]: 112
0x0000e5fb x86_emulate_insn [kvm]: 112
0x0000e8f5 x86_emulate_insn [kvm]: 112
0x00004353 kvm_arch_vcpu_ioctl [kvm]: 104
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 7e7c396..f4e62f2 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2154,18 +2154,24 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
gpa_t addr, unsigned long *ret)
{
int r;
- struct kvm_pv_mmu_op_buffer buffer;
+ struct kvm_pv_mmu_op_buffer *buffer =
+ kmalloc(GFP_KERNEL, sizeof(struct kvm_pv_mmu_op_buffer));
- buffer.ptr = buffer.buf;
- buffer.len = min_t(unsigned long, bytes, sizeof buffer.buf);
- buffer.processed = 0;
+ if (!buffer) {
+ *ret = 0;
+ return -ENOMEM;
+ }
+
+ buffer->ptr = buffer->buf;
+ buffer->len = min_t(unsigned long, bytes, sizeof buffer->buf);
+ buffer->processed = 0;
- r = kvm_read_guest(vcpu->kvm, addr, buffer.buf, buffer.len);
+ r = kvm_read_guest(vcpu->kvm, addr, buffer->buf, buffer->len);
if (r)
goto out;
- while (buffer.len) {
- r = kvm_pv_mmu_op_one(vcpu, &buffer);
+ while (buffer->len) {
+ r = kvm_pv_mmu_op_one(vcpu, buffer);
if (r < 0)
goto out;
if (r == 0)
@@ -2174,7 +2180,8 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
r = 1;
out:
- *ret = buffer.processed;
+ *ret = buffer->processed;
+ kfree(buffer);
return r;
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 63a77ca..dbb0edd 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1283,12 +1283,15 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
int r;
+ struct kvm_lapic_state *lapic = NULL;
switch (ioctl) {
case KVM_GET_LAPIC: {
- struct kvm_lapic_state lapic;
+ lapic = kzalloc(GFP_KERNEL, sizeof(*lapic));
- memset(&lapic, 0, sizeof lapic);
+ r = -ENOMEM;
+ if (!lapic)
+ goto out;
r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
if (r)
goto out;
@@ -1299,8 +1302,10 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
break;
}
case KVM_SET_LAPIC: {
- struct kvm_lapic_state lapic;
-
+ lapic = kmalloc(GFP_KERNEL, sizeof(*lapic));
+ r = -ENOMEM;
+ if (!lapic)
+ goto out;
r = -EFAULT;
if (copy_from_user(&lapic, argp, sizeof lapic))
goto out;
@@ -1402,6 +1407,8 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EINVAL;
}
out:
+ if (lapic)
+ kfree(lapic);
return r;
}
@@ -1602,12 +1609,73 @@ out:
return r;
}
+static int kvm_arch_vm_irqchip_ioctl(struct kvm *kvm, void *argp,
+ unsigned int ioctl)
+{
+ int ret = 0;
+ struct kvm_irqchip *chip = kmalloc(GFP_KERNEL, sizeof(*chip));
+
+ if (!chip)
+ return -ENOMEM;
+
+ /* cheaper than the copy, so do this first */
+ if (!irqchip_in_kernel(kvm)) {
+ ret = -ENXIO;
+ goto out;
+ }
+ if (copy_from_user(chip, argp, sizeof *chip)) {
+ ret = -EFAULT;
+ goto out;
+ }
+ switch (ioctl) {
+ case KVM_GET_IRQCHIP:
+ ret = kvm_vm_ioctl_get_irqchip(kvm, chip);
+ if (ret)
+ goto out;
+ ret = copy_to_user(argp, chip, sizeof *chip);
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case KVM_SET_IRQCHIP:
+ ret = kvm_vm_ioctl_set_irqchip(kvm, chip);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+out:
+ kfree(chip);
+ return ret;
+}
+
+
+int x86_kvm_vm_ioctl_set_memory_region(struct kvm *kvm, void *argp)
+{
+ struct kvm_memory_region kvm_mem;
+ struct kvm_userspace_memory_region kvm_userspace_mem;
+
+ if (copy_from_user(&kvm_mem, argp, sizeof kvm_mem))
+ return -EFAULT;
+ kvm_userspace_mem.slot = kvm_mem.slot;
+ kvm_userspace_mem.flags = kvm_mem.flags;
+ kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
+ kvm_userspace_mem.memory_size = kvm_mem.memory_size;
+ return kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
+}
+
long kvm_arch_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm *kvm = filp->private_data;
void __user *argp = (void __user *)arg;
int r = -EINVAL;
+ union {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_pit_state ps;
+ struct kvm_memory_alias alias;
+ } u;
switch (ioctl) {
case KVM_SET_TSS_ADDR:
@@ -1639,17 +1707,14 @@ long kvm_arch_vm_ioctl(struct file *filp,
case KVM_GET_NR_MMU_PAGES:
r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
break;
- case KVM_SET_MEMORY_ALIAS: {
- struct kvm_memory_alias alias;
-
+ case KVM_SET_MEMORY_ALIAS:
r = -EFAULT;
- if (copy_from_user(&alias, argp, sizeof alias))
+ if (copy_from_user(&u.alias, argp, sizeof u.alias))
goto out;
- r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
+ r = kvm_vm_ioctl_set_memory_alias(kvm, &u.alias);
if (r)
goto out;
break;
- }
case KVM_CREATE_IRQCHIP:
r = -ENOMEM;
kvm->arch.vpic = kvm_create_pic(kvm);
@@ -1689,67 +1754,37 @@ long kvm_arch_vm_ioctl(struct file *filp,
}
break;
}
- case KVM_GET_IRQCHIP: {
- /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
- struct kvm_irqchip chip;
-
- r = -EFAULT;
- if (copy_from_user(&chip, argp, sizeof chip))
- goto out;
- r = -ENXIO;
- if (!irqchip_in_kernel(kvm))
- goto out;
- r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
- if (r)
- goto out;
- r = -EFAULT;
- if (copy_to_user(argp, &chip, sizeof chip))
- goto out;
- r = 0;
- break;
- }
- case KVM_SET_IRQCHIP: {
- /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
- struct kvm_irqchip chip;
-
- r = -EFAULT;
- if (copy_from_user(&chip, argp, sizeof chip))
- goto out;
- r = -ENXIO;
- if (!irqchip_in_kernel(kvm))
- goto out;
- r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
+ case KVM_GET_IRQCHIP:
+ case KVM_SET_IRQCHIP:
+ r = kvm_arch_vm_irqchip_ioctl(kvm, argp, ioctl);
if (r)
goto out;
r = 0;
break;
- }
case KVM_GET_PIT: {
- struct kvm_pit_state ps;
r = -EFAULT;
- if (copy_from_user(&ps, argp, sizeof ps))
+ if (copy_from_user(&u.ps, argp, sizeof u.ps))
goto out;
r = -ENXIO;
if (!kvm->arch.vpit)
goto out;
- r = kvm_vm_ioctl_get_pit(kvm, &ps);
+ r = kvm_vm_ioctl_get_pit(kvm, &u.ps);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, &ps, sizeof ps))
+ if (copy_to_user(argp, &u.ps, sizeof u.ps))
goto out;
r = 0;
break;
}
case KVM_SET_PIT: {
- struct kvm_pit_state ps;
r = -EFAULT;
- if (copy_from_user(&ps, argp, sizeof ps))
+ if (copy_from_user(&u.ps, argp, sizeof u.ps))
goto out;
r = -ENXIO;
if (!kvm->arch.vpit)
goto out;
- r = kvm_vm_ioctl_set_pit(kvm, &ps);
+ r = kvm_vm_ioctl_set_pit(kvm, &u.ps);
if (r)
goto out;
r = 0;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2d29e26..be2816a 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -905,6 +905,9 @@ static long kvm_vcpu_ioctl(struct file *filp,
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
int r;
+ struct kvm_fpu *fpu = NULL;
+ struct kvm_sregs *kvm_sregs = NULL;
+
if (vcpu->kvm->mm != current->mm)
return -EIO;
@@ -952,25 +955,29 @@ out_free2:
break;
}
case KVM_GET_SREGS: {
- struct kvm_sregs kvm_sregs;
-
- memset(&kvm_sregs, 0, sizeof kvm_sregs);
- r = kvm_arch_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs);
+ kvm_sregs = kzalloc(GFP_KERNEL, sizeof *kvm_sregs);
+ r = -ENOMEM;
+ if (!kvm_sregs)
+ goto out;
+ memset(kvm_sregs, 0, sizeof kvm_sregs);
+ r = kvm_arch_vcpu_ioctl_get_sregs(vcpu, kvm_sregs);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
+ if (copy_to_user(argp, kvm_sregs, sizeof *kvm_sregs))
goto out;
r = 0;
break;
}
case KVM_SET_SREGS: {
- struct kvm_sregs kvm_sregs;
-
+ kvm_sregs = kmalloc(GFP_KERNEL, sizeof kvm_sregs);
+ r = -ENOMEM;
+ if (!kvm_sregs)
+ goto out;
r = -EFAULT;
- if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
+ if (copy_from_user(kvm_sregs, argp, sizeof *kvm_sregs))
goto out;
- r = kvm_arch_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs);
+ r = kvm_arch_vcpu_ioctl_set_sregs(vcpu, kvm_sregs);
if (r)
goto out;
r = 0;
@@ -1051,25 +1058,28 @@ out_free2:
break;
}
case KVM_GET_FPU: {
- struct kvm_fpu fpu;
-
- memset(&fpu, 0, sizeof fpu);
- r = kvm_arch_vcpu_ioctl_get_fpu(vcpu, &fpu);
+ fpu = kzalloc(GFP_KERNEL, sizeof(*fpu));
+ r = -ENOMEM;
+ if (!fpu)
+ goto out;
+ r = kvm_arch_vcpu_ioctl_get_fpu(vcpu, fpu);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, &fpu, sizeof fpu))
+ if (copy_to_user(argp, fpu, sizeof *fpu))
goto out;
r = 0;
break;
}
case KVM_SET_FPU: {
- struct kvm_fpu fpu;
-
+ fpu = kmalloc(GFP_KERNEL, sizeof(*fpu));
+ r = -ENOMEM;
+ if (!fpu)
+ goto out;
r = -EFAULT;
- if (copy_from_user(&fpu, argp, sizeof fpu))
+ if (copy_from_user(fpu, argp, sizeof *fpu))
goto out;
- r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, &fpu);
+ r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu);
if (r)
goto out;
r = 0;
@@ -1079,6 +1089,10 @@ out_free2:
r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
}
out:
+ if (fpu)
+ kfree(fpu);
+ if (kvm_sregs)
+ kfree(kvm_sregs);
return r;
}
-- Dave
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC][PATCH] reduce KVM stack usage
2008-07-17 15:32 [RFC][PATCH] reduce KVM stack usage Dave Hansen
@ 2008-07-17 15:40 ` Roland Dreier
2008-07-17 17:23 ` Dave Hansen
2008-07-19 7:32 ` Avi Kivity
1 sibling, 1 reply; 5+ messages in thread
From: Roland Dreier @ 2008-07-17 15:40 UTC (permalink / raw)
To: Dave Hansen; +Cc: Avi Kivity, kvm-devel, Anthony Liguori
> + struct kvm_pv_mmu_op_buffer *buffer =
> + kmalloc(GFP_KERNEL, sizeof(struct kvm_pv_mmu_op_buffer));
Surely this produces a warning? kmalloc takes (size, flags) -- you have
them reversed here.
> + lapic = kzalloc(GFP_KERNEL, sizeof(*lapic));
> + lapic = kmalloc(GFP_KERNEL, sizeof(*lapic));
> + struct kvm_irqchip *chip = kmalloc(GFP_KERNEL, sizeof(*chip));
> + kvm_sregs = kmalloc(GFP_KERNEL, sizeof kvm_sregs);
> + fpu = kmalloc(GFP_KERNEL, sizeof(*fpu));
same for all of these places.
> + if (lapic)
> + kfree(lapic);
> + if (fpu)
> + kfree(fpu);
> + if (kvm_sregs)
> + kfree(kvm_sregs);
kfree(NULL) is fine, so you can remove the if()s here.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC][PATCH] reduce KVM stack usage
2008-07-17 15:40 ` Roland Dreier
@ 2008-07-17 17:23 ` Dave Hansen
2008-07-17 23:02 ` Roland Dreier
0 siblings, 1 reply; 5+ messages in thread
From: Dave Hansen @ 2008-07-17 17:23 UTC (permalink / raw)
To: Roland Dreier; +Cc: Avi Kivity, kvm-devel, Anthony Liguori
On Thu, 2008-07-17 at 08:40 -0700, Roland Dreier wrote:
> > + struct kvm_pv_mmu_op_buffer *buffer =
> > + kmalloc(GFP_KERNEL, sizeof(struct kvm_pv_mmu_op_buffer));
>
> Surely this produces a warning? kmalloc takes (size, flags) -- you have
> them reversed here.
Heh. It actually doesn't.
> > + lapic = kzalloc(GFP_KERNEL, sizeof(*lapic));
> > + lapic = kmalloc(GFP_KERNEL, sizeof(*lapic));
> > + struct kvm_irqchip *chip = kmalloc(GFP_KERNEL, sizeof(*chip));
> > + kvm_sregs = kmalloc(GFP_KERNEL, sizeof kvm_sregs);
> > + fpu = kmalloc(GFP_KERNEL, sizeof(*fpu));
>
> same for all of these places.
>
> > + if (lapic)
> > + kfree(lapic);
>
> > + if (fpu)
> > + kfree(fpu);
> > + if (kvm_sregs)
> > + kfree(kvm_sregs);
>
> kfree(NULL) is fine, so you can remove the if()s here.
I know it is fine, but I kinda like putting the if()s, just to let
people know that we don't always *expect* something to be in there.
But, it doesn't matter to me too much either way.
Here's another try. This actually lets kvm come up for me.
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
index 7e7c396..fd1f303 100644
--- a/arch/x86/kvm/mmu.c
+++ b/arch/x86/kvm/mmu.c
@@ -2154,18 +2154,24 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
gpa_t addr, unsigned long *ret)
{
int r;
- struct kvm_pv_mmu_op_buffer buffer;
+ struct kvm_pv_mmu_op_buffer *buffer =
+ kmalloc(sizeof(struct kvm_pv_mmu_op_buffer), GFP_KERNEL);
- buffer.ptr = buffer.buf;
- buffer.len = min_t(unsigned long, bytes, sizeof buffer.buf);
- buffer.processed = 0;
+ if (!buffer) {
+ *ret = 0;
+ return -ENOMEM;
+ }
+
+ buffer->ptr = buffer->buf;
+ buffer->len = min_t(unsigned long, bytes, sizeof buffer->buf);
+ buffer->processed = 0;
- r = kvm_read_guest(vcpu->kvm, addr, buffer.buf, buffer.len);
+ r = kvm_read_guest(vcpu->kvm, addr, buffer->buf, buffer->len);
if (r)
goto out;
- while (buffer.len) {
- r = kvm_pv_mmu_op_one(vcpu, &buffer);
+ while (buffer->len) {
+ r = kvm_pv_mmu_op_one(vcpu, buffer);
if (r < 0)
goto out;
if (r == 0)
@@ -2174,7 +2180,8 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
r = 1;
out:
- *ret = buffer.processed;
+ *ret = buffer->processed;
+ kfree(buffer);
return r;
}
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 0faa254..14eae49 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1283,13 +1283,16 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
int r;
+ struct kvm_lapic_state *lapic = NULL;
switch (ioctl) {
case KVM_GET_LAPIC: {
- struct kvm_lapic_state lapic;
+ lapic = kzalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
- memset(&lapic, 0, sizeof lapic);
- r = kvm_vcpu_ioctl_get_lapic(vcpu, &lapic);
+ r = -ENOMEM;
+ if (!lapic)
+ goto out;
+ r = kvm_vcpu_ioctl_get_lapic(vcpu, lapic);
if (r)
goto out;
r = -EFAULT;
@@ -1299,12 +1302,14 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
break;
}
case KVM_SET_LAPIC: {
- struct kvm_lapic_state lapic;
-
+ lapic = kmalloc(sizeof(struct kvm_lapic_state), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!lapic)
+ goto out;
r = -EFAULT;
- if (copy_from_user(&lapic, argp, sizeof lapic))
+ if (copy_from_user(lapic, argp, sizeof(struct kvm_lapic_state)))
goto out;
- r = kvm_vcpu_ioctl_set_lapic(vcpu, &lapic);;
+ r = kvm_vcpu_ioctl_set_lapic(vcpu, lapic);
if (r)
goto out;
r = 0;
@@ -1402,6 +1407,7 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
r = -EINVAL;
}
out:
+ kfree(lapic);
return r;
}
@@ -1602,12 +1608,73 @@ out:
return r;
}
+static int kvm_arch_vm_irqchip_ioctl(struct kvm *kvm, void *argp,
+ unsigned int ioctl)
+{
+ int ret = 0;
+ struct kvm_irqchip *chip = kmalloc(sizeof(struct kvm_irqchip), GFP_KERNEL);
+
+ if (!chip)
+ return -ENOMEM;
+
+ /* cheaper than the copy, so do this first */
+ if (!irqchip_in_kernel(kvm)) {
+ ret = -ENXIO;
+ goto out;
+ }
+ if (copy_from_user(chip, argp, sizeof(struct kvm_irqchip))) {
+ ret = -EFAULT;
+ goto out;
+ }
+ switch (ioctl) {
+ case KVM_GET_IRQCHIP:
+ ret = kvm_vm_ioctl_get_irqchip(kvm, chip);
+ if (ret)
+ goto out;
+ ret = copy_to_user(argp, chip, sizeof(struct kvm_irqchip));
+ if (ret) {
+ ret = -EFAULT;
+ goto out;
+ }
+ break;
+ case KVM_SET_IRQCHIP:
+ ret = kvm_vm_ioctl_set_irqchip(kvm, chip);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+out:
+ kfree(chip);
+ return ret;
+}
+
+
+int x86_kvm_vm_ioctl_set_memory_region(struct kvm *kvm, void *argp)
+{
+ struct kvm_memory_region kvm_mem;
+ struct kvm_userspace_memory_region kvm_userspace_mem;
+
+ if (copy_from_user(&kvm_mem, argp, sizeof(struct kvm_memory_region)))
+ return -EFAULT;
+ kvm_userspace_mem.slot = kvm_mem.slot;
+ kvm_userspace_mem.flags = kvm_mem.flags;
+ kvm_userspace_mem.guest_phys_addr = kvm_mem.guest_phys_addr;
+ kvm_userspace_mem.memory_size = kvm_mem.memory_size;
+ return kvm_vm_ioctl_set_memory_region(kvm, &kvm_userspace_mem, 0);
+}
+
long kvm_arch_vm_ioctl(struct file *filp,
unsigned int ioctl, unsigned long arg)
{
struct kvm *kvm = filp->private_data;
void __user *argp = (void __user *)arg;
int r = -EINVAL;
+ union {
+ /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
+ struct kvm_pit_state ps;
+ struct kvm_memory_alias alias;
+ } u;
switch (ioctl) {
case KVM_SET_TSS_ADDR:
@@ -1639,17 +1706,14 @@ long kvm_arch_vm_ioctl(struct file *filp,
case KVM_GET_NR_MMU_PAGES:
r = kvm_vm_ioctl_get_nr_mmu_pages(kvm);
break;
- case KVM_SET_MEMORY_ALIAS: {
- struct kvm_memory_alias alias;
-
+ case KVM_SET_MEMORY_ALIAS:
r = -EFAULT;
- if (copy_from_user(&alias, argp, sizeof alias))
+ if (copy_from_user(&u.alias, argp, sizeof(struct kvm_memory_alias)))
goto out;
- r = kvm_vm_ioctl_set_memory_alias(kvm, &alias);
+ r = kvm_vm_ioctl_set_memory_alias(kvm, &u.alias);
if (r)
goto out;
break;
- }
case KVM_CREATE_IRQCHIP:
r = -ENOMEM;
kvm->arch.vpic = kvm_create_pic(kvm);
@@ -1689,67 +1753,37 @@ long kvm_arch_vm_ioctl(struct file *filp,
}
break;
}
- case KVM_GET_IRQCHIP: {
- /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
- struct kvm_irqchip chip;
-
- r = -EFAULT;
- if (copy_from_user(&chip, argp, sizeof chip))
- goto out;
- r = -ENXIO;
- if (!irqchip_in_kernel(kvm))
- goto out;
- r = kvm_vm_ioctl_get_irqchip(kvm, &chip);
- if (r)
- goto out;
- r = -EFAULT;
- if (copy_to_user(argp, &chip, sizeof chip))
- goto out;
- r = 0;
- break;
- }
- case KVM_SET_IRQCHIP: {
- /* 0: PIC master, 1: PIC slave, 2: IOAPIC */
- struct kvm_irqchip chip;
-
- r = -EFAULT;
- if (copy_from_user(&chip, argp, sizeof chip))
- goto out;
- r = -ENXIO;
- if (!irqchip_in_kernel(kvm))
- goto out;
- r = kvm_vm_ioctl_set_irqchip(kvm, &chip);
+ case KVM_GET_IRQCHIP:
+ case KVM_SET_IRQCHIP:
+ r = kvm_arch_vm_irqchip_ioctl(kvm, argp, ioctl);
if (r)
goto out;
r = 0;
break;
- }
case KVM_GET_PIT: {
- struct kvm_pit_state ps;
r = -EFAULT;
- if (copy_from_user(&ps, argp, sizeof ps))
+ if (copy_from_user(&u.ps, argp, sizeof(struct kvm_pit_state)))
goto out;
r = -ENXIO;
if (!kvm->arch.vpit)
goto out;
- r = kvm_vm_ioctl_get_pit(kvm, &ps);
+ r = kvm_vm_ioctl_get_pit(kvm, &u.ps);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, &ps, sizeof ps))
+ if (copy_to_user(argp, &u.ps, sizeof(struct kvm_pit_state)))
goto out;
r = 0;
break;
}
case KVM_SET_PIT: {
- struct kvm_pit_state ps;
r = -EFAULT;
- if (copy_from_user(&ps, argp, sizeof ps))
+ if (copy_from_user(&u.ps, argp, sizeof u.ps))
goto out;
r = -ENXIO;
if (!kvm->arch.vpit)
goto out;
- r = kvm_vm_ioctl_set_pit(kvm, &ps);
+ r = kvm_vm_ioctl_set_pit(kvm, &u.ps);
if (r)
goto out;
r = 0;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index d4eae6a..c31adbb 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -905,6 +905,9 @@ static long kvm_vcpu_ioctl(struct file *filp,
struct kvm_vcpu *vcpu = filp->private_data;
void __user *argp = (void __user *)arg;
int r;
+ struct kvm_fpu *fpu = NULL;
+ struct kvm_sregs *kvm_sregs = NULL;
+
if (vcpu->kvm->mm != current->mm)
return -EIO;
@@ -952,25 +955,29 @@ out_free2:
break;
}
case KVM_GET_SREGS: {
- struct kvm_sregs kvm_sregs;
-
- memset(&kvm_sregs, 0, sizeof kvm_sregs);
- r = kvm_arch_vcpu_ioctl_get_sregs(vcpu, &kvm_sregs);
+ kvm_sregs = kzalloc(sizeof(struct kvm_sregs), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!kvm_sregs)
+ goto out;
+ memset(kvm_sregs, 0, sizeof(struct kvm_sregs));
+ r = kvm_arch_vcpu_ioctl_get_sregs(vcpu, kvm_sregs);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, &kvm_sregs, sizeof kvm_sregs))
+ if (copy_to_user(argp, kvm_sregs, sizeof(struct kvm_sregs)))
goto out;
r = 0;
break;
}
case KVM_SET_SREGS: {
- struct kvm_sregs kvm_sregs;
-
+ kvm_sregs = kmalloc(sizeof(struct kvm_sregs), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!kvm_sregs)
+ goto out;
r = -EFAULT;
- if (copy_from_user(&kvm_sregs, argp, sizeof kvm_sregs))
+ if (copy_from_user(kvm_sregs, argp, sizeof(struct kvm_sregs)))
goto out;
- r = kvm_arch_vcpu_ioctl_set_sregs(vcpu, &kvm_sregs);
+ r = kvm_arch_vcpu_ioctl_set_sregs(vcpu, kvm_sregs);
if (r)
goto out;
r = 0;
@@ -1051,25 +1058,28 @@ out_free2:
break;
}
case KVM_GET_FPU: {
- struct kvm_fpu fpu;
-
- memset(&fpu, 0, sizeof fpu);
- r = kvm_arch_vcpu_ioctl_get_fpu(vcpu, &fpu);
+ fpu = kzalloc(sizeof(struct kvm_fpu), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!fpu)
+ goto out;
+ r = kvm_arch_vcpu_ioctl_get_fpu(vcpu, fpu);
if (r)
goto out;
r = -EFAULT;
- if (copy_to_user(argp, &fpu, sizeof fpu))
+ if (copy_to_user(argp, fpu, sizeof(struct kvm_fpu)))
goto out;
r = 0;
break;
}
case KVM_SET_FPU: {
- struct kvm_fpu fpu;
-
+ fpu = kmalloc(sizeof(struct kvm_fpu), GFP_KERNEL);
+ r = -ENOMEM;
+ if (!fpu)
+ goto out;
r = -EFAULT;
- if (copy_from_user(&fpu, argp, sizeof fpu))
+ if (copy_from_user(fpu, argp, sizeof(struct kvm_fpu)))
goto out;
- r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, &fpu);
+ r = kvm_arch_vcpu_ioctl_set_fpu(vcpu, fpu);
if (r)
goto out;
r = 0;
@@ -1079,6 +1089,8 @@ out_free2:
r = kvm_arch_vcpu_ioctl(filp, ioctl, arg);
}
out:
+ kfree(fpu);
+ kfree(kvm_sregs);
return r;
}
-- Dave
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [RFC][PATCH] reduce KVM stack usage
2008-07-17 17:23 ` Dave Hansen
@ 2008-07-17 23:02 ` Roland Dreier
0 siblings, 0 replies; 5+ messages in thread
From: Roland Dreier @ 2008-07-17 23:02 UTC (permalink / raw)
To: Dave Hansen; +Cc: Avi Kivity, kvm-devel, Anthony Liguori
> > > + kmalloc(GFP_KERNEL, sizeof(struct kvm_pv_mmu_op_buffer));
> > Surely this produces a warning? kmalloc takes (size, flags) -- you have
> > them reversed here.
> Heh. It actually doesn't.
Yeah, I guess you need sparse to catch the gfp_t mismatch.
> > kfree(NULL) is fine, so you can remove the if()s here.
> I know it is fine, but I kinda like putting the if()s, just to let
> people know that we don't always *expect* something to be in there.
> But, it doesn't matter to me too much either way.
It's not really a big deal, but "if (x) kfree(x);" does bloat the object
code with the extra test of 'x'. I guess you could put a comment like
/* free any temp structures we allocated */ or something like that.
- R.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [RFC][PATCH] reduce KVM stack usage
2008-07-17 15:32 [RFC][PATCH] reduce KVM stack usage Dave Hansen
2008-07-17 15:40 ` Roland Dreier
@ 2008-07-19 7:32 ` Avi Kivity
1 sibling, 0 replies; 5+ messages in thread
From: Avi Kivity @ 2008-07-19 7:32 UTC (permalink / raw)
To: Dave Hansen; +Cc: kvm-devel, Anthony Liguori, Roland Dreier
Dave Hansen wrote:
> KVM uses a lot of kernel stack on x86, especially with gcc 3.x. It
> likes to overflow it and make my poor machine go boom. This patch takes
> the worst stack users and makes them use kmalloc(). It also saves ~30
> bytes in kvm_arch_vm_ioctl() by using a union.
>
> I haven't tested this at all yet. Just posting to get some comments.
>
> Avi, you said that one of these was a hot path. Which one is that? I
> kinda doubt you'll be able to see any impact anyway.
>
>
The pv_mmu_ops thing.
> diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c
> index 7e7c396..f4e62f2 100644
> --- a/arch/x86/kvm/mmu.c
> +++ b/arch/x86/kvm/mmu.c
> @@ -2154,18 +2154,24 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
> gpa_t addr, unsigned long *ret)
> {
> int r;
> - struct kvm_pv_mmu_op_buffer buffer;
> + struct kvm_pv_mmu_op_buffer *buffer =
> + kmalloc(GFP_KERNEL, sizeof(struct kvm_pv_mmu_op_buffer));
>
> - buffer.ptr = buffer.buf;
> - buffer.len = min_t(unsigned long, bytes, sizeof buffer.buf);
> - buffer.processed = 0;
> + if (!buffer) {
> + *ret = 0;
> + return -ENOMEM;
> + }
> +
> + buffer->ptr = buffer->buf;
> + buffer->len = min_t(unsigned long, bytes, sizeof buffer->buf);
> + buffer->processed = 0;
>
> - r = kvm_read_guest(vcpu->kvm, addr, buffer.buf, buffer.len);
> + r = kvm_read_guest(vcpu->kvm, addr, buffer->buf, buffer->len);
> if (r)
> goto out;
>
> - while (buffer.len) {
> - r = kvm_pv_mmu_op_one(vcpu, &buffer);
> + while (buffer->len) {
> + r = kvm_pv_mmu_op_one(vcpu, buffer);
> if (r < 0)
> goto out;
> if (r == 0)
> @@ -2174,7 +2180,8 @@ int kvm_pv_mmu_op(struct kvm_vcpu *vcpu, unsigned long bytes,
>
> r = 1;
> out:
> - *ret = buffer.processed;
> + *ret = buffer->processed;
> + kfree(buffer);
>
Please change this to store the buffer in vcpu->arch.something, and free
it on vcpu destruction. If this path is called at all, it is called
very often, so it's fine to "waste" those 512 bytes.
Might even allocate it as a field in vcpu->arch, since it's only 512 bytes.
>
> +static int kvm_arch_vm_irqchip_ioctl(struct kvm *kvm, void *argp,
> + unsigned int ioctl)
> +{
> +
> +int x86_kvm_vm_ioctl_set_memory_region(struct kvm *kvm, void *argp)
> +{
>
Please keep the code inlined in kvm_arch_vcpu_ioctl(), as this is a
-stable candidate and I want to keep the patch obvious. A later patch
can break it up.
Please separate the vm ioctl, vcpu ioctl, and pv_mmu_op thing into
separate patches, for bisect goodness.
--
I have a truly marvellous patch that fixes the bug which this
signature is too narrow to contain.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2008-07-19 7:32 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-17 15:32 [RFC][PATCH] reduce KVM stack usage Dave Hansen
2008-07-17 15:40 ` Roland Dreier
2008-07-17 17:23 ` Dave Hansen
2008-07-17 23:02 ` Roland Dreier
2008-07-19 7:32 ` Avi Kivity
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox