Skip to content

Commit

Permalink
Restore docs "rcu: Restore barrier() to rcu_read_lock() and rcu_read_…
Browse files Browse the repository at this point in the history
…unlock()"

This restores docs back in ReST format.

Signed-off-by: Joel Fernandes (Google) <[email protected]>
[ paulmck: Added Joel's SoB per Stephen Rothwell feedback. ]
[ paulmck: Joel approved via private email. ]
Signed-off-by: Paul E. McKenney <[email protected]>
  • Loading branch information
joelagnel authored and paulmckrcu committed Oct 29, 2019
1 parent d7424e2 commit 71cb46a
Showing 1 changed file with 54 additions and 0 deletions.
54 changes: 54 additions & 0 deletions Documentation/RCU/Design/Requirements/Requirements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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`_
Expand Down Expand Up @@ -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
~~~~~~~~~~~~~~~~~

Expand Down

0 comments on commit 71cb46a

Please sign in to comment.