Reputation: 1138
I have a boilerplate function that finds a structure in a tree-like database:
struct foo {
struct foo *child1; /* RCU-protected. */
struct foo *child2; /* RCU-protected. */
... /* Other stuff */
}
static struct foo *find_foo(int arg)
{
struct foo *parent;
... /* Do something to find parent. */
return rcu_dereference(parent->child1); /* or child2. Whatever. */
}
And then I have several functions that do something with that result:
void a(int arg)
{
struct foo *bar;
rcu_read_lock();
bar = find_foo(arg);
... /* Read something from bar and do something with it. */
rcu_read_unlock();
}
And then I have a single updater/reclaimer. It needs to find the object just like the "a" functions (Assume it's already mutex'd from outside):
void c(int arg)
{
struct foo *bar;
bar = find_foo(arg);
... /* make a backup pointer of bar->child1. */
rcu_assign_pointer(bar->child1, ...);
... /* free the old child or whatever. */
}
My problem is, rcu_dereference()
's documentation says it must be called from within a read-side critical section (ie. between rcu_read_lock()
and rcu_read_unlock()
). c()
violates this rule by calling find_foo()
.
I'm hesitant to make a whole new version of find_foo()
which uses rcu_dereference_protected()
instead of rcu_dereference()
, because it's too much duplicate code, so I'm wondering if this implementation of c()
is legal:
void c(int arg)
{
struct foo *bar;
rcu_read_lock();
bar = find_foo(arg);
bar = rcu_dereference_protected(bar, ...); /* THIS. */
rcu_read_unlock();
... /* make a backup pointer of bar->child1. */
rcu_assign_pointer(bar->child1, ...);
... /* free the old child or whatever. */
}
If this is not legal, how should I instead be mixing reader and updater code?
Upvotes: 1
Views: 195
Reputation: 66061
Actually, the first variant of c()
is correct (no specific dereference is needed on updater side), but it makes rcu checker to be confused (the checker expects rcu_dereference
occured under rcu_read
section).
The second variant of c()
is correct even from the view of rcu checker, but rcu_dereference_protected
is not need: bar
is already result of rcu_dereference
.
Another way for make rcu checker happy is to use
rcu_dereference_check(<pointer>, <condition-when-in-updater>)
instead of
rcu_dereference(<pointer>)
inside foo
implementation. So checker will not complain on foo() call outside of rcu_read
section until it can prove that condition is false
in that case.
With such foo()
implementation the first variant of c()
is OK.
Upvotes: 1