linux/Documentation/core-api
Suren Baghdasaryan 7f8ceea0c5 refcount: provide ops for cases when object's memory can be reused
For speculative lookups where a successful inc_not_zero() pins the object,
but where we still need to double check if the object acquired is indeed
the one we set out to acquire (identity check), needs this validation to
happen *after* the increment.  Similarly, when a new object is initialized
and its memory might have been previously occupied by another object, all
stores to initialize the object should happen *before* refcount
initialization.

Notably SLAB_TYPESAFE_BY_RCU is one such an example when this ordering is
required for reference counting.

Add refcount_{add|inc}_not_zero_acquire() to guarantee the proper ordering
between acquiring a reference count on an object and performing the
identity check for that object.

Add refcount_set_release() to guarantee proper ordering between stores
initializing object attributes and the store initializing the refcount. 
refcount_set_release() should be done after all other object attributes
are initialized.  Once refcount_set_release() is called, the object should
be considered visible to other tasks even if it was not yet added into an
object collection normally used to discover it.  This is because other
tasks might have discovered the object previously occupying the same
memory and after memory reuse they can succeed in taking refcount for the
new object and start using it.

Object reuse example to consider:

consumer:
    obj = lookup(collection, key);
    if (!refcount_inc_not_zero_acquire(&obj->ref))
        return;
    if (READ_ONCE(obj->key) != key) { /* identity check */
        put_ref(obj);
        return;
    }
    use(obj->value);

                 producer:
                     remove(collection, obj->key);
                     if (!refcount_dec_and_test(&obj->ref))
                         return;
                     obj->key = KEY_INVALID;
                     free(obj);
                     obj = malloc(); /* obj is reused */
                     obj->key = new_key;
                     obj->value = new_value;
                     refcount_set_release(obj->ref, 1);
                     add(collection, new_key, obj);

refcount_{add|inc}_not_zero_acquire() is required to prevent the following
reordering when refcount_inc_not_zero() is used instead:

consumer:
    obj = lookup(collection, key);
    if (READ_ONCE(obj->key) != key) { /* reordered identity check */
        put_ref(obj);
        return;
    }
                 producer:
                     remove(collection, obj->key);
                     if (!refcount_dec_and_test(&obj->ref))
                         return;
                     obj->key = KEY_INVALID;
                     free(obj);
                     obj = malloc(); /* obj is reused */
                     obj->key = new_key;
                     obj->value = new_value;
                     refcount_set_release(obj->ref, 1);
                     add(collection, new_key, obj);

    if (!refcount_inc_not_zero(&obj->ref))
        return;
    use(obj->value); /* USING WRONG OBJECT */

refcount_set_release() is required to prevent the following reordering
when refcount_set() is used instead:

consumer:
    obj = lookup(collection, key);

                 producer:
                     remove(collection, obj->key);
                     if (!refcount_dec_and_test(&obj->ref))
                         return;
                     obj->key = KEY_INVALID;
                     free(obj);
                     obj = malloc(); /* obj is reused */
                     obj->key = new_key; /* new_key == old_key */
                     refcount_set(obj->ref, 1);

    if (!refcount_inc_not_zero_acquire(&obj->ref))
        return;
    if (READ_ONCE(obj->key) != key) { /* pass since new_key == old_key */
        put_ref(obj);
        return;
    }
    use(obj->value); /* USING STALE obj->value */

                     obj->value = new_value; /* reordered store */
                     add(collection, key, obj);

[surenb@google.com: fix title underlines in refcount-vs-atomic.rst]
  Link: https://lkml.kernel.org/r/20250217161645.3137927-1-surenb@google.com
Link: https://lkml.kernel.org/r/20250213224655.1680278-11-surenb@google.com
Signed-off-by: Suren Baghdasaryan <surenb@google.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>	[slab]
Tested-by: Shivank Garg <shivankg@amd.com>
  Link: https://lkml.kernel.org/r/5e19ec93-8307-47c2-bb13-3ddf7150624e@amd.com
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will@kernel.org>
Cc: Paul E. McKenney <paulmck@kernel.org>
Cc: Christian Brauner <brauner@kernel.org>
Cc: David Hildenbrand <david@redhat.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: Hugh Dickins <hughd@google.com>
Cc: Jann Horn <jannh@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Klara Modin <klarasmodin@gmail.com>
Cc: Liam R. Howlett <Liam.Howlett@Oracle.com>
Cc: Lokesh Gidra <lokeshgidra@google.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Mateusz Guzik <mjguzik@gmail.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Mel Gorman <mgorman@techsingularity.net>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Minchan Kim <minchan@google.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Pasha Tatashin <pasha.tatashin@soleen.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Shakeel Butt <shakeel.butt@linux.dev>
Cc: Sourav Panda <souravpanda@google.com>
Cc: Wei Yang <richard.weiyang@gmail.com>
Cc: Heiko Carstens <hca@linux.ibm.com>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
History 2025-03-16 22:06:19 -07:00
..
irq Documentation: irqdomain: Fix typo of "at least once" 2022-08-18 11:11:52 -06:00
wrappers docs: put atomic*.txt and memory-barriers.txt into the core-api book 2022-09-29 12:55:06 -06:00
asm-annotations.rst docs: move x86 documentation into Documentation/arch/ 2023-03-30 12:58:51 -06:00
assoc_array.rst Documentation: Use "while" instead of "whilst" 2018-11-20 09:30:43 -07:00
boot-time-mm.rst docs/boot-time-mm: remove bootmem documentation 2018-10-31 08:54:16 -07:00
cachetlb.rst mm: remove ARCH_IMPLEMENTS_FLUSH_DCACHE_FOLIO 2023-08-24 16:20:19 -07:00
cgroup.rst doc/cgroup: Fix title underline length 2025-01-15 09:46:18 +01:00
circular-buffers.rst doc: Remove ".vnet" from paulmck email addresses 2019-05-28 09:02:57 -07:00
cleanup.rst cleanup: Add usage and style documentation 2024-08-05 16:54:41 +02:00
cpu_hotplug.rst Documentation: core-api/cpuhotplug: Fix missing prefix 2024-10-07 11:50:54 -06:00
debug-objects.rst doc: debugobjects: actually pull in the kerneldoc comments 2016-11-29 14:44:14 -07:00
debugging-via-ohci1394.rst Documentation: Drop or replace remaining mentions of IA64 2023-09-11 08:13:18 +00:00
dma-api-howto.rst docs: dma: correct dma_set_mask() sample code 2024-04-02 10:07:15 -06:00
dma-api.rst docs: dma-api: Fix description of the sync_sg API 2023-11-17 08:52:13 -07:00
dma-attributes.rst Reinstate some of "swiotlb: rework "fix info leak with DMA_FROM_DEVICE"" 2022-03-28 11:37:05 -07:00
dma-isa-lpc.rst docs: core-api: avoid using ReST :doc:foo markup 2021-06-17 13:24:37 -06:00
entry.rst Docs: typos/spelling 2024-05-02 10:02:29 -06:00
errseq.rst errseq: Add to documentation tree 2018-01-01 12:40:27 -07:00
floating-point.rst arch: add ARCH_HAS_KERNEL_FPU_SUPPORT 2024-05-19 14:36:17 -07:00
folio_queue.rst netfs: Add folio_queue API documentation 2024-09-30 14:10:51 +02:00
genalloc.rst lib/genalloc.c: rename addr_in_gen_pool to gen_pool_has_addr 2019-12-04 19:44:13 -08:00
generic-radix-tree.rst generic radix trees 2019-03-12 10:04:02 -07:00
genericirq.rst Updates for the interrupt subsystem: 2024-07-22 13:52:05 -07:00
gfp_mask-from-fs-io.rst docs: core-api/gfp_mask-from-fs-io: indicate that vmalloc supports GFP_NOFS/GFP_NOIO 2024-11-22 10:42:37 -07:00
idr.rst IDR: Note that the IDR API is deprecated 2022-07-10 21:17:30 -04:00
index.rst Documentation changes this time around include: 2025-01-21 18:00:00 -08:00
kernel-api.rst Documentation: core-api: Drop :export: for int_log.h 2023-07-25 17:40:25 +01:00
kobject.rst kobject documentation: remove default_attrs information 2022-01-07 11:23:37 +01:00
kref.rst kref: Improve documentation 2024-12-13 08:49:31 -07:00
librs.rst docs-rst: convert librs book to ReST 2017-05-16 08:44:16 -03:00
local_ops.rst timers: Update the documentation to reflect on the new timer_shutdown() API 2022-11-24 15:09:12 +01:00
maple_tree.rst maple_tree: update the documentation of maple tree 2023-12-10 16:51:32 -08:00
memory-allocation.rst docs/core-api: memory-allocation: GFP_NOWAIT doesn't need __GFP_NOWARN 2024-07-29 15:10:25 -06:00
memory-hotplug.rst mm/memory_hotplug: remove HIGHMEM leftovers 2021-11-06 13:30:42 -07:00
min_heap.rst Documentation/core-api: min_heap: add author information 2025-01-12 20:20:57 -08:00
mm-api.rst mm/slab, docs: switch mm-api docs generation from slab.c to slub.c 2023-12-05 11:11:34 +01:00
netlink.rst doc/netlink: Update genetlink-legacy documentation 2023-08-27 17:17:09 -07:00
packing.rst lib: packing: document recently added APIs 2024-12-11 20:13:00 -08:00
padata.rst Documentation: core-api: padata: correct spelling 2023-02-16 16:58:01 -07:00
parser.rst Documentation: core-api: add generic parser docbook 2024-12-11 09:07:40 -07:00
pin_user_pages.rst mm: remove page_mkclean() 2024-07-03 19:30:17 -07:00
printk-basics.rst printk: Move the printk() kerneldoc comment to its new home 2021-07-26 12:36:44 +02:00
printk-formats.rst printf: Add print format (%pra) for struct range 2024-10-28 14:32:43 -07:00
printk-index.rst docs:core-api: fixed typos and grammar in printk-index page 2024-05-07 08:01:11 -06:00
protection-keys.rst Documentation/protection-keys: add AArch64 to documentation 2024-10-14 17:27:48 +01:00
rbtree.rst docs: rbtree.rst: Fix a typo 2021-03-25 11:38:51 -06:00
refcount-vs-atomic.rst refcount: provide ops for cases when object's memory can be reused 2025-03-16 22:06:19 -07:00
swiotlb.rst docs/core-api: swiotlb: fix typos 2024-10-17 09:37:05 -06:00
symbol-namespaces.rst doc: module: DEFAULT_SYMBOL_NAMESPACE must be defined before #includes 2025-01-09 12:36:55 -07:00
this_cpu_ops.rst arch: Remove cmpxchg_double 2023-06-05 09:36:39 +02:00
timekeeping.rst timekeeping: Introduce fast accessor to clock tai 2022-04-14 16:19:30 +02:00
tracepoint.rst doc: Sphinxify the tracepoint docbook 2016-11-29 14:44:23 -07:00
unaligned-memory-access.rst move asm/unaligned.h to linux/unaligned.h 2024-10-02 17:23:23 -04:00
union_find.rst Documentation: Fix the compilation errors in union_find.rst 2024-08-02 08:58:16 -10:00
watch_queue.rst Documentation: move watch_queue to core-api 2022-04-22 09:47:25 -06:00
workqueue.rst workqueue: Adjust WQ_MAX_ACTIVE from 512 to 2048 2024-10-08 08:46:54 -10:00
xarray.rst XArray: minor documentation improvements 2025-01-12 20:21:08 -08:00