Commit b865c2c6 authored by John Garry's avatar John Garry Committed by Greg Kroah-Hartman

lib: logic_pio: Fix RCU usage

commit 06709e81 upstream.

The traversing of io_range_list with list_for_each_entry_rcu()
is not properly protected by rcu_read_lock() and rcu_read_unlock(),
so add them.

These functions mark the critical section scope where the list is
protected for the reader, it cannot be  "reclaimed". Any updater - in
this case, the logical PIO registration functions - cannot update the
list until the reader exits this critical section.

In addition, the list traversing used in logic_pio_register_range()
does not need to use the rcu variant.

This is because we are already using io_range_mutex to guarantee mutual
exclusion from mutating the list.

Cc: stable@vger.kernel.org
Fixes: 031e3601 ("lib: Add generic PIO mapping method")
Signed-off-by: default avatarJohn Garry <john.garry@huawei.com>
Signed-off-by: default avatarWei Xu <xuwei5@hisilicon.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 79829fc4
...@@ -46,7 +46,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range) ...@@ -46,7 +46,7 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
end = new_range->hw_start + new_range->size; end = new_range->hw_start + new_range->size;
mutex_lock(&io_range_mutex); mutex_lock(&io_range_mutex);
list_for_each_entry_rcu(range, &io_range_list, list) { list_for_each_entry(range, &io_range_list, list) {
if (range->fwnode == new_range->fwnode) { if (range->fwnode == new_range->fwnode) {
/* range already there */ /* range already there */
goto end_register; goto end_register;
...@@ -108,26 +108,38 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range) ...@@ -108,26 +108,38 @@ int logic_pio_register_range(struct logic_pio_hwaddr *new_range)
*/ */
struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode) struct logic_pio_hwaddr *find_io_range_by_fwnode(struct fwnode_handle *fwnode)
{ {
struct logic_pio_hwaddr *range; struct logic_pio_hwaddr *range, *found_range = NULL;
rcu_read_lock();
list_for_each_entry_rcu(range, &io_range_list, list) { list_for_each_entry_rcu(range, &io_range_list, list) {
if (range->fwnode == fwnode) if (range->fwnode == fwnode) {
return range; found_range = range;
break;
} }
return NULL; }
rcu_read_unlock();
return found_range;
} }
/* Return a registered range given an input PIO token */ /* Return a registered range given an input PIO token */
static struct logic_pio_hwaddr *find_io_range(unsigned long pio) static struct logic_pio_hwaddr *find_io_range(unsigned long pio)
{ {
struct logic_pio_hwaddr *range; struct logic_pio_hwaddr *range, *found_range = NULL;
rcu_read_lock();
list_for_each_entry_rcu(range, &io_range_list, list) { list_for_each_entry_rcu(range, &io_range_list, list) {
if (in_range(pio, range->io_start, range->size)) if (in_range(pio, range->io_start, range->size)) {
return range; found_range = range;
break;
}
} }
pr_err("PIO entry token %lx invalid\n", pio); rcu_read_unlock();
return NULL;
if (!found_range)
pr_err("PIO entry token 0x%lx invalid\n", pio);
return found_range;
} }
/** /**
...@@ -180,14 +192,23 @@ unsigned long logic_pio_trans_cpuaddr(resource_size_t addr) ...@@ -180,14 +192,23 @@ unsigned long logic_pio_trans_cpuaddr(resource_size_t addr)
{ {
struct logic_pio_hwaddr *range; struct logic_pio_hwaddr *range;
rcu_read_lock();
list_for_each_entry_rcu(range, &io_range_list, list) { list_for_each_entry_rcu(range, &io_range_list, list) {
if (range->flags != LOGIC_PIO_CPU_MMIO) if (range->flags != LOGIC_PIO_CPU_MMIO)
continue; continue;
if (in_range(addr, range->hw_start, range->size)) if (in_range(addr, range->hw_start, range->size)) {
return addr - range->hw_start + range->io_start; unsigned long cpuaddr;
cpuaddr = addr - range->hw_start + range->io_start;
rcu_read_unlock();
return cpuaddr;
} }
pr_err("addr %llx not registered in io_range_list\n", }
(unsigned long long) addr); rcu_read_unlock();
pr_err("addr %pa not registered in io_range_list\n", &addr);
return ~0UL; return ~0UL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment