Skip to content

Commit

Permalink
Merge tag 'for-linus-4.2-rc5-tag' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/xen/tip

Pull xen bug fixes from David Vrabel:

 - don't lose interrupts when offlining CPUs

 - fix gntdev oops during unmap

 - drop the balloon lock occasionally to allow domain create/destroy

* tag 'for-linus-4.2-rc5-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/xen/tip:
  xen/events/fifo: Handle linked events when closing a port
  xen: release lock occasionally during ballooning
  xen/gntdevt: Fix race condition in gntdev_release()
  • Loading branch information
Linus Torvalds committed Aug 4, 2015
2 parents ed8bbba + fcdf31a commit 1ddc6dd
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 17 deletions.
15 changes: 7 additions & 8 deletions drivers/xen/balloon.c
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
}

/*
* We avoid multiple worker processes conflicting via the balloon mutex.
* As this is a work item it is guaranteed to run as a single instance only.
* We may of course race updates of the target counts (which are protected
* by the balloon lock), or with changes to the Xen hard limit, but we will
* recover from these in time.
Expand All @@ -482,9 +482,10 @@ static void balloon_process(struct work_struct *work)
enum bp_state state = BP_DONE;
long credit;

mutex_lock(&balloon_mutex);

do {
mutex_lock(&balloon_mutex);

credit = current_credit();

if (credit > 0) {
Expand All @@ -499,17 +500,15 @@ static void balloon_process(struct work_struct *work)

state = update_schedule(state);

#ifndef CONFIG_PREEMPT
if (need_resched())
schedule();
#endif
mutex_unlock(&balloon_mutex);

cond_resched();

} while (credit && state == BP_DONE);

/* Schedule more work if there is some still to be done. */
if (state == BP_EAGAIN)
schedule_delayed_work(&balloon_worker, balloon_stats.schedule_delay * HZ);

mutex_unlock(&balloon_mutex);
}

/* Resets the Xen limit, sets new target, and kicks off processing. */
Expand Down
10 changes: 6 additions & 4 deletions drivers/xen/events/events_base.c
Original file line number Diff line number Diff line change
Expand Up @@ -452,10 +452,12 @@ static void xen_free_irq(unsigned irq)
irq_free_desc(irq);
}

static void xen_evtchn_close(unsigned int port)
static void xen_evtchn_close(unsigned int port, unsigned int cpu)
{
struct evtchn_close close;

xen_evtchn_op_close(port, cpu);

close.port = port;
if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
BUG();
Expand Down Expand Up @@ -544,7 +546,7 @@ static unsigned int __startup_pirq(unsigned int irq)

err:
pr_err("irq%d: Failed to set port to irq mapping (%d)\n", irq, rc);
xen_evtchn_close(evtchn);
xen_evtchn_close(evtchn, NR_CPUS);
return 0;
}

Expand All @@ -565,7 +567,7 @@ static void shutdown_pirq(struct irq_data *data)
return;

mask_evtchn(evtchn);
xen_evtchn_close(evtchn);
xen_evtchn_close(evtchn, cpu_from_evtchn(evtchn));
xen_irq_info_cleanup(info);
}

Expand Down Expand Up @@ -609,7 +611,7 @@ static void __unbind_from_irq(unsigned int irq)
if (VALID_EVTCHN(evtchn)) {
unsigned int cpu = cpu_from_irq(irq);

xen_evtchn_close(evtchn);
xen_evtchn_close(evtchn, cpu);

switch (type_from_irq(irq)) {
case IRQT_VIRQ:
Expand Down
45 changes: 40 additions & 5 deletions drivers/xen/events/events_fifo.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ static void evtchn_fifo_unmask(unsigned port)
}
}

static bool evtchn_fifo_is_linked(unsigned port)
{
event_word_t *word = event_word_from_port(port);
return sync_test_bit(EVTCHN_FIFO_BIT(LINKED, word), BM(word));
}

static uint32_t clear_linked(volatile event_word_t *word)
{
event_word_t new, old, w;
Expand All @@ -281,7 +287,8 @@ static void handle_irq_for_port(unsigned port)

static void consume_one_event(unsigned cpu,
struct evtchn_fifo_control_block *control_block,
unsigned priority, unsigned long *ready)
unsigned priority, unsigned long *ready,
bool drop)
{
struct evtchn_fifo_queue *q = &per_cpu(cpu_queue, cpu);
uint32_t head;
Expand Down Expand Up @@ -313,13 +320,15 @@ static void consume_one_event(unsigned cpu,
if (head == 0)
clear_bit(priority, ready);

if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port))
handle_irq_for_port(port);
if (evtchn_fifo_is_pending(port) && !evtchn_fifo_is_masked(port)) {
if (likely(!drop))
handle_irq_for_port(port);
}

q->head[priority] = head;
}

static void evtchn_fifo_handle_events(unsigned cpu)
static void __evtchn_fifo_handle_events(unsigned cpu, bool drop)
{
struct evtchn_fifo_control_block *control_block;
unsigned long ready;
Expand All @@ -331,11 +340,16 @@ static void evtchn_fifo_handle_events(unsigned cpu)

while (ready) {
q = find_first_bit(&ready, EVTCHN_FIFO_MAX_QUEUES);
consume_one_event(cpu, control_block, q, &ready);
consume_one_event(cpu, control_block, q, &ready, drop);
ready |= xchg(&control_block->ready, 0);
}
}

static void evtchn_fifo_handle_events(unsigned cpu)
{
__evtchn_fifo_handle_events(cpu, false);
}

static void evtchn_fifo_resume(void)
{
unsigned cpu;
Expand Down Expand Up @@ -371,6 +385,26 @@ static void evtchn_fifo_resume(void)
event_array_pages = 0;
}

static void evtchn_fifo_close(unsigned port, unsigned int cpu)
{
if (cpu == NR_CPUS)
return;

get_online_cpus();
if (cpu_online(cpu)) {
if (WARN_ON(irqs_disabled()))
goto out;

while (evtchn_fifo_is_linked(port))
cpu_relax();
} else {
__evtchn_fifo_handle_events(cpu, true);
}

out:
put_online_cpus();
}

static const struct evtchn_ops evtchn_ops_fifo = {
.max_channels = evtchn_fifo_max_channels,
.nr_channels = evtchn_fifo_nr_channels,
Expand All @@ -384,6 +418,7 @@ static const struct evtchn_ops evtchn_ops_fifo = {
.unmask = evtchn_fifo_unmask,
.handle_events = evtchn_fifo_handle_events,
.resume = evtchn_fifo_resume,
.close = evtchn_fifo_close,
};

static int evtchn_fifo_alloc_control_block(unsigned cpu)
Expand Down
7 changes: 7 additions & 0 deletions drivers/xen/events/events_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ struct evtchn_ops {
bool (*test_and_set_mask)(unsigned port);
void (*mask)(unsigned port);
void (*unmask)(unsigned port);
void (*close)(unsigned port, unsigned cpu);

void (*handle_events)(unsigned cpu);
void (*resume)(void);
Expand Down Expand Up @@ -145,6 +146,12 @@ static inline void xen_evtchn_resume(void)
evtchn_ops->resume();
}

static inline void xen_evtchn_op_close(unsigned port, unsigned cpu)
{
if (evtchn_ops->close)
return evtchn_ops->close(port, cpu);
}

void xen_evtchn_2l_init(void);
int xen_evtchn_fifo_init(void);

Expand Down
2 changes: 2 additions & 0 deletions drivers/xen/gntdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -568,12 +568,14 @@ static int gntdev_release(struct inode *inode, struct file *flip)

pr_debug("priv %p\n", priv);

mutex_lock(&priv->lock);
while (!list_empty(&priv->maps)) {
map = list_entry(priv->maps.next, struct grant_map, next);
list_del(&map->next);
gntdev_put_map(NULL /* already removed */, map);
}
WARN_ON(!list_empty(&priv->freeable_maps));
mutex_unlock(&priv->lock);

if (use_ptemod)
mmu_notifier_unregister(&priv->mn, priv->mm);
Expand Down

0 comments on commit 1ddc6dd

Please sign in to comment.