From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from out-177.mta1.migadu.com (out-177.mta1.migadu.com [95.215.58.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C5DBF33D6F7 for ; Thu, 11 Jun 2026 04:43:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.177 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781152998; cv=none; b=Op/MnrlVKt7MwuCfOXnDlISxlGFvpj74p7X3mv574O1iI6eoCRp/9d54LmH17wl9IhTgJ+ZlqFTt78e45wnGNdZLHTm0S/912VGtx4fnv5PVMSJfBLJyK1uHxMthcFt/+d0MYdd+/LX6pQLAH0zC5rq4zZ3V+qi+hDaMMnkZB+M= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1781152998; c=relaxed/simple; bh=V05i8sWLPIV7+ekrRfpT+axkw+kf4lhxNWhkbffL4mQ=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=ec5ssulNaNt4ox92m3Y1qFImPIvga92YxGh5r6nynqajZ7e92jt7Xc3i7IbrKWalH6Asqk3riHv7ILoQoXY87MvyDkYXZn0geyPdU0txhfu7NxiqrJF5OOD7U0dhZeoJpZViYCa78X2XurotfeksgihcuE9qeEGIKFr2v7hhIb4= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev; spf=pass smtp.mailfrom=linux.dev; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b=Hp8pOFHp; arc=none smtp.client-ip=95.215.58.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.dev Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.dev Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux.dev header.i=@linux.dev header.b="Hp8pOFHp" Message-ID: <9b98e860-11df-44bf-9a95-3046d2c274a6@linux.dev> DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1781152991; h=from:from: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:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=amFobG45FitZxSTZMk37sKmrzp6+HTwygF2QRCMVESA=; b=Hp8pOFHpWz66c6aS666mzKdGRUOg5trj2OOXjIC2FT49beQLeiNdwbdvku6y74Ze+FUPE+ E8RFdhLaOrZjL9dY7cSSbpn242HXv3fuPOtrI0a7ePuPhOCMW89fa+R0t1DoJD4yyOztEo oTw51U8wnDSUmm+mYfNoclmpLJbmbns= Date: Thu, 11 Jun 2026 12:42:02 +0800 Precedence: bulk X-Mailing-List: linux-tegra@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Subject: Re: [PATCH v2 00/14] list: Prepare entry iterators to cache cursor state To: Andy Shevchenko , =?UTF-8?Q?Christian_K=C3=B6nig?= Cc: Thierry Reding , Jonathan Hunter , Sowjanya Komatineni , Davidlohr Bueso , "Paul E . McKenney" , Josh Triplett , Peter Zijlstra , Ingo Molnar , Will Deacon , Boqun Feng , Liam Girdwood , Jani Nikula , Joonas Lahtinen , Rodrigo Vivi , Tvrtko Ursulin , Huang Rui , Eddie James , Mark Brown , Maxime Coquelin , Alexandre Torgue , Laxman Dewangan , Neil Armstrong , Robert Foss , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Matthew Auld , Matthew Brost , Waiman Long , drbd-dev@lists.linbit.com, linux-block@vger.kernel.org, linux1394-devel@lists.sourceforge.net, dri-devel@lists.freedesktop.org, intel-gfx@lists.freedesktop.org, linux-spi@vger.kernel.org, linux-stm32@st-md-mailman.stormreply.com, linux-arm-kernel@lists.infradead.org, linux-tegra@vger.kernel.org, linux-sound@vger.kernel.org, linux-kernel@vger.kernel.org, Andrew Morton , Randy Dunlap , Christian Brauner , David Howells , Luca Ceresoli , Kaito Cheng , Muchun Song , Philipp Reisner , Lars Ellenberg , =?UTF-8?Q?Christoph_B=C3=B6hmwalder?= , Jens Axboe , Takashi Sakamoto , Andrzej Hajda , Jaroslav Kysela , Takashi Iwai References: <20260609061347.93688-1-kaitao.cheng@linux.dev> <5152089a-2808-4fe9-b633-b03018105dd2@linux.dev> X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. From: Kaitao Cheng In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT 在 2026/6/10 22:43, Andy Shevchenko 写道: > On Wed, Jun 10, 2026 at 02:14:06PM +0800, Kaitao Cheng wrote: >> 在 2026/6/9 18:33, Christian König 写道: >>> On 6/9/26 08:13, Kaitao Cheng wrote: >>>> >>>> This series prepares for, and then updates, the list_for_each_entry() >>>> family so the common entry iterators cache their next or previous cursor >>>> before the loop body runs. >>> >>> Why in the world would we want to do that? >>> >>> The safe and non-safe variants have very distinct use cases and that is completely intentional. >>> >>> What we could improve maybe is the documentation, from my experience an astonishing large amount of people have misconceptions about the safe variants. >>> >>>> The first 13 patches open-code loops that intentionally depend on the >>>> old "derive the next entry from the current cursor at the end of the >>>> iteration" behaviour. These loops append work to the list being walked, >>>> restart traversal after dropping a lock, skip an entry consumed by the >>>> current iteration, or otherwise adjust the cursor in the loop body. >>> >>> Well I have to clearly reject the changes for subsystems/components I'm maintaining, that just looks horrible to me and I clearly don't see a good reason for that. >> >> Hi Christian and Andy Shevchenko, >> >> Thanks for taking a look. I would like to clarify the point you raised. >> >> The reason I started looking at this is the original motivation behind >> the _safe() variants. They exist because some users need to remove, move >> or otherwise consume the current entry while walking the list. In that >> case the next cursor has to be preserved before the loop body can modify >> the current entry. >> >> The unfortunate part is that this could not be expressed with the >> existing list_for_each_entry() interface without changing its calling >> convention. The _safe() variants had to grow an extra argument for the >> temporary cursor, and that is why we ended up with a separate family of >> macros. >> >> But conceptually, the distinction does not have to be exposed as two >> different iterator families forever. The difference is an implementation >> detail: whether the iterator keeps the next/previous cursor before the >> body runs. This series makes the common list_for_each_entry() iterators >> do that internally, so the safe and non-safe forms can effectively be >> folded together, or at least the need for a separate public _safe() >> interface becomes much weaker. >> >> There is also a usability issue with the current _safe() interface. The >> caller is forced to define a temporary cursor outside the macro and pass >> it in, even though almost all users never use that cursor directly. It is >> just boilerplate required by the macro implementation. I find that >> redundant and awkward: the temporary cursor is an internal detail of the >> iteration, but every caller has to spell it out. > > Ah, I think the distinct macro families is that what we want. > But the hiding of the parameter can be done inside list_for_each_*_safe(). > You can do a treewide change with coccinelle. > > Sorry if I didn't get the whole idea from your previous contributions. > > Note, even cases that would need a temporary cursor may be switched to > new list_for_each_*_safe(), see how PCI macros for iterating over resources > are implemented (include/linux/pci.h). Thanks for your suggestions. I've written a demo based on your feedback. Could you please review it and share your thoughts on this approach? diff --git a/include/linux/list.h b/include/linux/list.h index 9df84a56a789..306554ab1841 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -7,6 +7,7 @@ #include #include #include +#include #include @@ -911,20 +912,34 @@ static inline size_t list_count_nodes(struct list_head *head) for (; !list_entry_is_head(pos, head, member); \ pos = list_prev_entry(pos, member)) +#define __list_for_each_entry_safe_internal(pos, next, head, member) \ + for (typeof(pos) next = list_next_entry(pos = \ + list_first_entry(head, typeof(*pos), member), member); \ + !list_entry_is_head(pos, head, member); \ + pos = next, next = list_next_entry(next, member)) + +#define __list_for_each_entry_safe2(pos, head, member) \ + __list_for_each_entry_safe_internal(pos, __UNIQUE_ID(next), head, member) + +#define __list_for_each_entry_safe3(pos, next, head, member) \ + for (pos = list_first_entry(head, typeof(*pos), member), \ + next = list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos = next, next = list_next_entry(next, member)) + /** * list_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. + * @...: either (head, member) or (next, head, member) + * @next: another type * to use as optional temporary storage. The temporary + * cursor is internal unless explicitly supplied by the caller. + * @head: the head for your list. + * @member:the name of the list_head within the struct. * */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member), \ - n = list_next_entry(pos, member); \ - !list_entry_is_head(pos, head, member); \ - pos = n, n = list_next_entry(n, member)) +#define list_for_each_entry_safe(pos, ...) \ + CONCATENATE(__list_for_each_entry_safe, COUNT_ARGS(__VA_ARGS__))\ + (pos, __VA_ARGS__) /** * list_for_each_entry_safe_continue - continue list iteration safe against removal >> With the updated list_for_each_entry() implementation, that extra cursor >> can be kept inside the iterator itself. Callers that only want to walk >> the list, including callers that delete or consume the current entry, no >> longer need to carry an otherwise-unused temporary variable just to make >> the macro work. >> >>>> The final patch changes include/linux/list.h to keep a private cursor in >>>> the common entry iterators while preserving the public macro interface. >>>> The safe variants remain available when callers need the temporary >>>> cursor explicitly or have stronger mutation requirements. > > -- Thanks Kaitao Cheng