Issue
I'm a bit confused about such code:
struct a {
// ...
struct list_head some_list;
// ...
};
struct e {
struct list_head next;
// ...
};
static void *traverse(struct a *a)
{
struct e *e;
rcu_read_lock();
list_for_each_entry_rcu(e, &a->some_list, next) {
if (...) {
rcu_read_unlock();
return e;
}
}
rcu_read_unlock();
return NULL;
}
In the function traverse
we take a lock rcu_read_lock
and then iterate over some list until some condition is met, but after this condition is met we unlock rcu_read_unlock
RCU and return the e
pointer.
The key point that is confusing me is that we unlock RCU read-side critical section, but keep pointer from the list, what if write-side will remove this element and it seems that this pointer e
will be broken, isn't it?
AFAIK, the pointer is valid only inside read-side critical section, i.e. between rcu_read_lock
and rcu_read_unlock
, am I wrong?
P.S.: traverse
is called without holding any locks.
Solution
Your assumptions are right, the snippet of code you posted seems "broken". What you usually want to do in such a situation is something like the following:
static void traverse(struct a *a, void (*callback)(struct e *))
{
struct e *e;
rcu_read_lock();
list_for_each_entry_rcu(e, &a->some_list, next) {
if (...) {
callback(e);
break;
}
}
rcu_read_unlock();
}
This way you can ensure that whatever operation you need to perform on e
, the callback()
function that gets called to use it will see a consistent version of the list (of course, assuming that it does not save e
somewhere to use it later, otherwise we're back at square one).
Doing return e;
after rcu_read_unlock();
can cause trouble as you have noted in your question, but in theory it could still be fine depending on the exact scenario. Whether there's a problem or not only depends on what is done with e
after it is returned.
For example, if e
is simply checked in the caller with something like if (e != NULL) {...}
then that'd be fine. Of course though, one could argue that you could have just made the traverse
function return a bool
in such case :')
Answered By - Marco Bonelli Answer Checked By - Candace Johnson (WPSolving Volunteer)