Thread (20 messages) 20 messages, 5 authors, 2012-06-29

Re: needed lru_add_drain_all() change

From: Kamezawa Hiroyuki <hidden>
Date: 2012-06-28 07:46:13

(2012/06/27 6:37), Andrew Morton wrote:
https://bugzilla.kernel.org/show_bug.cgi?id=43811

lru_add_drain_all() uses schedule_on_each_cpu().  But
schedule_on_each_cpu() hangs if a realtime thread is spinning, pinned
to a CPU.  There's no intention to change the scheduler behaviour, so I
think we should remove schedule_on_each_cpu() from the kernel.

The biggest user of schedule_on_each_cpu() is lru_add_drain_all().

Does anyone have any thoughts on how we can do this?  The obvious
approach is to declare these:

static DEFINE_PER_CPU(struct pagevec[NR_LRU_LISTS], lru_add_pvecs);
static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs);
static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs);

to be irq-safe and use on_each_cpu().  lru_rotate_pvecs is already
irq-safe and converting lru_add_pvecs and lru_deactivate_pvecs looks
pretty simple.

Thoughts?
How about this kind of RCU synchronization ?
==
/*
  * Double buffered pagevec for quick drain.
  * The usual per-cpu-pvec user need to take rcu_read_lock() before accessing.
  * External drainer of pvecs will relpace pvec vector and call synchroize_rcu(),
  * and drain all pages on unused pvecs in turn.
  */
static DEFINE_PER_CPU(struct pagevec[NR_LRU_LISTS * 2], lru_pvecs);

atomic_t pvec_idx; /* must be placed onto some aligned address...*/


struct pagevec *my_pagevec(enum lru)
{
	return  pvec = &__get_cpu_var(lru_pvecs[lru << atomic_read(pvec_idx)]);
}

/*
  * percpu pagevec access should be surrounded by these calls.
  */
static inline void pagevec_start_access()
{
	rcu_read_lock();
}

static inline void pagevec_end_access()
{
	rcu_read_unlock();
}


/*
  * changing pagevec array vec 0 <-> 1
  */
static void lru_pvec_update()
{
	if (atomic_read(&pvec_idx))
		atomic_set(&pvec_idx, 0);
	else
		atomic_set(&pvec_idx, 1);
}

/*
  * drain all LRUS on per-cpu pagevecs.
  */
DEFINE_MUTEX(lru_add_drain_all_mutex);
static void lru_add_drain_all()
{
	mutex_lock(&lru_add_drain_mutex);
	lru_pvec_update();
	synchronize_rcu();  /* waits for all accessors to pvec quits. */
	for_each_cpu(cpu)
		drain_pvec_of_the_cpu(cpu);
	mutex_unlock(&lru_add_drain_mutex);
}
==














--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help