I store a RCU protected pointer MyStruct *, in a RCU protected hashtable MyHash. When reading/updating MyStruct via hashtable, I do as shown below.
rcu_read_lock() /* For hashtable 'MyHash' */
hash_for_each_possible_rcu(MyHash, obj, member, key)
{
rcu_read_lock(); /* For RCU protected data(MyStruct*) stored in hashtable */
Mystruct* s = rcu_dereference_pointer(obj->s);
if(s)
{
s->read++;
}
rcu_read_unlock(); /* For RCU protected data(MyStruct*) stored in hashtable */
}
rcu_read_unlock() /* For hashtable 'MyHash'*/
Note that MyStruct is itself part of another RCU protected list ( i.e it is a RCU protected node of another list), which is stored in MyHash for faster lookup.
As I understand, rcu_read_lock's are required to make sure any writer update doesn't free up memory until all read-side critical sections are complete. So, is it really necessary to nest rcu_read_lock's or just having the outer rcu_read_lock/rcu_read_unlock is sufficient?
IOW, since RCU locks are not tied to any single object, do we really need nested rcu locks when accessing multiple RCU protected objects together?
No, nested
rcu_read_lock()is not required.Similar to other "nested" critical sections, the only effect of nested
rcu_read_lockis increment of the lock level. That is, futherrcu_read_unlockdoes not immediately end critical section but just revert lock level back.However, supporting nested locking is treated as an advantage of RCU locking mechanism. Having supported nested operations one may develop components independently one from others.
E.g., you may have
object_incrementfunction which can be safely called without RCU lock:Then call this function under RCU lock:
Simple design is almost always outweigh small performance hit from the nested calls to
rcu_read_lock.Without nested calls allowed one would need to implement another component's function for access with RCU lock:
and carefully choose which function - locked or non-locked - to use in concrete situations: