Documentation/RCU/Design/Requirements/Requirements.rst

Source file repositories/reference/linux-study-clean/Documentation/RCU/Design/Requirements/Requirements.rst

File Facts

System
Linux kernel
Corpus path
Documentation/RCU/Design/Requirements/Requirements.rst
Extension
.rst
Size
141888 bytes
Lines
2874
Domain
Support Tooling And Documentation
Bucket
Documentation
Inferred role
Support Tooling And Documentation: documentation
Status
atlas-only

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

7   if (rcu_access_pointer(gp)) {
       8     spin_unlock(&gp_lock);
       9     return false;
      10   }
      11   p->a = a;
      12   p->b = a;
      13   gp = p; /* ORDERING BUG */
      14   spin_unlock(&gp_lock);
      15   return true;
      16 }

The problem is that both the compiler and weakly ordered CPUs are within
their rights to reorder this code as follows:

   ::

       1 bool add_gp_buggy_optimized(int a, int b)
       2 {
       3   p = kmalloc_obj(*p);
       4   if (!p)
       5     return -ENOMEM;
       6   spin_lock(&gp_lock);
       7   if (rcu_access_pointer(gp)) {
       8     spin_unlock(&gp_lock);
       9     return false;
      10   }
      11   gp = p; /* ORDERING BUG */
      12   p->a = a;
      13   p->b = a;
      14   spin_unlock(&gp_lock);
      15   return true;
      16 }

If an RCU reader fetches ``gp`` just after ``add_gp_buggy_optimized``
executes lineĀ 11, it will see garbage in the ``->a`` and ``->b`` fields.
And this is but one of many ways in which compiler and hardware
optimizations could cause trouble. Therefore, we clearly need some way
to prevent the compiler and the CPU from reordering in this manner,
which brings us to the publish-subscribe guarantee discussed in the next
section.

Publish/Subscribe Guarantee
~~~~~~~~~~~~~~~~~~~~~~~~~~~

RCU's publish-subscribe guarantee allows data to be inserted into a
linked data structure without disrupting RCU readers. The updater uses
rcu_assign_pointer() to insert the new data, and readers use
rcu_dereference() to access data, whether new or old. The following
shows an example of insertion:

   ::

       1 bool add_gp(int a, int b)
       2 {
       3   p = kmalloc_obj(*p);
       4   if (!p)
       5     return -ENOMEM;
       6   spin_lock(&gp_lock);
       7   if (rcu_access_pointer(gp)) {
       8     spin_unlock(&gp_lock);
       9     return false;
      10   }
      11   p->a = a;
      12   p->b = a;
      13   rcu_assign_pointer(gp, p);
      14   spin_unlock(&gp_lock);
      15   return true;
      16 }

The rcu_assign_pointer() on lineĀ 13 is conceptually equivalent to a

Annotation

Implementation Notes