From nobody Mon Jun 8 12:11:55 2026 Received: from out-183.mta1.migadu.com (out-183.mta1.migadu.com [95.215.58.183]) (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 56D1A33F5B0 for ; Fri, 29 May 2026 08:23:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=95.215.58.183 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780042984; cv=none; b=PfVex+KUlBwk2GYXZTmjSe5ThPJUOo3fywahXu53/BxSyFVkHWcIV+TF9skgEkD7+Fou8mXjY+BiVS4TY14nqVGi1ajAAmtV0fv9FSDdFTLIxDKVE+nS3eEm3FETpGnhlBsUnc2BZTJYvnigNw1A3nnc60PhkCmFci+oQXq7fK0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780042984; c=relaxed/simple; bh=c3oVVD6kZvlrKQRQvI7PdW/g+oWg8omgZYlotFsXuOk=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=gnqDMs4Cr2bqIgP6v1EH+qMoXftcOb3YbUrzEiBBxJJVRlS5VnntWFTYYd8bpM9qxzhj/7cGK2/HoZarcWJNWUqbu2D2SiG/VVSDeQylFniRu7rciEBw2hEt0sokpjqCZcMZVLf/cqmttCveKzWpfLsfepTPdci9DQgqFg8vr44= 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=NcPohvVm; arc=none smtp.client-ip=95.215.58.183 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="NcPohvVm" X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1780042970; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=H8yeksQo1mEg5JLCpBGlOlGyi2qg/6Wyyghbci5eAvc=; b=NcPohvVmzk2HHJgvfc8glbnO6ktN4D6mVn38+H5vyN2PwuVzEvBsnRs6mEQtRNM7PcLozE 37yxPaXALzSgEn9R3ht1K0cpKG5dh4K6HaYp/EWbmzzcPMgG79qnfbj8UXzaXhaz7pE2AQ HpAjKxT7/Ts7zLYLon3Yf8T7oVuATOU= From: Kaitao Cheng To: nsc@kernel.org, nathan@kernel.org Cc: paulmck@kernel.org, andriy.shevchenko@linux.intel.com, akpm@linux-foundation.org, dhowells@redhat.com, rdunlap@infradead.org, luca.ceresoli@bootlin.com, chengkaitao@kylinos.cn, acme@redhat.com, irogers@google.com, peterz@infradead.org, namhyung@kernel.org, swapnil.sapkal@amd.com, linux-kernel@vger.kernel.org, muchun.song@linux.dev, linux-kbuild@vger.kernel.org Subject: [PATCH] list: Add safe entry iterators without an explicit n cursor Date: Fri, 29 May 2026 16:21:49 +0800 Message-ID: <20260529082149.76764-1-kaitao.cheng@linux.dev> 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 X-Migadu-Flow: FLOW_OUT Content-Type: text/plain; charset="utf-8" From: Kaitao Cheng The list_for_each_entry_safe*() helpers are useful for loops which may remove the current entry, but they require callers to provide a second cursor named by convention as n. Some users do not need to inspect or reset that cursor; they only need the iterator to keep the next entry available while the current entry may be removed. Add entry iterators which hide that temporary next cursor while otherwise following the traversal pattern of the corresponding list_for_each_entry_safe*() helpers. Do not fold this behavior into list_for_each_entry(). That iterator advances from pos after the loop body, and a few existing callers rely on that semantics to observe list changes made during the body. For example, stress_reorder_work() in kernel/locking/test-ww_mutex.c moves the current entry to the list head with list_move(&ll->link, &locks) and documents that this restarts iteration. If list_for_each_entry() cached the next entry before running the body, the loop would continue from the stale saved next entry instead of honoring the modified list order. Signed-off-by: Kaitao Cheng --- include/linux/list.h | 60 ++++++++++++++++++++++++++++++++++++++ scripts/include/list.h | 13 +++++++++ tools/include/linux/list.h | 60 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index 09d979976b3b..d3597da3e952 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -908,6 +908,19 @@ static inline size_t list_count_nodes(struct list_head= *head) !list_entry_is_head(pos, head, member); \ pos =3D n, n =3D list_next_entry(n, member)) =20 +/** + * list_for_each_entry_mutable - iterate over list of given type safe agai= nst + * removal of list entry + * @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_for_each_entry_mutable(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos =3D \ + list_first_entry(head, typeof(*pos), member), member); \ + !list_entry_is_head(pos, head, member); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_safe_continue - continue list iteration safe agains= t removal * @pos: the type * to use as a loop cursor. @@ -924,6 +937,22 @@ static inline size_t list_count_nodes(struct list_head= *head) !list_entry_is_head(pos, head, member); \ pos =3D n, n =3D list_next_entry(n, member)) =20 +/** + * list_for_each_entry_mutable_continue - continue list iteration safe aga= inst + * removal of list entry + * @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 after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_mutable_continue(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos =3D \ + list_next_entry(pos, member), member); \ + !list_entry_is_head(pos, head, member); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_safe_from - iterate over list from current point sa= fe against removal * @pos: the type * to use as a loop cursor. @@ -939,6 +968,21 @@ static inline size_t list_count_nodes(struct list_head= *head) !list_entry_is_head(pos, head, member); \ pos =3D n, n =3D list_next_entry(n, member)) =20 +/** + * list_for_each_entry_mutable_from - iterate over list from current point= safe + * against removal + * @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 from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_mutable_from(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos, member); \ + !list_entry_is_head(pos, head, member); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_safe_reverse - iterate backwards over list safe aga= inst removal * @pos: the type * to use as a loop cursor. @@ -955,6 +999,22 @@ static inline size_t list_count_nodes(struct list_head= *head) !list_entry_is_head(pos, head, member); \ pos =3D n, n =3D list_prev_entry(n, member)) =20 +/** + * list_for_each_entry_mutable_reverse - iterate backwards over list safe = against + * removal + * @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, safe against removal + * of list entry. + */ +#define list_for_each_entry_mutable_reverse(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_prev_entry(pos =3D \ + list_last_entry(head, typeof(*pos), member), member); \ + !list_entry_is_head(pos, head, member); \ + pos =3D __temp__, __temp__ =3D list_prev_entry(__temp__, member)) + /** * list_safe_reset_next - reset a stale list_for_each_entry_safe loop * @pos: the loop cursor used in the list_for_each_entry_safe loop diff --git a/scripts/include/list.h b/scripts/include/list.h index 8bdcaadca709..ab84e3f70793 100644 --- a/scripts/include/list.h +++ b/scripts/include/list.h @@ -286,6 +286,19 @@ static inline int list_empty(const struct list_head *h= ead) !list_entry_is_head(pos, head, member); \ pos =3D list_next_entry(pos, member)) =20 +/** + * list_for_each_entry_mutable - iterate over list of given type safe agai= nst + * removal of list entry + * @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_for_each_entry_mutable(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos =3D \ + list_first_entry(head, typeof(*pos), member), member); \ + !list_entry_is_head(pos, head, member); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_reverse - iterate backwards over list of given type. * @pos: the type * to use as a loop cursor. diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h index a692ff7aed5c..8aa394832aba 100644 --- a/tools/include/linux/list.h +++ b/tools/include/linux/list.h @@ -544,6 +544,19 @@ static inline void list_splice_tail_init(struct list_h= ead *list, &pos->member !=3D (head); \ pos =3D n, n =3D list_next_entry(n, member)) =20 +/** + * list_for_each_entry_mutable - iterate over list of given type safe agai= nst + * removal of list entry + * @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_for_each_entry_mutable(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos =3D \ + list_first_entry(head, typeof(*pos), member), member); \ + &pos->member !=3D (head); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_safe_continue - continue list iteration safe agains= t removal * @pos: the type * to use as a loop cursor. @@ -560,6 +573,22 @@ static inline void list_splice_tail_init(struct list_h= ead *list, &pos->member !=3D (head); \ pos =3D n, n =3D list_next_entry(n, member)) =20 +/** + * list_for_each_entry_mutable_continue - continue list iteration safe aga= inst + * removal of list entry + * @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 after current point, + * safe against removal of list entry. + */ +#define list_for_each_entry_mutable_continue(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos =3D \ + list_next_entry(pos, member), member); \ + &pos->member !=3D (head); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_safe_from - iterate over list from current point sa= fe against removal * @pos: the type * to use as a loop cursor. @@ -575,6 +604,21 @@ static inline void list_splice_tail_init(struct list_h= ead *list, &pos->member !=3D (head); \ pos =3D n, n =3D list_next_entry(n, member)) =20 +/** + * list_for_each_entry_mutable_from - iterate over list from current point= safe + * against removal + * @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 from current point, safe against + * removal of list entry. + */ +#define list_for_each_entry_mutable_from(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_next_entry(pos, member); \ + &pos->member !=3D (head); \ + pos =3D __temp__, __temp__ =3D list_next_entry(__temp__, member)) + /** * list_for_each_entry_safe_reverse - iterate backwards over list safe aga= inst removal * @pos: the type * to use as a loop cursor. @@ -591,6 +635,22 @@ static inline void list_splice_tail_init(struct list_h= ead *list, &pos->member !=3D (head); \ pos =3D n, n =3D list_prev_entry(n, member)) =20 +/** + * list_for_each_entry_mutable_reverse - iterate backwards over list safe + * against removal + * @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, safe against removal + * of list entry. + */ +#define list_for_each_entry_mutable_reverse(pos, head, member) \ + for (typeof(pos) __temp__ =3D list_prev_entry(pos =3D \ + list_last_entry(head, typeof(*pos), member), member); \ + &pos->member !=3D (head); \ + pos =3D __temp__, __temp__ =3D list_prev_entry(__temp__, member)) + /** * list_safe_reset_next - reset a stale list_for_each_entry_safe loop * @pos: the loop cursor used in the list_for_each_entry_safe loop --=20 2.50.1 (Apple Git-155)