From patchwork Thu Feb 6 02:52:01 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Suren Baghdasaryan X-Patchwork-Id: 13962144 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 325C3C02192 for ; Thu, 6 Feb 2025 02:52:08 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 53B8A6B007B; Wed, 5 Feb 2025 21:52:08 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 4C5276B0082; Wed, 5 Feb 2025 21:52:08 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 33E5D6B0083; Wed, 5 Feb 2025 21:52:08 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 0C09E6B007B for ; Wed, 5 Feb 2025 21:52:08 -0500 (EST) Received: from smtpin02.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id A3604C0E19 for ; Thu, 6 Feb 2025 02:52:07 +0000 (UTC) X-FDA: 83087995494.02.58BA068 Received: from mail-oa1-f74.google.com (mail-oa1-f74.google.com [209.85.160.74]) by imf15.hostedemail.com (Postfix) with ESMTP id CFC11A000C for ; Thu, 6 Feb 2025 02:52:05 +0000 (UTC) Authentication-Results: imf15.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=3VgWYqfI; spf=pass (imf15.hostedemail.com: domain of 31COkZwYKCO8jliVeSXffXcV.TfdcZelo-ddbmRTb.fiX@flex--surenb.bounces.google.com designates 209.85.160.74 as permitted sender) smtp.mailfrom=31COkZwYKCO8jliVeSXffXcV.TfdcZelo-ddbmRTb.fiX@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1738810325; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=uxxD+jAbhCcwO8C2DOIhXDyhe0riU6WFytq8OKh1XJE=; b=m/wDof+YMAGqASNT0zLm8Ib9Uqd0mDW3gWibSrFeZUJRQ9pFIZvZ956sKQauTtGQjy1aDv WvecC9p4JmhpsbC1TqDyU1HxCAdKvAbeK5uZPMsUTk/25WbbaLq2HkXpbGQ7JuNlXsMCiW t5HnXjB9f7+h/JT8VzKhfIW1ppWemSA= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1738810325; a=rsa-sha256; cv=none; b=xgV6gzF5x5F2O0LHNS1vh1D1f/TkLOdh0UqOsYtAmx/CElS0E6pnhDhh3Z4myyrg3wwYLH lIaLVyl0M/jiompS0akIiVqMN7Rg+ze5oqnxGoLZnizAiAjyfIQo5V/Lnv4GW5BBJA6f3B 4u6Tx8Uy1GKXpjP1pGJKP1xL7SD59JQ= ARC-Authentication-Results: i=1; imf15.hostedemail.com; dkim=pass header.d=google.com header.s=20230601 header.b=3VgWYqfI; spf=pass (imf15.hostedemail.com: domain of 31COkZwYKCO8jliVeSXffXcV.TfdcZelo-ddbmRTb.fiX@flex--surenb.bounces.google.com designates 209.85.160.74 as permitted sender) smtp.mailfrom=31COkZwYKCO8jliVeSXffXcV.TfdcZelo-ddbmRTb.fiX@flex--surenb.bounces.google.com; dmarc=pass (policy=reject) header.from=google.com Received: by mail-oa1-f74.google.com with SMTP id 586e51a60fabf-2b7c8cb27a2so324439fac.1 for ; Wed, 05 Feb 2025 18:52:05 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1738810325; x=1739415125; darn=kvack.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=uxxD+jAbhCcwO8C2DOIhXDyhe0riU6WFytq8OKh1XJE=; b=3VgWYqfI9XM0ndKzgA/WTyeaV996HihkSCw54+0u828tVuc7zYJkqi15hJ4M/uIEcL pNVpGFX0N8X7IDgWA0VSrnwBZWs6CTcEWm+34ETLoUu5AKmGTK76nF58KKYbTO2EioSS TrasYDKZGHJaAfZWMXgQnmSIIEuG6fV0RJTrukAWUUIqevvsvB1uUzm6V5E+mOSMFIF8 XDRpkIDfqJfLFVIQl95J+xF3eczWUkPbvg20/JhCqONp1ak6YVDx8T5Y5a67w4L87Db3 JJIadTOzLwScTF0BDJHwsdCCzTUq8i6So9apLezWm/X/W7nGaqsbNdOTq9l+GU8K/r1x /6+g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1738810325; x=1739415125; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=uxxD+jAbhCcwO8C2DOIhXDyhe0riU6WFytq8OKh1XJE=; b=QGyl6mGMfib+8dIEKgYF9VFz9bGcMutmswYzUMbtrjKC/VhdidmSuEt7qcES6yhXWV DEMDg92/l0J5v4JKnSKMb7TZEKmQx6FXkr8qm6hGCZutLi2Nh3QTrpb7PJBjinifoekP 4un0KNZ1gNHvcEU/oCduftgpBIoeMnHaSbM1JoSvPw9Krcev5q149gJHUy7Hb+qcYzQB Hcrd+CrNImGYfogm9DEwyBoQBBAk4pvqSJADgD91O1UPMWWjbQIIpx+Do6YMJhOkTx6M zZWxeIYvE4xutafYy9s9J/FSarikI7+i0BnjdtSXtvKbpTXzIjveGgR5cksEiVQYD854 rwIw== X-Forwarded-Encrypted: i=1; AJvYcCVbrjqU2uqgVLMm3ZuJpDewQjSXETO9cysamhhPvlMHelgQp2TXsgc+JoZrpqXiBBKcbicqn/GlyA==@kvack.org X-Gm-Message-State: AOJu0YytfdjmRmIH6KBXQ3XM1uQhVnffF9SUW0idHzvYjCMd8P5R/r6G 4D/IJ+35ge5CqybOs+LL5Gcvgg6KLKTuH+WYvAFI7/mu0mnqtTKl/vko6fm5/tiHLnvPyyWssg8 QIA== X-Google-Smtp-Source: AGHT+IH74Eck9OiEYfeZK3i/QiqSO/2Qq5MwDok2zuhwZZWt4EKmJxq6VEGkOuv1YlKKA8IvnfM/F+puuh4= X-Received: from oabso7.prod.google.com ([2002:a05:6871:8187:b0:2b3:580c:19f4]) (user=surenb job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6871:c3c3:b0:29e:3921:b1ea with SMTP id 586e51a60fabf-2b80514453emr4246981fac.30.1738810324733; Wed, 05 Feb 2025 18:52:04 -0800 (PST) Date: Wed, 5 Feb 2025 18:52:01 -0800 In-Reply-To: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.48.1.362.g079036d154-goog Message-ID: <20250206025201.979573-1-surenb@google.com> Subject: [PATCH 1/1] refcount: provide ops for cases when object's memory can be reused From: Suren Baghdasaryan To: peterz@infradead.org Cc: will@kernel.org, paulmck@kernel.org, boqun.feng@gmail.com, mark.rutland@arm.com, mjguzik@gmail.com, akpm@linux-foundation.org, willy@infradead.org, liam.howlett@oracle.com, lorenzo.stoakes@oracle.com, david.laight.linux@gmail.com, mhocko@suse.com, vbabka@suse.cz, hannes@cmpxchg.org, oliver.sang@intel.com, mgorman@techsingularity.net, david@redhat.com, peterx@redhat.com, oleg@redhat.com, dave@stgolabs.net, brauner@kernel.org, dhowells@redhat.com, hdanton@sina.com, hughd@google.com, lokeshgidra@google.com, minchan@google.com, jannh@google.com, shakeel.butt@linux.dev, souravpanda@google.com, pasha.tatashin@soleen.com, klarasmodin@gmail.com, richard.weiyang@gmail.com, corbet@lwn.net, linux-doc@vger.kernel.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org, kernel-team@android.com, Suren Baghdasaryan X-Rspamd-Queue-Id: CFC11A000C X-Stat-Signature: ww3ds1srbdgpjkbbfjdq6gtstsj1zdjz X-Rspam-User: X-Rspamd-Server: rspam12 X-HE-Tag: 1738810325-726443 X-HE-Meta: U2FsdGVkX1+Z9BWr5LidGBGU/abHdFFxXrLRXGykBs1nwALZwO6VhPs1AdjOqrnp9vNRZgEOgeLnx+UHLHPH9UVA/UlKLhX/2cP4769H2ZR/ov31/EQ3thaCXN1CPlDgPNXl5c5xi1NSQBzXhTCljlAafDhsbCu1PmBCAwuGXFHh4myXUlAU8gfyGz2NMGU0RWpL3UWoca6yFanlYQEY3IMpPcUZCS8TneA1O2t+hgB2Q9lESX7BR6I7f9SAudlpZkTQB+BYzrg4m7MaQE+6S3+Z/g0RMzrmcerO3J3IsKXPpTPA75ouXkxPEdM8oUXTq6okACwUUAG09mttxaSIDHBAeEcogjRMa0O/TTqK1j4bqAkpVNsRDhtJbPFQ/Qd87jx7nP48r8JS4h/NN4HWEydFinmkl2jhazY0+IR3Xbw/JgvcTRhWA5qkV5ka0HRMifeTvWH98SnTDiCdrJrKKCs8yoxioM//n6sCHDDNoizG7Sctq8G9Mq4C5z2f2pGHSaL2ta7QdDrj56jLyr8Ypclq9srzkUD4MvjNW+2kJws6cVH1i7SFztHuVTJl98qFL+dQ7HlaW6wFxQ7SZQjykKzLuNINBSiE1jngdtyKREfF4uDquJvrQvnr7Z9syB3MJ9jXNd4/uNR9gGwoM7PRyEM4fztZOyyD7i1fvKcL1bM5Orpyo5JRM/waSOrBpBUqOuKTA8JnC6e1heiNALv33eatCQLY9U3gusRV7jUhviVkAtKSlJrUYGtrHBcy0PTPvpMwZ2mhxe65pk0Lc2K20ls33yBC3op/m5fNqyGkqv4YOpXnyPZfRYJuEKCcBcXatxn648MCVsKewVGt/v5qIYSdeECiO+OVyh6G70vdF/Tg04blS6wBuy9iMaVOh9I8EgIzA6E5ww2Fh5u4cH2b7n88SvO2mmTFN1TA5At7vUaDcgF9EhoQuPVfhN3ujAItstF67Ndc6tY3w5QpozJ mLEkKlu0 Zwq+2SfKKpU+tXqn8UO482vkytY8ji92/c6C5c1Vp6GjvHQZbg8+yWqXFZ7wFKKaDk5aWL+62G+WLeeC5Ui0BwaUQuvMCbN7Wwfl3iUYTtgz8GLfrjxfwcsppjcmWAHvX7M+aHhn/98WjQReqev/veLjLp1fdE+utlUBE4CjdC3Fz5EWWmXbeYfh7j1EQPSdFxTKUCK+DDQW++Hi6DiGZFcEpzU1nVwsZCdpiQVNOY5MLZ73ZfXOXhI9+h4VUlDXy7u555TEZvtqW4pMvdwAOVXjCe1skMZ32770DLpXCf6GSaDYFVnmfYRE2wrEpaXl84Zy6as3TzWeMKKgMnbUs+nND0guWcWRFifwe1rJ50aaElNybInZ6FE30sHJjcIn3LmzoqK8EtenmddhdNeQfuhKW2+w2UyZGJQh0UQLrZ9Gg8LcI4ijoTbSydsWxwnkGMVrbia0ultXGT77PCeSkkVyW5uYae9wA/4M9DTrRS58/p2/I5jc2cPgN3rZDlDsT26b37Trl1X7YBXl7/4siyifEhNt86Z4nNhhaFoRENeR6HB0EjNxVbrc4XRrodiTxoj2hI1scKrmP4L+Rt44E4AtCrYje/yGSQzf8LnTFoK/I+CBBaC1kurLuxqQmlGiTNqhXk81KHB9HRN7jGPzZPYDMZjzyxpUQgHA5EvoMMWv5uJnowY7FcmMsSfulkcLwdtU9hD22e5RZCO97zx2jZAe1kNGw8KCr92be X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: 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); Signed-off-by: Suren Baghdasaryan Cc: Peter Zijlstra Cc: Will Deacon Cc: Paul E. McKenney Acked-by: Vlastimil Babka #slab --- Documentation/RCU/whatisRCU.rst | 10 ++ Documentation/core-api/refcount-vs-atomic.rst | 37 +++++- include/linux/refcount.h | 106 ++++++++++++++++++ include/linux/slab.h | 9 ++ 4 files changed, 156 insertions(+), 6 deletions(-) base-commit: 92514ef226f511f2ca1fb1b8752966097518edc0 diff --git a/Documentation/RCU/whatisRCU.rst b/Documentation/RCU/whatisRCU.rst index 1ef5784c1b84..53faeed7c190 100644 --- a/Documentation/RCU/whatisRCU.rst +++ b/Documentation/RCU/whatisRCU.rst @@ -971,6 +971,16 @@ unfortunately any spinlock in a ``SLAB_TYPESAFE_BY_RCU`` object must be initialized after each and every call to kmem_cache_alloc(), which renders reference-free spinlock acquisition completely unsafe. Therefore, when using ``SLAB_TYPESAFE_BY_RCU``, make proper use of a reference counter. +If using refcount_t, the specialized refcount_{add|inc}_not_zero_acquire() +and refcount_set_release() APIs should be used to ensure correct operation +ordering when verifying object identity and when initializing newly +allocated objects. Acquire fence in refcount_{add|inc}_not_zero_acquire() +ensures that identity checks happen *after* reference count is taken. +refcount_set_release() should be called after a newly allocated object is +fully initialized and release fence ensures that new values are visible +*before* refcount can be successfully taken by other users. Once +refcount_set_release() is called, the object should be considered visible +by other tasks. (Those willing to initialize their locks in a kmem_cache constructor may also use locking, including cache-friendly sequence locking.) diff --git a/Documentation/core-api/refcount-vs-atomic.rst b/Documentation/core-api/refcount-vs-atomic.rst index 79a009ce11df..9551a7bbfd38 100644 --- a/Documentation/core-api/refcount-vs-atomic.rst +++ b/Documentation/core-api/refcount-vs-atomic.rst @@ -86,7 +86,19 @@ Memory ordering guarantee changes: * none (both fully unordered) -case 2) - increment-based ops that return no value +case 2) - non-"Read/Modify/Write" (RMW) ops with release ordering +------------------------------------------- + +Function changes: + + * atomic_set_release() --> refcount_set_release() + +Memory ordering guarantee changes: + + * none (both provide RELEASE ordering) + + +case 3) - increment-based ops that return no value -------------------------------------------------- Function changes: @@ -98,7 +110,7 @@ Memory ordering guarantee changes: * none (both fully unordered) -case 3) - decrement-based RMW ops that return no value +case 4) - decrement-based RMW ops that return no value ------------------------------------------------------ Function changes: @@ -110,7 +122,7 @@ Memory ordering guarantee changes: * fully unordered --> RELEASE ordering -case 4) - increment-based RMW ops that return a value +case 5) - increment-based RMW ops that return a value ----------------------------------------------------- Function changes: @@ -126,7 +138,20 @@ Memory ordering guarantees changes: result of obtaining pointer to the object! -case 5) - generic dec/sub decrement-based RMW ops that return a value +case 6) - increment-based RMW ops with acquire ordering that return a value +----------------------------------------------------- + +Function changes: + + * atomic_inc_not_zero() --> refcount_inc_not_zero_acquire() + * no atomic counterpart --> refcount_add_not_zero_acquire() + +Memory ordering guarantees changes: + + * fully ordered --> ACQUIRE ordering on success + + +case 7) - generic dec/sub decrement-based RMW ops that return a value --------------------------------------------------------------------- Function changes: @@ -139,7 +164,7 @@ Memory ordering guarantees changes: * fully ordered --> RELEASE ordering + ACQUIRE ordering on success -case 6) other decrement-based RMW ops that return a value +case 8) other decrement-based RMW ops that return a value --------------------------------------------------------- Function changes: @@ -154,7 +179,7 @@ Memory ordering guarantees changes: .. note:: atomic_add_unless() only provides full order on success. -case 7) - lock-based RMW +case 9) - lock-based RMW ------------------------ Function changes: diff --git a/include/linux/refcount.h b/include/linux/refcount.h index 35f039ecb272..4589d2e7bfea 100644 --- a/include/linux/refcount.h +++ b/include/linux/refcount.h @@ -87,6 +87,15 @@ * The decrements dec_and_test() and sub_and_test() also provide acquire * ordering on success. * + * refcount_{add|inc}_not_zero_acquire() and refcount_set_release() provide + * acquire and release ordering for cases when the memory occupied by the + * object might be reused to store another object. This is important for the + * cases where secondary validation is required to detect such reuse, e.g. + * SLAB_TYPESAFE_BY_RCU. The secondary validation checks have to happen after + * the refcount is taken, hence acquire order is necessary. Similarly, when the + * object is initialized, all stores to its attributes should be visible before + * the refcount is set, otherwise a stale attribute value might be used by + * another task which succeeds in taking a refcount to the new object. */ #ifndef _LINUX_REFCOUNT_H @@ -125,6 +134,31 @@ static inline void refcount_set(refcount_t *r, int n) atomic_set(&r->refs, n); } +/** + * refcount_set_release - set a refcount's value with release ordering + * @r: the refcount + * @n: value to which the refcount will be set + * + * This function should be used when memory occupied by the object might be + * reused to store another object -- consider SLAB_TYPESAFE_BY_RCU. + * + * Provides release memory ordering which will order previous memory operations + * against this store. This ensures all updates to this object are visible + * once the refcount is set and stale values from the object previously + * occupying this memory are overwritten with new ones. + * + * This function should be called only after new object is fully initialized. + * After this call 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 to the new object and start using it. + */ +static inline void refcount_set_release(refcount_t *r, int n) +{ + atomic_set_release(&r->refs, n); +} + /** * refcount_read - get a refcount's value * @r: the refcount @@ -178,6 +212,52 @@ static inline __must_check bool refcount_add_not_zero(int i, refcount_t *r) return __refcount_add_not_zero(i, r, NULL); } +static inline __must_check __signed_wrap +bool __refcount_add_not_zero_acquire(int i, refcount_t *r, int *oldp) +{ + int old = refcount_read(r); + + do { + if (!old) + break; + } while (!atomic_try_cmpxchg_acquire(&r->refs, &old, old + i)); + + if (oldp) + *oldp = old; + + if (unlikely(old < 0 || old + i < 0)) + refcount_warn_saturate(r, REFCOUNT_ADD_NOT_ZERO_OVF); + + return old; +} + +/** + * refcount_add_not_zero_acquire - add a value to a refcount with acquire ordering unless it is 0 + * + * @i: the value to add to the refcount + * @r: the refcount + * + * Will saturate at REFCOUNT_SATURATED and WARN. + * + * This function should be used when memory occupied by the object might be + * reused to store another object -- consider SLAB_TYPESAFE_BY_RCU. + * + * Provides acquire memory ordering on success, it is assumed the caller has + * guaranteed the object memory to be stable (RCU, etc.). It does provide a + * control dependency and thereby orders future stores. See the comment on top. + * + * Use of this function is not recommended for the normal reference counting + * use case in which references are taken and released one at a time. In these + * cases, refcount_inc_not_zero_acquire() should instead be used to increment a + * reference count. + * + * Return: false if the passed refcount is 0, true otherwise + */ +static inline __must_check bool refcount_add_not_zero_acquire(int i, refcount_t *r) +{ + return __refcount_add_not_zero_acquire(i, r, NULL); +} + static inline __signed_wrap void __refcount_add(int i, refcount_t *r, int *oldp) { @@ -236,6 +316,32 @@ static inline __must_check bool refcount_inc_not_zero(refcount_t *r) return __refcount_inc_not_zero(r, NULL); } +static inline __must_check bool __refcount_inc_not_zero_acquire(refcount_t *r, int *oldp) +{ + return __refcount_add_not_zero_acquire(1, r, oldp); +} + +/** + * refcount_inc_not_zero_acquire - increment a refcount with acquire ordering unless it is 0 + * @r: the refcount to increment + * + * Similar to refcount_inc_not_zero(), but provides acquire memory ordering on + * success. + * + * This function should be used when memory occupied by the object might be + * reused to store another object -- consider SLAB_TYPESAFE_BY_RCU. + * + * Provides acquire memory ordering on success, it is assumed the caller has + * guaranteed the object memory to be stable (RCU, etc.). It does provide a + * control dependency and thereby orders future stores. See the comment on top. + * + * Return: true if the increment was successful, false otherwise + */ +static inline __must_check bool refcount_inc_not_zero_acquire(refcount_t *r) +{ + return __refcount_inc_not_zero_acquire(r, NULL); +} + static inline void __refcount_inc(refcount_t *r, int *oldp) { __refcount_add(1, r, oldp); diff --git a/include/linux/slab.h b/include/linux/slab.h index 09eedaecf120..ad902a2d692b 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -136,6 +136,15 @@ enum _slab_flag_bits { * rcu_read_lock before reading the address, then rcu_read_unlock after * taking the spinlock within the structure expected at that address. * + * Note that object identity check has to be done *after* acquiring a + * reference, therefore user has to ensure proper ordering for loads. + * Similarly, when initializing objects allocated with SLAB_TYPESAFE_BY_RCU, + * the newly allocated object has to be fully initialized *before* its + * refcount gets initialized and proper ordering for stores is required. + * refcount_{add|inc}_not_zero_acquire() and refcount_set_release() are + * designed with the proper fences required for reference counting objects + * allocated with SLAB_TYPESAFE_BY_RCU. + * * Note that it is not possible to acquire a lock within a structure * allocated with SLAB_TYPESAFE_BY_RCU without first acquiring a reference * as described above. The reason is that SLAB_TYPESAFE_BY_RCU pages