From nobody Mon Dec 1 23:36:40 2025 Received: from mail-yx1-f52.google.com (mail-yx1-f52.google.com [74.125.224.52]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0402D312836 for ; Wed, 26 Nov 2025 18:57:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=74.125.224.52 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764183453; cv=none; b=VbEZhMNECdo69KvX1ugALV6KAYxhsDuT4EMZpgfPddb68qLnyRS1QV2AVFlp4DqBiIaHADrFbVfwuKA8qwYLCPtZvfNpEZfSaGe4Cvp/pDZJXrKDB/LeI4FFG8RL4rmXRULeyCj073EfBGPOrKMw+6yYV4sjgIsyCY5lZsnUf6c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764183453; c=relaxed/simple; bh=44wvrjsJsA56OuYSPS9rS3D1Jv0o0ZdFIoHQwFGkRDc=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=VO5txcdblg1PRv4qC+lJOvAw1ih/zK5XkxNfzIVuMuqr9rpiiQVIDvPc8QPaVy70GxtF8Sh5wXoqYTtYbJgBzvY/qypBujhValFX0UDhkhIQhElGGp+3KvNhWNKoqvtC9a/8xUXxtDcuR2akrOBMtq9z5X6K4FO11lukWsqId/A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com; spf=pass smtp.mailfrom=soleen.com; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b=hlcQvjOl; arc=none smtp.client-ip=74.125.224.52 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=soleen.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=soleen.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=soleen.com header.i=@soleen.com header.b="hlcQvjOl" Received: by mail-yx1-f52.google.com with SMTP id 956f58d0204a3-6420c0cf4abso98691d50.1 for ; Wed, 26 Nov 2025 10:57:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1764183451; x=1764788251; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:from:to:cc:subject:date:message-id :reply-to; bh=252XjyR+0lgh5x/2v3DurnNqDLZdTdfYV2jUwplovA0=; b=hlcQvjOlT/nt6c3sIr0osj95aOONwCwkDR2AQGaI/Q+Dmn58eA387QpfdzPhXPGCOB vESovq0hqFkRQSHx3N9TFtRKVoCPhg8LW4W3ee6ftCSR5DuTTf6wP7YJnLYcD5C1C5B2 sci2wf+8W0demdIhB9JqEcn9z4iig9tHyDknHg8GPlziaD8xjdhnkcHM+U4EhcqypR4O aLzX6JSSUOJxCkYKoJAhVDlqq4EAhNdLSoPatbr6lcTg7Pgp6Saf9FsNx3rrqoZCyXqk WJvD4XYo6oIJQc5smg7Hu8MJPLmXoUo9HNIye2exQsJNaO5NoYFGSqWI2APMdJDsXuKn rQkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1764183451; x=1764788251; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=252XjyR+0lgh5x/2v3DurnNqDLZdTdfYV2jUwplovA0=; b=P2Wy64NbY22F0IuSvXCUjJlJ7TA14xJy5hyGubIrH1yTEF3Ay9soyb0xP2ACP4y20x 2XP0Q8/Oi3oUlBc5ib8pBFNO3CaGufg4VOhTstnswCP3KnRq43Vf8od0o0kKo3KWKUHW kM0uG0iGNYucgCIfFmoYY2bcmzr5ELthiH1DJCQh1ps/LkPHuBOTzWO4BmNr5IvFHZt0 1c/bQ8n8cMl0V6wV/VuRp20rZ3vv3trAe7Og4zZBhWSUALSTx2Sc0J2pAV3Kz/W79ovd HaMjtzmIOsyEwMZsXa6h0AZUY95EEui/OKf7+oym29OyyfypI+YYI+5YkEnWOAD83Pfw hRiw== X-Forwarded-Encrypted: i=1; AJvYcCWbGSBz7WdVNkEqsfd+HYet/SV50t0iK35jv1W3WWgI9oPqBWFhR7QV881M7hsMoPhF5zCXVuQlqBuzpDU=@vger.kernel.org X-Gm-Message-State: AOJu0YzZbQo8+n2/QoIWVFVwwYt9PVR8rCsUBCofRoC70x65i2GcUAu4 v7PZ4MeVdgSk0UuuxaUf+lLn1jCP7iUUdS+Ot8+rGAn8FQpXWtqQNlmuJMYBQihvH+U= X-Gm-Gg: ASbGncsq15LxzzuwXZXAZGUD+F3tqvRAXfr1o6SqEuRFmuWQUMBdkq5dSw7X6Qn3PUp hjB+lzcjPQYzPYI/BuN/yrkHCD2CqMYqc9VIe36O7fB2kijwNsgguAqpLU2yJB6/TyEIc0iiWzS UsWptK6PDlEotANE1HLBDTm2DpAG/QZ2HY2J0IdOJJsO1SKHe8Zl5hX7DKfiMEVMoV+ZbvE7zkz 2TdyEaWTnEuFbfDh3ShPaGlXoSoH02cnlnF77MZZIFAU/371D/q4xr+cNQDpT1T5jqL17pstkas a5TukeWmauo3nr1SGJHDyKez7DTTt3RdxEjdXhbpuXjjXpeFNJRGq8TeMsqPAupwZ96V3XFKVJJ C8m9jPtg99mg9GkQsiJlkZb2DOTy0H4SInkzcdheo5Cvj6GsZ328iPSmrXLpQsh8gUlgDIqCiKi Xi6eR1GCfcDuTsunc5h/cKzJfelgzFOGNDKGr34oOBVhZlhJdwV1Pb/fMZ6X6LFmTstsfpzz5IH Dea/TnQF9sMkJArNw== X-Google-Smtp-Source: AGHT+IHu24upDOl7ro9ofRNY1haZ/Bs6YtgAgi3REfJFG6MqRROVjAAPoCaKTsxQrfJqTFs30v63Ng== X-Received: by 2002:a05:690e:784:b0:63f:b590:2e9 with SMTP id 956f58d0204a3-64302aa4865mr11760784d50.21.1764183450703; Wed, 26 Nov 2025 10:57:30 -0800 (PST) Received: from soleen.c.googlers.com.com (182.221.85.34.bc.googleusercontent.com. [34.85.221.182]) by smtp.gmail.com with ESMTPSA id 956f58d0204a3-643259fd696sm2960753d50.7.2025.11.26.10.57.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 26 Nov 2025 10:57:30 -0800 (PST) From: Pasha Tatashin To: corbet@lwn.net, pasha.tatashin@soleen.com, nicolas.frattaroli@collabora.com, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, akpm@linux-foundation.org, kees@kernel.org, davidgow@google.com, pmladek@suse.com, tamird@gmail.com, raemoar63@gmail.com, ebiggers@kernel.org, diego.daniel.professional@gmail.com, rppt@kernel.org, pratyush@kernel.org, jasonmiu@google.com, graf@amazon.com, dmatlack@google.com, rientjes@google.com Subject: [PATCH v1 1/3] list: add primitives for private list manipulations Date: Wed, 26 Nov 2025 13:57:23 -0500 Message-ID: <20251126185725.4164769-2-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.52.0.487.g5c8c507ade-goog In-Reply-To: <20251126185725.4164769-1-pasha.tatashin@soleen.com> References: <20251126185725.4164769-1-pasha.tatashin@soleen.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Linux recently added an ability to add private members to structs (i.e. __private) and access them via ACCESS_PRIVATE(). This ensures that those members are only accessible by the subsystem which owns the struct type, and not to the object owner. However, struct list_head often needs to be placed into the private section to be manipulated privately by the subsystem. Add macros to support private list manipulations in . Signed-off-by: Pasha Tatashin --- Documentation/core-api/list.rst | 9 ++ include/linux/list_private.h | 256 ++++++++++++++++++++++++++++++++ 2 files changed, 265 insertions(+) create mode 100644 include/linux/list_private.h diff --git a/Documentation/core-api/list.rst b/Documentation/core-api/list.= rst index 86873ce9adbf..241464ca0549 100644 --- a/Documentation/core-api/list.rst +++ b/Documentation/core-api/list.rst @@ -774,3 +774,12 @@ Full List API =20 .. kernel-doc:: include/linux/list.h :internal: + +Private List API +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +.. kernel-doc:: include/linux/list_private.h + :doc: Private List Primitives + +.. kernel-doc:: include/linux/list_private.h + :internal: diff --git a/include/linux/list_private.h b/include/linux/list_private.h new file mode 100644 index 000000000000..6f93d54e797a --- /dev/null +++ b/include/linux/list_private.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* + * Copyright (c) 2025, Google LLC. + * Pasha Tatashin + */ +#ifndef _LINUX_LIST_PRIVATE_H +#define _LINUX_LIST_PRIVATE_H + +/** + * DOC: Private List Primitives + * + * Provides a set of list primitives identical in function to those in + * ````, but designed for cases where the embedded + * ``&struct list_head`` is private member. + */ + +#include +#include + +#define __list_private_offset(type, member) \ + ((size_t)(&ACCESS_PRIVATE(((type *)0), member))) + +/** + * list_private_entry - get the struct for this entry + * @ptr: the &struct list_head pointer. + * @type: the type of the struct this is embedded in. + * @member: the identifier passed to ACCESS_PRIVATE. + */ +#define list_private_entry(ptr, type, member) ({ \ + const struct list_head *__mptr =3D (ptr); \ + (type *)((char *)__mptr - __list_private_offset(type, member)); \ +}) + +/** + * list_private_first_entry - get the first element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the identifier passed to ACCESS_PRIVATE. + */ +#define list_private_first_entry(ptr, type, member) \ + list_private_entry((ptr)->next, type, member) + +/** + * list_private_last_entry - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the identifier passed to ACCESS_PRIVATE. + */ +#define list_private_last_entry(ptr, type, member) \ + list_private_entry((ptr)->prev, type, member) + +/** + * list_private_next_entry - get the next element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_private_next_entry(pos, member) \ + list_private_entry(ACCESS_PRIVATE(pos, member).next, typeof(*(pos)), memb= er) + +/** + * list_private_next_entry_circular - get the next element in list + * @pos: the type * to cursor. + * @head: the list head to take the element from. + * @member: the name of the list_head within the struct. + * + * Wraparound if pos is the last element (return the first element). + * Note, that list is expected to be not empty. + */ +#define list_private_next_entry_circular(pos, head, member) \ + (list_is_last(&ACCESS_PRIVATE(pos, member), head) ? \ + list_private_first_entry(head, typeof(*(pos)), member) : \ + list_private_next_entry(pos, member)) + +/** + * list_private_prev_entry - get the prev element in list + * @pos: the type * to cursor + * @member: the name of the list_head within the struct. + */ +#define list_private_prev_entry(pos, member) \ + list_private_entry(ACCESS_PRIVATE(pos, member).prev, typeof(*(pos)), memb= er) + +/** + * list_prev_entry_circular - get the prev element in list + * @pos: the type * to cursor. + * @head: the list head to take the element from. + * @member: the name of the list_head within the struct. + * + * Wraparound if pos is the first element (return the last element). + * Note, that list is expected to be not empty. + */ +#define list_private_prev_entry_circular(pos, head, member) \ + (list_is_first(&ACCESS_PRIVATE(pos, member), head) ? \ + list_private_last_entry(head, typeof(*(pos)), member) : \ + list_private_prev_entry(pos, member)) + +/** + * list_private_entry_is_head - test if the entry points to the head of th= e list + * @pos: the type * to cursor + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_private_entry_is_head(pos, head, member) \ + list_is_head(&ACCESS_PRIVATE(pos, member), (head)) + +/** + * list_private_for_each_entry - iterate over list of given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_private_for_each_entry(pos, head, member) \ + for (pos =3D list_private_first_entry(head, typeof(*pos), member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D list_private_next_entry(pos, member)) + +/** + * list_private_for_each_entry_reverse - iterate backwards over list of gi= ven type. + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_private_for_each_entry_reverse(pos, head, member) \ + for (pos =3D list_private_last_entry(head, typeof(*pos), member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D list_private_prev_entry(pos, member)) + +/** + * list_private_for_each_entry_continue - continue iteration over list of = given type + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Continue to iterate over list of given type, continuing after + * the current position. + */ +#define list_private_for_each_entry_continue(pos, head, member) \ + for (pos =3D list_private_next_entry(pos, member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D list_private_next_entry(pos, member)) + +/** + * list_private_for_each_entry_continue_reverse - iterate backwards from t= he given point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Start to iterate over list of given type backwards, continuing after + * the current position. + */ +#define list_private_for_each_entry_continue_reverse(pos, head, member) \ + for (pos =3D list_private_prev_entry(pos, member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D list_private_prev_entry(pos, member)) + +/** + * list_private_for_each_entry_from - iterate over list of given type from= the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing from current position. + */ +#define list_private_for_each_entry_from(pos, head, member) \ + for (; !list_private_entry_is_head(pos, head, member); \ + pos =3D list_private_next_entry(pos, member)) + +/** + * list_private_for_each_entry_from_reverse - iterate backwards over list = of given type + * from the current point + * @pos: the type * to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, continuing from current posi= tion. + */ +#define list_private_for_each_entry_from_reverse(pos, head, member) \ + for (; !list_private_entry_is_head(pos, head, member); \ + pos =3D list_private_prev_entry(pos, member)) + +/** + * list_private_for_each_entry_safe - iterate over list of given type safe= against removal of list entry + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + */ +#define list_private_for_each_entry_safe(pos, n, head, member) \ + for (pos =3D list_private_first_entry(head, typeof(*pos), member), \ + n =3D list_private_next_entry(pos, member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D n, n =3D list_private_next_entry(n, member)) + +/** + * list_private_for_each_entry_safe_continue - continue list iteration saf= e against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type, continuing after current point, + * safe against removal of list entry. + */ +#define list_private_for_each_entry_safe_continue(pos, n, head, member) \ + for (pos =3D list_private_next_entry(pos, member), \ + n =3D list_private_next_entry(pos, member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D n, n =3D list_private_next_entry(n, member)) + +/** + * list_private_for_each_entry_safe_from - iterate over list from current = point safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate over list of given type from current point, safe against + * removal of list entry. + */ +#define list_private_for_each_entry_safe_from(pos, n, head, member) \ + for (n =3D list_private_next_entry(pos, member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D n, n =3D list_private_next_entry(n, member)) + +/** + * list_private_for_each_entry_safe_reverse - iterate backwards over list = safe against removal + * @pos: the type * to use as a loop cursor. + * @n: another type * to use as temporary storage + * @head: the head for your list. + * @member: the name of the list_head within the struct. + * + * Iterate backwards over list of given type, safe against removal + * of list entry. + */ +#define list_private_for_each_entry_safe_reverse(pos, n, head, member) \ + for (pos =3D list_private_last_entry(head, typeof(*pos), member), \ + n =3D list_private_prev_entry(pos, member); \ + !list_private_entry_is_head(pos, head, member); \ + pos =3D n, n =3D list_private_prev_entry(n, member)) + +/** + * list_private_safe_reset_next - reset a stale list_for_each_entry_safe l= oop + * @pos: the loop cursor used in the list_for_each_entry_safe loop + * @n: temporary storage used in list_for_each_entry_safe + * @member: the name of the list_head within the struct. + * + * list_safe_reset_next is not safe to use in general if the list may be + * modified concurrently (eg. the lock is dropped in the loop body). An + * exception to this is if the cursor element (pos) is pinned in the list, + * and list_safe_reset_next is called after re-taking the lock and before + * completing the current iteration of the loop body. + */ +#define list_private_safe_reset_next(pos, n, member) \ + n =3D list_private_next_entry(pos, member) + +#endif /* _LINUX_LIST_PRIVATE_H */ --=20 2.52.0.487.g5c8c507ade-goog