From nobody Tue Feb 10 00:57:50 2026 Received: from mail-yw1-f182.google.com (mail-yw1-f182.google.com [209.85.128.182]) (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 A136635CB85 for ; Thu, 18 Dec 2025 15:57:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766073481; cv=none; b=SG1J+3jUwOX8EGw9zJ5WMWR88eJZ0ZrAhXrq6TJ4c8lD8jl4wSLxAdXcloi49IiiHUb+Flhk63JthCPW8p44B8XqssUHSrRbc9fF8LOHyNFvGjyIesQiM7q5WU29kqbCmBnFvp1eLBGWgonvq6y5DoD2t9To7ToEU5JRBI7KAX4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1766073481; c=relaxed/simple; bh=5C+RcXkK3A1ZSReLK1qZRhNMinh6jju+ITuqispS68k=; h=From:To:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=d8663iigkI+cDOo1Cb80pBwaioeZDu7SyLzdRK+KU7O9Bnf72qS7TkHWmnN+Hxl+pa2Z/IkPKc7OO3zuXfYgVuaPrVGsuwxJ5sAcRx46TVFiS+CAfjn8qYdti1ddUo3GzfKyc6xqttuQifa13ZHoqOerr+2lf5SeFDMw5+WAJRM= 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=NYaWSNDB; arc=none smtp.client-ip=209.85.128.182 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="NYaWSNDB" Received: by mail-yw1-f182.google.com with SMTP id 00721157ae682-78c4aa7af99so8050557b3.0 for ; Thu, 18 Dec 2025 07:57:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=soleen.com; s=google; t=1766073478; x=1766678278; 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=kbo/Q10fOjWM8sV0DuXlsI6QStMFfk28dpPwdp8oFO4=; b=NYaWSNDB/GqgzVl4W6cHP62JmAtBBzz+6u97qalxSCQoP7P6TEdi+7QU32H0mm+Rhl S25jXETCTi9ddtTPFNX5H6cVzTME2FVqoeMy2G/zet6DpUX8kudYQz4aJQrRCxGF0Btd +TpMVQi3bLSqtIKP51cE+vLAJt6dqW3QtqHIQCfkCQpHf5dAj4KdKPINEm4DuaX3dlzf vLlMHwjfhj7UbXxzP+wYhrx8cceKRDkbGoC0ZPC1GPyghlJ1z6Yd+n+YH5cfp1G49/4n dq6JqI9IHWU95/RYqMo2B9PEs30dQoy2lAOjZmbvOhYuN5dlrO68YSL6kpiH7ob6jJFA i1ig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1766073478; x=1766678278; 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=kbo/Q10fOjWM8sV0DuXlsI6QStMFfk28dpPwdp8oFO4=; b=wZcwdYfuZXeJ3oUI7MKxTYWIamEzc7H4vxshFcKxUA9AVGrT65sxk1+Qu6/UGL6Xmw CUJ0Yt7Vq8Rm20iPD3kVbUXDp0hVRzXfpxgVaZV0rcTmDYdVzJGE+pFzwtEQ4clulq4B HzF7/0u5MQd+Cfo7OE/+06xzle6Jb9cWdFEnC+A7hGruMoUaH4Kp6lHglHB4MGL6c0a6 h9meCocFkF/wFU310v0vfahB7FzjM30fytY4b7/CrQ8jIf2r8FwxCiL9qq/mjmyaSRs1 FRjfdQwui1pSrswsf+fUVlfyP84lUZiDJkk8Wwh8onRKcQiSfZAjl5+BRVOexyNZ/wSD xzAw== X-Forwarded-Encrypted: i=1; AJvYcCWNZGurI4vprQygAoeL1ap6qAMAtzB6ZSPqorDe17/hpqIgJ2cBcbXVbXNj7Cywe1bDscyIq2l/BHvDvwE=@vger.kernel.org X-Gm-Message-State: AOJu0Yw9W3aC8p0SnnrH+m7wYuavSWAsFu3OC4UVbTgi13KVq22B9BOu 7Gq//zTr6niofogAtG9FDuFk3nl/W27/9E9KOdTYoQHvzCDwxXFpveO495c4K0mLa08= X-Gm-Gg: AY/fxX49Fx1Yn/diBQJow6M0HInMgGOeZgWU5K6mUwi5QgCUCOkyNny+64TBj/yINEw B0UMqmfntVQ2xM6Oj+V16gSo7+naBGFGtoJZrfbuj/BkcCeWi0G4PFrjnsTb0CJCOQgivh4S/f2 QYNb+z6NV4EsBaDV++R+vfe9A6IdvrEU0F2M0Lw+mqLi2dUQ4wNND3ZKQn2xVpcm38lY3pDA5X8 fjiRsT41pi6kvYnd6QBm112wuxGWhsIn/hQ8L2fnmF+MubudgO0flSwxXsICYJiMQ/S3ww8MTxk OZmVY7wMtmcr9sLLYV46ko5WZ7IfMx7/bDIVhxKA8mKIlqVGZxY9bvSl5iDoxA7jV/Hrsrp7H2i +yd6r5/6UlDkSxnnG1MloBvFveCxAe0K54l4z3wQDrZS7kLs9Wj1gr20Pa+4Nr5vsc+DyQtxpj4 npAQl36vINqIPBhxh+Sjw2twDVBaiHvrOfXdU6hx4COESqRRiNzTt/6/kSnfVdeIPDGAZZ/ogtH +NNqicBGykBHxmn3xGPD98n5sEfdkE7Z2N37w== X-Google-Smtp-Source: AGHT+IHF15CHFSvn2iw7JiSe1zOiuiDDwSN7HW3uphvKiqLN0UcGgr621SGo4sNapWA5IhaiEHGrRw== X-Received: by 2002:a05:690c:488a:b0:78a:6fd9:ef49 with SMTP id 00721157ae682-78e66951cb2mr177183317b3.14.1766073478421; Thu, 18 Dec 2025 07:57:58 -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 00721157ae682-78fa6f52bb2sm9348467b3.16.2025.12.18.07.57.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Dec 2025 07:57:57 -0800 (PST) From: Pasha Tatashin To: pratyush@kernel.org, pasha.tatashin@soleen.com, rppt@kernel.org, dmatlack@google.com, skhawaja@google.com, rientjes@google.com, corbet@lwn.net, akpm@linux-foundation.org, kees@kernel.org, davidgow@google.com, pmladek@suse.com, linux-kernel@vger.kernel.org, linux-mm@kvack.org, nicolas.frattaroli@collabora.com, linux-doc@vger.kernel.org, tamird@gmail.com, raemoar63@gmail.com, graf@amazon.com Subject: [PATCH v2 1/5] list: add primitives for private list manipulations Date: Thu, 18 Dec 2025 10:57:48 -0500 Message-ID: <20251218155752.3045808-2-pasha.tatashin@soleen.com> X-Mailer: git-send-email 2.52.0.313.g674ac2bdf7-goog In-Reply-To: <20251218155752.3045808-1-pasha.tatashin@soleen.com> References: <20251218155752.3045808-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.313.g674ac2bdf7-goog