mirror of https://gitee.com/openkylin/linux.git
Restore docs "rcu: Restore barrier() to rcu_read_lock() and rcu_read_unlock()"
This restores docs back in ReST format. Signed-off-by: Joel Fernandes (Google) <joel@joelfernandes.org> [ paulmck: Added Joel's SoB per Stephen Rothwell feedback. ] [ paulmck: Joel approved via private email. ] Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
This commit is contained in:
parent
d7424e283c
commit
71cb46ae46
|
@ -1691,6 +1691,7 @@ follows:
|
|||
#. `Hotplug CPU`_
|
||||
#. `Scheduler and RCU`_
|
||||
#. `Tracing and RCU`_
|
||||
#. `Accesses to User Memory and RCU`_
|
||||
#. `Energy Efficiency`_
|
||||
#. `Scheduling-Clock Interrupts and RCU`_
|
||||
#. `Memory Efficiency`_
|
||||
|
@ -2004,6 +2005,59 @@ where RCU readers execute in environments in which tracing cannot be
|
|||
used. The tracing folks both located the requirement and provided the
|
||||
needed fix, so this surprise requirement was relatively painless.
|
||||
|
||||
Accesses to User Memory and RCU
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The kernel needs to access user-space memory, for example, to access data
|
||||
referenced by system-call parameters. The ``get_user()`` macro does this job.
|
||||
|
||||
However, user-space memory might well be paged out, which means that
|
||||
``get_user()`` might well page-fault and thus block while waiting for the
|
||||
resulting I/O to complete. It would be a very bad thing for the compiler to
|
||||
reorder a ``get_user()`` invocation into an RCU read-side critical section.
|
||||
|
||||
For example, suppose that the source code looked like this:
|
||||
|
||||
::
|
||||
|
||||
1 rcu_read_lock();
|
||||
2 p = rcu_dereference(gp);
|
||||
3 v = p->value;
|
||||
4 rcu_read_unlock();
|
||||
5 get_user(user_v, user_p);
|
||||
6 do_something_with(v, user_v);
|
||||
|
||||
The compiler must not be permitted to transform this source code into
|
||||
the following:
|
||||
|
||||
::
|
||||
|
||||
1 rcu_read_lock();
|
||||
2 p = rcu_dereference(gp);
|
||||
3 get_user(user_v, user_p); // BUG: POSSIBLE PAGE FAULT!!!
|
||||
4 v = p->value;
|
||||
5 rcu_read_unlock();
|
||||
6 do_something_with(v, user_v);
|
||||
|
||||
If the compiler did make this transformation in a ``CONFIG_PREEMPT=n`` kernel
|
||||
build, and if ``get_user()`` did page fault, the result would be a quiescent
|
||||
state in the middle of an RCU read-side critical section. This misplaced
|
||||
quiescent state could result in line 4 being a use-after-free access,
|
||||
which could be bad for your kernel's actuarial statistics. Similar examples
|
||||
can be constructed with the call to ``get_user()`` preceding the
|
||||
``rcu_read_lock()``.
|
||||
|
||||
Unfortunately, ``get_user()`` doesn't have any particular ordering properties,
|
||||
and in some architectures the underlying ``asm`` isn't even marked
|
||||
``volatile``. And even if it was marked ``volatile``, the above access to
|
||||
``p->value`` is not volatile, so the compiler would not have any reason to keep
|
||||
those two accesses in order.
|
||||
|
||||
Therefore, the Linux-kernel definitions of ``rcu_read_lock()`` and
|
||||
``rcu_read_unlock()`` must act as compiler barriers, at least for outermost
|
||||
instances of ``rcu_read_lock()`` and ``rcu_read_unlock()`` within a nested set
|
||||
of RCU read-side critical sections.
|
||||
|
||||
Energy Efficiency
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
Loading…
Reference in New Issue