Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aac1cda3 authored by Paul E. McKenney's avatar Paul E. McKenney
Browse files

Merge branches 'urgent.2012.10.27a', 'doc.2012.11.16a', 'fixes.2012.11.13a',...

Merge branches 'urgent.2012.10.27a', 'doc.2012.11.16a', 'fixes.2012.11.13a', 'srcu.2012.10.27a', 'stall.2012.11.13a', 'tracing.2012.11.08a' and 'idle.2012.10.24a' into HEAD

urgent.2012.10.27a: Fix for RCU user-mode transition (already in -tip).

doc.2012.11.08a: Documentation updates, most notably codifying the
	memory-barrier guarantees inherent to grace periods.

fixes.2012.11.13a: Miscellaneous fixes.

srcu.2012.10.27a: Allow statically allocated and initialized srcu_struct
	structures (courtesy of Lai Jiangshan).

stall.2012.11.13a: Add more diagnostic information to RCU CPU stall
	warnings, also decrease from 60 seconds to 21 seconds.

hotplug.2012.11.08a: Minor updates to CPU hotplug handling.

tracing.2012.11.08a: Improved debugfs tracing, courtesy of Michael Wang.

idle.2012.10.24a: Updates to RCU idle/adaptive-idle handling, including
	a boot parameter that maps normal grace periods to expedited.

Resolved conflict in kernel/rcutree.c due to side-by-side change.
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -186,7 +186,7 @@ Bibtex Entries

@article{Kung80
,author="H. T. Kung and Q. Lehman"
,title="Concurrent Maintenance of Binary Search Trees"
,title="Concurrent Manipulation of Binary Search Trees"
,Year="1980"
,Month="September"
,journal="ACM Transactions on Database Systems"
+8 −9
Original line number Diff line number Diff line
@@ -271,15 +271,14 @@ over a rather long period of time, but improvements are always welcome!
	The same cautions apply to call_rcu_bh() and call_rcu_sched().

9.	All RCU list-traversal primitives, which include
	rcu_dereference(), list_for_each_entry_rcu(),
	list_for_each_continue_rcu(), and list_for_each_safe_rcu(),
	must be either within an RCU read-side critical section or
	must be protected by appropriate update-side locks.  RCU
	read-side critical sections are delimited by rcu_read_lock()
	and rcu_read_unlock(), or by similar primitives such as
	rcu_read_lock_bh() and rcu_read_unlock_bh(), in which case
	the matching rcu_dereference() primitive must be used in order
	to keep lockdep happy, in this case, rcu_dereference_bh().
	rcu_dereference(), list_for_each_entry_rcu(), and
	list_for_each_safe_rcu(), must be either within an RCU read-side
	critical section or must be protected by appropriate update-side
	locks.	RCU read-side critical sections are delimited by
	rcu_read_lock() and rcu_read_unlock(), or by similar primitives
	such as rcu_read_lock_bh() and rcu_read_unlock_bh(), in which
	case the matching rcu_dereference() primitive must be used in
	order to keep lockdep happy, in this case, rcu_dereference_bh().

	The reason that it is permissible to use RCU list-traversal
	primitives when the update-side lock is held is that doing so
+1 −1
Original line number Diff line number Diff line
@@ -205,7 +205,7 @@ RCU ("read-copy update") its name. The RCU code is as follows:
				audit_copy_rule(&ne->rule, &e->rule);
				ne->rule.action = newaction;
				ne->rule.file_count = newfield_count;
				list_replace_rcu(e, ne);
				list_replace_rcu(&e->list, &ne->list);
				call_rcu(&e->rcu, audit_free_rule);
				return 0;
			}
+59 −2
Original line number Diff line number Diff line
@@ -20,7 +20,7 @@ release_referenced() delete()
{					{
    ...					    write_lock(&list_lock);
    atomic_dec(&el->rc, relfunc)	    ...
    ...					    delete_element
    ...					    remove_element
}					    write_unlock(&list_lock);
 					    ...
					    if (atomic_dec_and_test(&el->rc))
@@ -52,7 +52,7 @@ release_referenced() delete()
{					{
    ...					    spin_lock(&list_lock);
    if (atomic_dec_and_test(&el->rc))       ...
        call_rcu(&el->head, el_free);       delete_element
        call_rcu(&el->head, el_free);       remove_element
    ...                                     spin_unlock(&list_lock);
} 					    ...
					    if (atomic_dec_and_test(&el->rc))
@@ -64,3 +64,60 @@ Sometimes, a reference to the element needs to be obtained in the
update (write) stream.  In such cases, atomic_inc_not_zero() might be
overkill, since we hold the update-side spinlock.  One might instead
use atomic_inc() in such cases.

It is not always convenient to deal with "FAIL" in the
search_and_reference() code path.  In such cases, the
atomic_dec_and_test() may be moved from delete() to el_free()
as follows:

1.					2.
add()					search_and_reference()
{					{
    alloc_object			    rcu_read_lock();
    ...					    search_for_element
    atomic_set(&el->rc, 1);		    atomic_inc(&el->rc);
    spin_lock(&list_lock);		    ...

    add_element				    rcu_read_unlock();
    ...					}
    spin_unlock(&list_lock);		4.
}					delete()
3.					{
release_referenced()			    spin_lock(&list_lock);
{					    ...
    ...					    remove_element
    if (atomic_dec_and_test(&el->rc))       spin_unlock(&list_lock);
        kfree(el);			    ...
    ...                                     call_rcu(&el->head, el_free);
} 					    ...
5.					}
void el_free(struct rcu_head *rhp)
{
    release_referenced();
}

The key point is that the initial reference added by add() is not removed
until after a grace period has elapsed following removal.  This means that
search_and_reference() cannot find this element, which means that the value
of el->rc cannot increase.  Thus, once it reaches zero, there are no
readers that can or ever will be able to reference the element.  The
element can therefore safely be freed.  This in turn guarantees that if
any reader finds the element, that reader may safely acquire a reference
without checking the value of the reference counter.

In cases where delete() can sleep, synchronize_rcu() can be called from
delete(), so that el_free() can be subsumed into delete as follows:

4.
delete()
{
    spin_lock(&list_lock);
    ...
    remove_element
    spin_unlock(&list_lock);
    ...
    synchronize_rcu();
    if (atomic_dec_and_test(&el->rc))
    	kfree(el);
    ...
}
+218 −178

File changed.

Preview size limit exceeded, changes collapsed.

Loading