Skip to content

Commit

Permalink
Merge branch 'bugfix' of git://git.kernel.org/pub/scm/linux/kernel/gi…
Browse files Browse the repository at this point in the history
…t/jeremy/xen

* 'bugfix' of git://git.kernel.org/pub/scm/linux/kernel/git/jeremy/xen:
  xen: try harder to balloon up under memory pressure.
  Xen balloon: fix totalram_pages counting.
  xen: explicitly create/destroy stop_machine workqueues outside suspend/resume region.
  xen: improve error handling in do_suspend.
  xen: don't leak IRQs over suspend/resume.
  xen: call clock resume notifier on all CPUs
  xen: use iret for return from 64b kernel to 32b usermode
  xen: don't call dpm_resume_noirq() with interrupts disabled.
  xen: register runstate info for boot CPU early
  xen: register runstate on secondary CPUs
  xen: register timer interrupt with IRQF_TIMER
  xen: correctly restore pfn_to_mfn_list_list after resume
  xen: restore runstate_info even if !have_vcpu_info_placement
  xen: re-register runstate area earlier on resume.
  xen: wait up to 5 minutes for device connetion
  xen: improvement to wait_for_devices()
  xen: fix is_disconnected_device/exists_disconnected_device
  xen/xenbus: make DEVICE_ATTR()s static
  • Loading branch information
torvalds committed Dec 10, 2009
2 parents eae6fa9 + bc2c030 commit ab1831b
Show file tree
Hide file tree
Showing 11 changed files with 107 additions and 79 deletions.
27 changes: 14 additions & 13 deletions arch/x86/xen/enlighten.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,24 +138,23 @@ static void xen_vcpu_setup(int cpu)
*/
void xen_vcpu_restore(void)
{
if (have_vcpu_info_placement) {
int cpu;
int cpu;

for_each_online_cpu(cpu) {
bool other_cpu = (cpu != smp_processor_id());
for_each_online_cpu(cpu) {
bool other_cpu = (cpu != smp_processor_id());

if (other_cpu &&
HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
BUG();
if (other_cpu &&
HYPERVISOR_vcpu_op(VCPUOP_down, cpu, NULL))
BUG();

xen_vcpu_setup(cpu);
xen_setup_runstate_info(cpu);

if (other_cpu &&
HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
BUG();
}
if (have_vcpu_info_placement)
xen_vcpu_setup(cpu);

BUG_ON(!have_vcpu_info_placement);
if (other_cpu &&
HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL))
BUG();
}
}

Expand Down Expand Up @@ -1180,6 +1179,8 @@ asmlinkage void __init xen_start_kernel(void)

xen_raw_console_write("about to get started...\n");

xen_setup_runstate_info(0);

/* Start the world */
#ifdef CONFIG_X86_32
i386_start_kernel();
Expand Down
2 changes: 1 addition & 1 deletion arch/x86/xen/mmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ static inline unsigned p2m_index(unsigned long pfn)
}

/* Build the parallel p2m_top_mfn structures */
static void __init xen_build_mfn_list_list(void)
void xen_build_mfn_list_list(void)
{
unsigned pfn, idx;

Expand Down
1 change: 1 addition & 0 deletions arch/x86/xen/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ static int __cpuinit xen_cpu_up(unsigned int cpu)
(unsigned long)task_stack_page(idle) -
KERNEL_STACK_OFFSET + THREAD_SIZE;
#endif
xen_setup_runstate_info(cpu);
xen_setup_timer(cpu);
xen_init_lock_cpu(cpu);

Expand Down
17 changes: 16 additions & 1 deletion arch/x86/xen/suspend.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <linux/types.h>
#include <linux/clockchips.h>

#include <xen/interface/xen.h>
#include <xen/grant_table.h>
Expand Down Expand Up @@ -27,6 +28,8 @@ void xen_pre_suspend(void)

void xen_post_suspend(int suspend_cancelled)
{
xen_build_mfn_list_list();

xen_setup_shared_info();

if (suspend_cancelled) {
Expand All @@ -44,7 +47,19 @@ void xen_post_suspend(int suspend_cancelled)

}

static void xen_vcpu_notify_restore(void *data)
{
unsigned long reason = (unsigned long)data;

/* Boot processor notified via generic timekeeping_resume() */
if ( smp_processor_id() == 0)
return;

clockevents_notify(reason, NULL);
}

void xen_arch_resume(void)
{
/* nothing */
smp_call_function(xen_vcpu_notify_restore,
(void *)CLOCK_EVT_NOTIFY_RESUME, 1);
}
7 changes: 3 additions & 4 deletions arch/x86/xen/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ bool xen_vcpu_stolen(int vcpu)
return per_cpu(runstate, vcpu).state == RUNSTATE_runnable;
}

static void setup_runstate_info(int cpu)
void xen_setup_runstate_info(int cpu)
{
struct vcpu_register_runstate_memory_area area;

Expand Down Expand Up @@ -434,16 +434,14 @@ void xen_setup_timer(int cpu)
name = "<timer kasprintf failed>";

irq = bind_virq_to_irqhandler(VIRQ_TIMER, cpu, xen_timer_interrupt,
IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING,
IRQF_DISABLED|IRQF_PERCPU|IRQF_NOBALANCING|IRQF_TIMER,
name, NULL);

evt = &per_cpu(xen_clock_events, cpu);
memcpy(evt, xen_clockevent, sizeof(*evt));

evt->cpumask = cpumask_of(cpu);
evt->irq = irq;

setup_runstate_info(cpu);
}

void xen_teardown_timer(int cpu)
Expand Down Expand Up @@ -494,6 +492,7 @@ __init void xen_time_init(void)

setup_force_cpu_cap(X86_FEATURE_TSC);

xen_setup_runstate_info(cpu);
xen_setup_timer(cpu);
xen_setup_cpu_clockevents();
}
4 changes: 2 additions & 2 deletions arch/x86/xen/xen-asm_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ ENTRY(xen_sysret32)
pushq $__USER32_CS
pushq %rcx

pushq $VGCF_in_syscall
pushq $0
1: jmp hypercall_iret
ENDPATCH(xen_sysret32)
RELOC(xen_sysret32, 1b+1)
Expand Down Expand Up @@ -151,7 +151,7 @@ ENTRY(xen_syscall32_target)
ENTRY(xen_sysenter_target)
lea 16(%rsp), %rsp /* strip %rcx, %r11 */
mov $-ENOSYS, %rax
pushq $VGCF_in_syscall
pushq $0
jmp hypercall_iret
ENDPROC(xen_syscall32_target)
ENDPROC(xen_sysenter_target)
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/xen/xen-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ extern struct shared_info *HYPERVISOR_shared_info;

void xen_setup_mfn_list_list(void);
void xen_setup_shared_info(void);
void xen_build_mfn_list_list(void);
void xen_setup_machphys_mapping(void);
pgd_t *xen_setup_kernel_pagetable(pgd_t *pgd, unsigned long max_pfn);
void xen_ident_map_ISA(void);
Expand All @@ -41,6 +42,7 @@ void __init xen_build_dynamic_phys_to_machine(void);

void xen_init_irq_ops(void);
void xen_setup_timer(int cpu);
void xen_setup_runstate_info(int cpu);
void xen_teardown_timer(int cpu);
cycle_t xen_clocksource_read(void);
void xen_setup_cpu_clockevents(void);
Expand Down
38 changes: 9 additions & 29 deletions drivers/xen/balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ struct balloon_stats {
/* We aim for 'current allocation' == 'target allocation'. */
unsigned long current_pages;
unsigned long target_pages;
/* We may hit the hard limit in Xen. If we do then we remember it. */
unsigned long hard_limit;
/*
* Drivers may alter the memory reservation independently, but they
* must inform the balloon driver so we avoid hitting the hard limit.
Expand Down Expand Up @@ -136,6 +134,8 @@ static void balloon_append(struct page *page)
list_add(&page->lru, &ballooned_pages);
balloon_stats.balloon_low++;
}

totalram_pages--;
}

/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
Expand All @@ -156,6 +156,8 @@ static struct page *balloon_retrieve(void)
else
balloon_stats.balloon_low--;

totalram_pages++;

return page;
}

Expand All @@ -181,7 +183,7 @@ static void balloon_alarm(unsigned long unused)

static unsigned long current_target(void)
{
unsigned long target = min(balloon_stats.target_pages, balloon_stats.hard_limit);
unsigned long target = balloon_stats.target_pages;

target = min(target,
balloon_stats.current_pages +
Expand Down Expand Up @@ -217,23 +219,10 @@ static int increase_reservation(unsigned long nr_pages)
set_xen_guest_handle(reservation.extent_start, frame_list);
reservation.nr_extents = nr_pages;
rc = HYPERVISOR_memory_op(XENMEM_populate_physmap, &reservation);
if (rc < nr_pages) {
if (rc > 0) {
int ret;

/* We hit the Xen hard limit: reprobe. */
reservation.nr_extents = rc;
ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
&reservation);
BUG_ON(ret != rc);
}
if (rc >= 0)
balloon_stats.hard_limit = (balloon_stats.current_pages + rc -
balloon_stats.driver_pages);
if (rc < 0)
goto out;
}

for (i = 0; i < nr_pages; i++) {
for (i = 0; i < rc; i++) {
page = balloon_retrieve();
BUG_ON(page == NULL);

Expand All @@ -259,13 +248,12 @@ static int increase_reservation(unsigned long nr_pages)
__free_page(page);
}

balloon_stats.current_pages += nr_pages;
totalram_pages = balloon_stats.current_pages;
balloon_stats.current_pages += rc;

out:
spin_unlock_irqrestore(&balloon_lock, flags);

return 0;
return rc < 0 ? rc : rc != nr_pages;
}

static int decrease_reservation(unsigned long nr_pages)
Expand Down Expand Up @@ -323,7 +311,6 @@ static int decrease_reservation(unsigned long nr_pages)
BUG_ON(ret != nr_pages);

balloon_stats.current_pages -= nr_pages;
totalram_pages = balloon_stats.current_pages;

spin_unlock_irqrestore(&balloon_lock, flags);

Expand Down Expand Up @@ -367,7 +354,6 @@ static void balloon_process(struct work_struct *work)
static void balloon_set_new_target(unsigned long target)
{
/* No need for lock. Not read-modify-write updates. */
balloon_stats.hard_limit = ~0UL;
balloon_stats.target_pages = target;
schedule_work(&balloon_worker);
}
Expand Down Expand Up @@ -422,12 +408,10 @@ static int __init balloon_init(void)
pr_info("xen_balloon: Initialising balloon driver.\n");

balloon_stats.current_pages = min(xen_start_info->nr_pages, max_pfn);
totalram_pages = balloon_stats.current_pages;
balloon_stats.target_pages = balloon_stats.current_pages;
balloon_stats.balloon_low = 0;
balloon_stats.balloon_high = 0;
balloon_stats.driver_pages = 0UL;
balloon_stats.hard_limit = ~0UL;

init_timer(&balloon_timer);
balloon_timer.data = 0;
Expand Down Expand Up @@ -472,9 +456,6 @@ module_exit(balloon_exit);
BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(balloon_stats.current_pages));
BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_low));
BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(balloon_stats.balloon_high));
BALLOON_SHOW(hard_limit_kb,
(balloon_stats.hard_limit!=~0UL) ? "%lu\n" : "???\n",
(balloon_stats.hard_limit!=~0UL) ? PAGES2KB(balloon_stats.hard_limit) : 0);
BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(balloon_stats.driver_pages));

static ssize_t show_target_kb(struct sys_device *dev, struct sysdev_attribute *attr,
Expand Down Expand Up @@ -544,7 +525,6 @@ static struct attribute *balloon_info_attrs[] = {
&attr_current_kb.attr,
&attr_low_kb.attr,
&attr_high_kb.attr,
&attr_hard_limit_kb.attr,
&attr_driver_kb.attr,
NULL
};
Expand Down
3 changes: 3 additions & 0 deletions drivers/xen/events.c
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,9 @@ static void unbind_from_irq(unsigned int irq)
bind_evtchn_to_cpu(evtchn, 0);

evtchn_to_irq[evtchn] = -1;
}

if (irq_info[irq].type != IRQT_UNBOUND) {
irq_info[irq] = mk_unbound_info();

dynamic_irq_cleanup(irq);
Expand Down
37 changes: 24 additions & 13 deletions drivers/xen/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ static int xen_suspend(void *data)
if (err) {
printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
err);
dpm_resume_noirq(PMSG_RESUME);
return err;
}

Expand All @@ -69,7 +68,6 @@ static int xen_suspend(void *data)
}

sysdev_resume();
dpm_resume_noirq(PMSG_RESUME);

return 0;
}
Expand All @@ -81,36 +79,45 @@ static void do_suspend(void)

shutting_down = SHUTDOWN_SUSPEND;

err = stop_machine_create();
if (err) {
printk(KERN_ERR "xen suspend: failed to setup stop_machine %d\n", err);
goto out;
}

#ifdef CONFIG_PREEMPT
/* If the kernel is preemptible, we need to freeze all the processes
to prevent them from being in the middle of a pagetable update
during suspend. */
err = freeze_processes();
if (err) {
printk(KERN_ERR "xen suspend: freeze failed %d\n", err);
return;
goto out_destroy_sm;
}
#endif

err = dpm_suspend_start(PMSG_SUSPEND);
if (err) {
printk(KERN_ERR "xen suspend: dpm_suspend_start %d\n", err);
goto out;
goto out_thaw;
}

printk(KERN_DEBUG "suspending xenstore...\n");
xs_suspend();

err = dpm_suspend_noirq(PMSG_SUSPEND);
if (err) {
printk(KERN_ERR "dpm_suspend_noirq failed: %d\n", err);
goto resume_devices;
goto out_resume;
}

printk(KERN_DEBUG "suspending xenstore...\n");
xs_suspend();

err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));

dpm_resume_noirq(PMSG_RESUME);

if (err) {
printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
goto out;
cancelled = 1;
}

if (!cancelled) {
Expand All @@ -119,17 +126,21 @@ static void do_suspend(void)
} else
xs_suspend_cancel();

dpm_resume_noirq(PMSG_RESUME);

resume_devices:
out_resume:
dpm_resume_end(PMSG_RESUME);

/* Make sure timer events get retriggered on all CPUs */
clock_was_set();
out:

out_thaw:
#ifdef CONFIG_PREEMPT
thaw_processes();

out_destroy_sm:
#endif
stop_machine_destroy();

out:
shutting_down = SHUTDOWN_INVALID;
}
#endif /* CONFIG_PM_SLEEP */
Expand Down
Loading

0 comments on commit ab1831b

Please sign in to comment.