Generic Linux architectural discussions
 help / color / mirror / Atom feed
* Re: [PATCH] coredump/fcntl: Add FD_CLOBCOR flag to close fd before dumping core
From: Eric W. Biederman @ 2026-06-18  5:29 UTC (permalink / raw)
  To: Xin Zhao
  Cc: viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd,
	keescook, mcgrof, j.granados, allen.lkml, linux-fsdevel,
	linux-kernel, linux-arch
In-Reply-To: <20260618030700.2511668-1-jackzxcui1989@163.com>

Xin Zhao <jackzxcui1989@163.com> writes:

> A coredump typically takes some time to complete. If we happen to hold a
> write lock with flock just before triggering the coredump, that write lock
> will not be released during the entire coredump process. As a result,
> other processes attempting to acquire the same write lock may experience
> significant delays.

You are talking about giant processes writing to slow backing store?

I suspect you would be better off quickly writing the coredump to a pipe,
and then writing it to disk.

Unless your machine is badly balanced that should take perhaps a second.

That said I don't see why you need elaborate machinery to do something
about these file descriptors.  Unless I am mistaken no file descriptors
are placed into a coredump.  In which case it should be possible to just
call exit_files early.

> To address this, we introduce the F_[GET|SET]FD_EX fcntl operation and the
> FD_CLOBCOR flag, allowing coredump_wait() to release any file descriptors
> marked with FD_CLOBCOR. We can also assign the FD_CLOBCOR flag to specific
> shared memory segments, preventing the coredump from including shared
> memory that we are not interested in, thereby reducing both the coredump
> duration and the size of the core file.

Please look at vma_dump_size.  There are plenty of ways already to
skip dumping a memory area.  Using file backed shared memory,
and madvise(MADV_DONTDUMP) are two easy ones that already exist.

My point is that there are cleaner ways to solve your problem than
the solutions you have proposed.

Eric

^ permalink raw reply

* Re: [PATCH] coredump/fcntl: Add FD_CLOBCOR flag to close fd before dumping core
From: Xin Zhao @ 2026-06-18  4:58 UTC (permalink / raw)
  To: viro
  Cc: alex.aring, allen.lkml, arnd, brauner, chuck.lever, ebiederm,
	j.granados, jack, jackzxcui1989, jlayton, keescook, linux-arch,
	linux-fsdevel, linux-kernel, mcgrof
In-Reply-To: <20260618043054.GY2636677@ZenIV>

On Thu, 18 Jun 2026 05:30:54 +0100 Al Viro <viro@zeniv.linux.org.uk> wrote:

> No.  Leaving aside the unasked-for overhead for every process on every system,
> whether they are interested in this "feature" or not, this
> 
> > +static struct fdtable *close_files_before_core(struct files_struct *files)
> > +{
> > +	/*
> > +	 * It is safe to dereference the fd table without RCU or
> > +	 * ->file_lock because this is the last reference to the
> > +	 * files structure.
> > +	 */
> > +	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
> > +	unsigned int i, j = 0;
> > +
> > +	for (;;) {
> > +		unsigned long set;
> > +
> > +		i = j * BITS_PER_LONG;
> > +		if (i >= fdt->max_fds)
> > +			break;
> > +		set = fdt->open_fds[j++];
> > +		while (set) {
> > +			if (set & 1 && close_before_core(i, files)) {
> > +				struct file *file = fdt->fd[i];
> > +
> > +				if (file) {
> > +					filp_close(file, files);
> > +					cond_resched();
> > +				}
> > +			}
> > +			i++;
> > +			set >>= 1;
> > +		}
> > +	}
> 
> is just plain wrong.  You are leaving references in that descriptor table,
> whether you've closed them or not.  It *can't* be right - no matter what
> you do after having called that, you will either leak file references
> for ones that were not closed or eat double-free for ones that were.
> 
> Have you actually tested that patch?

Thank you for your response. I developed and tested this feature in 6.1.158,
but I made this serious mistake when porting it to linux-next. I should have
retained the xchg operation that was still present in 6.1.158 to retrieve
fdt->fd[i].


> Note that above is _not_ "fix that thing and I'll have no objections";
> I think the benefits of that API are nowhere near worth inflicting the
> cost on everyone.

I see.
The overhead introduced by this patch comes from the additional memory
allocation for the bitmap during process initialization, as well as the
extra traversal time during coredump_wait(). I need to think of ways to
achieve this with minimal cost, and then you can take another look at it.

Thanks
Xin Zhao


^ permalink raw reply

* Re: [PATCH] coredump/fcntl: Add FD_CLOBCOR flag to close fd before dumping core
From: Al Viro @ 2026-06-18  4:30 UTC (permalink / raw)
  To: Xin Zhao
  Cc: brauner, jack, jlayton, chuck.lever, alex.aring, arnd, ebiederm,
	keescook, mcgrof, j.granados, allen.lkml, linux-fsdevel,
	linux-kernel, linux-arch
In-Reply-To: <20260618030700.2511668-1-jackzxcui1989@163.com>

On Thu, Jun 18, 2026 at 11:07:00AM +0800, Xin Zhao wrote:
> A coredump typically takes some time to complete. If we happen to hold a
> write lock with flock just before triggering the coredump, that write lock
> will not be released during the entire coredump process. As a result,
> other processes attempting to acquire the same write lock may experience
> significant delays.
> 
> To address this, we introduce the F_[GET|SET]FD_EX fcntl operation and the
> FD_CLOBCOR flag, allowing coredump_wait() to release any file descriptors
> marked with FD_CLOBCOR. We can also assign the FD_CLOBCOR flag to specific
> shared memory segments, preventing the coredump from including shared
> memory that we are not interested in, thereby reducing both the coredump
> duration and the size of the core file.
> 
> We actually considered using signals that generate coredumps to perform
> the actions we wanted in user space. However, since other threads within
> the process are not frozen when handling these signals, indiscriminately
> closing an fd can lead to concurrency issues. For example, if the thread
> that triggered the coredump closes the fd in the signal handler while
> other threads are using the resources associated with that fd, it could
> cause secondary corruption of the coredump state.
> 
> Signed-off-by: Xin Zhao <jackzxcui1989@163.com>

No.  Leaving aside the unasked-for overhead for every process on every system,
whether they are interested in this "feature" or not, this

> +static struct fdtable *close_files_before_core(struct files_struct *files)
> +{
> +	/*
> +	 * It is safe to dereference the fd table without RCU or
> +	 * ->file_lock because this is the last reference to the
> +	 * files structure.
> +	 */
> +	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
> +	unsigned int i, j = 0;
> +
> +	for (;;) {
> +		unsigned long set;
> +
> +		i = j * BITS_PER_LONG;
> +		if (i >= fdt->max_fds)
> +			break;
> +		set = fdt->open_fds[j++];
> +		while (set) {
> +			if (set & 1 && close_before_core(i, files)) {
> +				struct file *file = fdt->fd[i];
> +
> +				if (file) {
> +					filp_close(file, files);
> +					cond_resched();
> +				}
> +			}
> +			i++;
> +			set >>= 1;
> +		}
> +	}

is just plain wrong.  You are leaving references in that descriptor table,
whether you've closed them or not.  It *can't* be right - no matter what
you do after having called that, you will either leak file references
for ones that were not closed or eat double-free for ones that were.

Have you actually tested that patch?

Note that above is _not_ "fix that thing and I'll have no objections";
I think the benefits of that API are nowhere near worth inflicting the
cost on everyone.

^ permalink raw reply

* [PATCH] coredump/fcntl: Add FD_CLOBCOR flag to close fd before dumping core
From: Xin Zhao @ 2026-06-18  3:07 UTC (permalink / raw)
  To: viro, brauner, jack, jlayton, chuck.lever, alex.aring, arnd,
	ebiederm, keescook, mcgrof, j.granados, allen.lkml
  Cc: linux-fsdevel, linux-kernel, linux-arch, Xin Zhao

A coredump typically takes some time to complete. If we happen to hold a
write lock with flock just before triggering the coredump, that write lock
will not be released during the entire coredump process. As a result,
other processes attempting to acquire the same write lock may experience
significant delays.

To address this, we introduce the F_[GET|SET]FD_EX fcntl operation and the
FD_CLOBCOR flag, allowing coredump_wait() to release any file descriptors
marked with FD_CLOBCOR. We can also assign the FD_CLOBCOR flag to specific
shared memory segments, preventing the coredump from including shared
memory that we are not interested in, thereby reducing both the coredump
duration and the size of the core file.

We actually considered using signals that generate coredumps to perform
the actions we wanted in user space. However, since other threads within
the process are not frozen when handling these signals, indiscriminately
closing an fd can lead to concurrency issues. For example, if the thread
that triggered the coredump closes the fd in the signal handler while
other threads are using the resources associated with that fd, it could
cause secondary corruption of the coredump state.

Signed-off-by: Xin Zhao <jackzxcui1989@163.com>
---
 fs/coredump.c                    |  2 +
 fs/fcntl.c                       |  7 +++
 fs/file.c                        | 91 ++++++++++++++++++++++++++++++--
 include/linux/fdtable.h          |  7 +++
 include/linux/file.h             |  2 +
 include/linux/sched/task.h       |  1 +
 include/uapi/asm-generic/fcntl.h | 11 ++++
 7 files changed, 118 insertions(+), 3 deletions(-)

diff --git a/fs/coredump.c b/fs/coredump.c
index bb6fdb1f4..d927fe93d 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -548,6 +548,8 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
 		}
 	}
 
+	exit_files_before_core(tsk);
+
 	return core_waiters;
 }
 
diff --git a/fs/fcntl.c b/fs/fcntl.c
index beab8080b..14b774250 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -470,6 +470,13 @@ static long do_fcntl(int fd, unsigned int cmd, unsigned long arg,
 		err = 0;
 		set_close_on_exec(fd, argi & FD_CLOEXEC);
 		break;
+	case F_GETFD_EX:
+		err = get_close_before_core(fd) ? FD_CLOBCOR : 0;
+		break;
+	case F_SETFD_EX:
+		err = 0;
+		set_close_before_core(fd, argi & FD_CLOBCOR);
+		break;
 	case F_GETFL:
 		err = filp->f_flags;
 		break;
diff --git a/fs/file.c b/fs/file.c
index 2c81c0b16..1c64dfdca 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -130,6 +130,8 @@ static inline void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt,
 			copy_words * BITS_PER_LONG, nwords * BITS_PER_LONG);
 	bitmap_copy_and_extend(nfdt->close_on_exec, ofdt->close_on_exec,
 			copy_words * BITS_PER_LONG, nwords * BITS_PER_LONG);
+	bitmap_copy_and_extend(nfdt->close_before_core, ofdt->close_before_core,
+			copy_words * BITS_PER_LONG, nwords * BITS_PER_LONG);
 	bitmap_copy_and_extend(nfdt->full_fds_bits, ofdt->full_fds_bits,
 			copy_words, nwords);
 }
@@ -222,7 +224,7 @@ static struct fdtable *alloc_fdtable(unsigned int slots_wanted)
 	fdt->fd = data;
 
 	data = kvmalloc(max_t(size_t,
-				 2 * nr / BITS_PER_BYTE + BITBIT_SIZE(nr), L1_CACHE_BYTES),
+				 3 * nr / BITS_PER_BYTE + BITBIT_SIZE(nr), L1_CACHE_BYTES),
 				 GFP_KERNEL_ACCOUNT);
 	if (!data)
 		goto out_arr;
@@ -230,6 +232,8 @@ static struct fdtable *alloc_fdtable(unsigned int slots_wanted)
 	data += nr / BITS_PER_BYTE;
 	fdt->close_on_exec = data;
 	data += nr / BITS_PER_BYTE;
+	fdt->close_before_core = data;
+	data += nr / BITS_PER_BYTE;
 	fdt->full_fds_bits = data;
 
 	return fdt;
@@ -330,10 +334,22 @@ static inline void __set_close_on_exec(unsigned int fd, struct fdtable *fdt,
 	}
 }
 
+static inline void __set_close_before_core(unsigned int fd, struct fdtable *fdt,
+				       bool set)
+{
+	if (set) {
+		__set_bit(fd, fdt->close_before_core);
+	} else {
+		if (test_bit(fd, fdt->close_before_core))
+			__clear_bit(fd, fdt->close_before_core);
+	}
+}
+
 static inline void __set_open_fd(unsigned int fd, struct fdtable *fdt, bool set)
 {
 	__set_bit(fd, fdt->open_fds);
 	__set_close_on_exec(fd, fdt, set);
+	__set_close_before_core(fd, fdt, false);
 	fd /= BITS_PER_LONG;
 	if (!~fdt->open_fds[fd])
 		__set_bit(fd, fdt->full_fds_bits);
@@ -400,6 +416,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho
 	new_fdt = &newf->fdtab;
 	new_fdt->max_fds = NR_OPEN_DEFAULT;
 	new_fdt->close_on_exec = newf->close_on_exec_init;
+	new_fdt->close_before_core = newf->close_before_core_init;
 	new_fdt->open_fds = newf->open_fds_init;
 	new_fdt->full_fds_bits = newf->full_fds_bits_init;
 	new_fdt->fd = &newf->fd_array[0];
@@ -471,7 +488,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, struct fd_range *punch_ho
 	return newf;
 }
 
-static struct fdtable *close_files(struct files_struct * files)
+static struct fdtable *close_files(struct files_struct *files)
 {
 	/*
 	 * It is safe to dereference the fd table without RCU or
@@ -483,6 +500,7 @@ static struct fdtable *close_files(struct files_struct * files)
 
 	for (;;) {
 		unsigned long set;
+
 		i = j * BITS_PER_LONG;
 		if (i >= fdt->max_fds)
 			break;
@@ -490,6 +508,7 @@ static struct fdtable *close_files(struct files_struct * files)
 		while (set) {
 			if (set & 1) {
 				struct file *file = fdt->fd[i];
+
 				if (file) {
 					filp_close(file, files);
 					cond_resched();
@@ -503,6 +522,41 @@ static struct fdtable *close_files(struct files_struct * files)
 	return fdt;
 }
 
+static struct fdtable *close_files_before_core(struct files_struct *files)
+{
+	/*
+	 * It is safe to dereference the fd table without RCU or
+	 * ->file_lock because this is the last reference to the
+	 * files structure.
+	 */
+	struct fdtable *fdt = rcu_dereference_raw(files->fdt);
+	unsigned int i, j = 0;
+
+	for (;;) {
+		unsigned long set;
+
+		i = j * BITS_PER_LONG;
+		if (i >= fdt->max_fds)
+			break;
+		set = fdt->open_fds[j++];
+		while (set) {
+			if (set & 1 && close_before_core(i, files)) {
+				struct file *file = fdt->fd[i];
+
+				if (file) {
+					filp_close(file, files);
+					cond_resched();
+				}
+			}
+			i++;
+			set >>= 1;
+		}
+	}
+
+	return fdt;
+}
+
+
 void put_files_struct(struct files_struct *files)
 {
 	if (atomic_dec_and_test(&files->count)) {
@@ -517,7 +571,7 @@ void put_files_struct(struct files_struct *files)
 
 void exit_files(struct task_struct *tsk)
 {
-	struct files_struct * files = tsk->files;
+	struct files_struct *files = tsk->files;
 
 	if (files) {
 		task_lock(tsk);
@@ -527,6 +581,15 @@ void exit_files(struct task_struct *tsk)
 	}
 }
 
+void exit_files_before_core(struct task_struct *tsk)
+{
+	struct files_struct *files = tsk->files;
+
+	if (files) {
+		close_files_before_core(files);
+	}
+}
+
 struct files_struct init_files = {
 	.count		= ATOMIC_INIT(1),
 	.fdt		= &init_files.fdtab,
@@ -534,6 +597,7 @@ struct files_struct init_files = {
 		.max_fds	= NR_OPEN_DEFAULT,
 		.fd		= &init_files.fd_array[0],
 		.close_on_exec	= init_files.close_on_exec_init,
+		.close_before_core = init_files.close_before_core_init,
 		.open_fds	= init_files.open_fds_init,
 		.full_fds_bits	= init_files.full_fds_bits_init,
 	},
@@ -1277,6 +1341,7 @@ void __f_unlock_pos(struct file *f)
 void set_close_on_exec(unsigned int fd, int flag)
 {
 	struct files_struct *files = current->files;
+
 	spin_lock(&files->file_lock);
 	__set_close_on_exec(fd, files_fdtable(files), flag);
 	spin_unlock(&files->file_lock);
@@ -1285,12 +1350,32 @@ void set_close_on_exec(unsigned int fd, int flag)
 bool get_close_on_exec(unsigned int fd)
 {
 	bool res;
+
 	rcu_read_lock();
 	res = close_on_exec(fd, current->files);
 	rcu_read_unlock();
 	return res;
 }
 
+void set_close_before_core(unsigned int fd, int flag)
+{
+	struct files_struct *files = current->files;
+
+	spin_lock(&files->file_lock);
+	__set_close_before_core(fd, files_fdtable(files), flag);
+	spin_unlock(&files->file_lock);
+}
+
+bool get_close_before_core(unsigned int fd)
+{
+	bool res;
+
+	rcu_read_lock();
+	res = close_before_core(fd, current->files);
+	rcu_read_unlock();
+	return res;
+}
+
 static int do_dup2(struct files_struct *files,
 	struct file *file, unsigned fd, unsigned flags)
 __releases(&files->file_lock)
diff --git a/include/linux/fdtable.h b/include/linux/fdtable.h
index c45306a9f..0a53d09bd 100644
--- a/include/linux/fdtable.h
+++ b/include/linux/fdtable.h
@@ -27,6 +27,7 @@ struct fdtable {
 	unsigned int max_fds;
 	struct file __rcu **fd;      /* current fd array */
 	unsigned long *close_on_exec;
+	unsigned long *close_before_core;
 	unsigned long *open_fds;
 	unsigned long *full_fds_bits;
 	struct rcu_head rcu;
@@ -51,6 +52,7 @@ struct files_struct {
 	spinlock_t file_lock ____cacheline_aligned_in_smp;
 	unsigned int next_fd;
 	unsigned long close_on_exec_init[1];
+	unsigned long close_before_core_init[1];
 	unsigned long open_fds_init[1];
 	unsigned long full_fds_bits_init[1];
 	struct file __rcu * fd_array[NR_OPEN_DEFAULT];
@@ -97,6 +99,11 @@ static inline bool close_on_exec(unsigned int fd, const struct files_struct *fil
 	return test_bit(fd, files_fdtable(files)->close_on_exec);
 }
 
+static inline bool close_before_core(unsigned int fd, const struct files_struct *files)
+{
+	return test_bit(fd, files_fdtable(files)->close_before_core);
+}
+
 struct task_struct;
 
 void put_files_struct(struct files_struct *fs);
diff --git a/include/linux/file.h b/include/linux/file.h
index 27484b444..52d27328f 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -88,6 +88,8 @@ extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
 extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
 extern void set_close_on_exec(unsigned int fd, int flag);
 extern bool get_close_on_exec(unsigned int fd);
+extern void set_close_before_core(unsigned int fd, int flag);
+extern bool get_close_before_core(unsigned int fd);
 extern int __get_unused_fd_flags(unsigned flags, unsigned long nofile);
 extern int get_unused_fd_flags(unsigned flags);
 extern void put_unused_fd(unsigned int fd);
diff --git a/include/linux/sched/task.h b/include/linux/sched/task.h
index 41ed884cf..d162fb2d9 100644
--- a/include/linux/sched/task.h
+++ b/include/linux/sched/task.h
@@ -93,6 +93,7 @@ static inline void exit_thread(struct task_struct *tsk)
 extern __noreturn void do_group_exit(int);
 
 extern void exit_files(struct task_struct *);
+extern void exit_files_before_core(struct task_struct *);
 extern void exit_itimers(struct task_struct *);
 
 extern pid_t kernel_clone(struct kernel_clone_args *kargs);
diff --git a/include/uapi/asm-generic/fcntl.h b/include/uapi/asm-generic/fcntl.h
index 613475285..f6cfe2fa5 100644
--- a/include/uapi/asm-generic/fcntl.h
+++ b/include/uapi/asm-generic/fcntl.h
@@ -131,6 +131,14 @@
 #define F_GETOWNER_UIDS	17
 #endif
 
+#ifndef F_GETFD_EX
+#define F_GETFD_EX	18
+#endif
+
+#ifndef F_SETFD_EX
+#define F_SETFD_EX	19
+#endif
+
 /*
  * Open File Description Locks
  *
@@ -159,6 +167,9 @@ struct f_owner_ex {
 /* for F_[GET|SET]FL */
 #define FD_CLOEXEC	1	/* actually anything with low bit set goes */
 
+/* for F_[GET|SET]FD_EX */
+#define FD_CLOBCOR	2	/* close the fd before dump core */
+
 /* for posix fcntl() and lockf() */
 #ifndef F_RDLCK
 #define F_RDLCK		0
-- 
2.34.1


^ permalink raw reply related

* Re: [PATCH] vfs: missing inode operation should return a consistent error code
From: Pedro Falcato @ 2026-06-17 14:44 UTC (permalink / raw)
  To: Jan Kara
  Cc: Jori Koolstra, Jeff Layton, Alexander Viro, Christian Brauner,
	Arnd Bergmann, open list:FILESYSTEMS (VFS and infrastructure),
	open list, open list:GENERIC INCLUDE/ASM HEADER FILES
In-Reply-To: <m5fqzr2ny4zb36u6zhmrrxgl36ycsxvlqnzf5idvsq4lxpfh3i@g276qtqgfv3f>

On Mon, Jun 01, 2026 at 06:50:10PM +0200, Jan Kara wrote:
> On Mon 01-06-26 18:27:53, Jori Koolstra wrote:
> > 
> > > Op 01-06-2026 17:58 CEST schreef Jan Kara <jack@suse.cz>:
> > > 
> > >  
> > > On Sun 31-05-26 10:08:47, Jeff Layton wrote:
> > > > 
> > > > This seems ill-advised. The problem is that most of this behavior has
> > > > been well established for years, and not all userland software (and
> > > > even some internal callers like nfsd), will react well when you go
> > > > changing behavior like this.
> > > > 
> > > > As a case in point, the POSIX spec doesn't list EOPNOTSUPP as a valid
> > > > error return for open():
> > > > 
> > > >    https://pubs.opengroup.org/onlinepubs/9690949399/functions/open.html
> > > > 
> > > > The manpage for open() says only:
> > > > 
> > > >        EOPNOTSUPP
> > > >               The filesystem containing pathname does not support O_TMPFILE.
> > > > 
> > > > What is the poor userland developer to make of this when open() starts
> > > > returning EOPNOTSUPP without O_TMPFILE being specified?
> > > 
> > > So I wouldn't care as much about POSIX, we largely ignore it anyway in the
> > > kernel. But I tend to agree that changing the error code we returned for
> > > several decades just for the sake of "cleanliness" isn't IMHO a good enough
> > > reason to risk breaking userspace or causing confusion.
> > > 
> > > 								Honza
> > > -- 
> > > Jan Kara <jack@suse.com>
> > > SUSE Labs, CR
> > 
> > For what its worth, the EACCES return value for not having a create()
> > call on the fs is also not specified in the open() man page. For mkdir,
> > EPERM IS specified.
> 
> Yep, as I said we don't really follow POSIX closely. And it goes way
> further than just error code :)

Not trying to excessively necro here (just seen this thread), but I'll
have to interject here: POSIX very much lets you return whatever error codes
you want. Quoting directly from POSIX.1-2024 (System Interfaces, 2.3 Error Numbers)

> Implementations may support additional errors not included in this list,
> may generate errors included in this list under circumstances other than
> those described here, or may contain extensions or limitations that prevent
> some errors from occurring.

and also:
> Implementations may generate error numbers listed here under circumstances
> other than those described [...]
> Implementations shall not generate a different error number from one
> required by this volume of POSIX.1-2024 for an error condition described
> in this volume of POSIX.1-2024, but may generate additional errors unless
> explicitly disallowed for a particular function.

which pretty much give you the freedom to do whatever you want (and that's how
I've seen other people language-lawyer this as well).

So, yes, while it is true that the kernel sometimes treats POSIX as merely a
suggestion, in this case we're strictly adhering :)


> 
> > But in general, can we never add new error codes to any syscall? Are
> > there user programs that do neatly check for each specified error code in
> > the man page, but that do not implement a fallback at all? I mean, I am
> > not unsympathetic to the arguments that you and Jeff make, but such a
> > user program would be odd.
> 
> We certainly can (and sometimes do) modify the returned errors. It is
> always just a balancing act between the benefit of the change and chances
> somebody will get broken by it. In this case I don't quite see the
> benefit, not that I'd be too worried about the a regression but there's
> always the chance...
> 

FWIW my opinion here would be that changing the error number doesn't _really_
matter. Filesystems with missing ops are generally already outliers in "sane
filesystems semantics ", and it's unlikely that someone is doing something like

if (unlink(path) < 0 && errno == EPERM) {
	printf("path is bad since you can't unlink it!!!\n");
}

particularly as most of these error numbers are actually impossible to
distinguish (I don't have permissions on the filesystem, or does the
filesystem not implement this op?).


-- 
Pedro

^ permalink raw reply

* Re: [PATCH] vfs: missing inode operation should return a consistent error code
From: Christian Brauner @ 2026-06-17 13:24 UTC (permalink / raw)
  To: Jori Koolstra
  Cc: Jan Kara, Jeff Layton, Alexander Viro, Arnd Bergmann,
	open list:FILESYSTEMS (VFS and infrastructure), open list,
	open list:GENERIC INCLUDE/ASM HEADER FILES
In-Reply-To: <1512332516.1435503.1781209872436@kpc.webmail.kpnmail.nl>

On Thu, Jun 11, 2026 at 10:31:12PM +0200, Jori Koolstra wrote:
> @Christian, since you suggested equalizing the error codes for missing
> inode ops, what is your opinion?
> 
> > Op 01-06-2026 18:50 CEST schreef Jan Kara <jack@suse.cz>:
> > 
> > We certainly can (and sometimes do) modify the returned errors. It is
> > always just a balancing act between the benefit of the change and chances
> > somebody will get broken by it. In this case I don't quite see the
> > benefit, not that I'd be too worried about the a regression but there's
> > always the chance...
> > 
> > 								Honza
> 
> No, I get that, and maybe you are right. I feel in this case it would be
> really odd if this breaks anyone's application. It would mean you are
> rigorously testing for receiving specific error codes, without handling
> a general error case. That just seems odd, especially since some of these
> error codes are not even listed as a possibility for missing ops (like EACCES).
> I would say we change this and revert if anyone complains. I believe that was
> also Christian's view in another thread, but I may be mistaken.

It's a general stance, yes. I think trying to make the things we
maintain more consistent is worth risking someone reporting a
regression.

^ permalink raw reply

* Re: [PATCH] init/main: Expose built-in initcalls and blacklist status via debugfs
From: Petr Pavlu @ 2026-06-17 12:39 UTC (permalink / raw)
  To: Aaron Tomlin
  Cc: arnd, mcgrof, da.gomez, samitolvanen, neelx, sean, chjohnst,
	steve, mproche, nick.lane, linux-arch, linux-modules,
	linux-kernel
In-Reply-To: <20260510061301.41341-1-atomlin@atomlin.com>

On 5/10/26 8:13 AM, Aaron Tomlin wrote:
> At present, identifying the correct function name to supply to the
> "initcall_blacklist=" kernel command-line parameter requires manual
> inspection of the source code or kernel symbol tables. Furthermore,
> administrators lack a reliable runtime mechanism to verify whether a
> specified built-in module has been successfully blacklisted.

My understanding is that initcall_blacklist is primarily a debugging
facility. This is documented in
Documentation/admin-guide/kernel-parameters.txt [1] and also outlined in
the initial commit 7b0b73d76651 ("init/main.c: add initcall_blacklist
kernel parameter") [2]. It is expected that to use it, one must inspect
the kernel source code.

If the goal is to allow specific built-in modules to be blacklisted,
I wonder whether extending module_blacklist to also cover built-in
modules might be a better option. Module names are more appropriate for
administrators to use, while initcall names should remain internal to
the kernel. Additionally, initcalls are typically "static" and therefore
are not guaranteed to have unique names + using module names avoids
a dependency on CONFIG_KALLSYMS=y.

[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/kernel-parameters.txt?h=v7.1#n2408
[2] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7b0b73d76651e5f88c88b76efa18d719f832bf6f

-- 
Thanks,
Petr

^ permalink raw reply

* Re: [PATCH v2 2/4] net: af_unix: Useful handling of LSM denials on SCM_RIGHTS
From: Kuniyuki Iwashima @ 2026-06-17  0:06 UTC (permalink / raw)
  To: Jori Koolstra
  Cc: brauner, cyphar, Alexander Viro, Jan Kara, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Arnd Bergmann, Willem de Bruijn, linux-fsdevel, Jeff Layton,
	open list, open list:NETWORKING [GENERAL],
	open list:GENERIC INCLUDE/ASM HEADER FILES
In-Reply-To: <20260616143020.3458085-2-jkoolstra@xs4all.nl>

On Tue, Jun 16, 2026 at 7:29 AM Jori Koolstra <jkoolstra@xs4all.nl> wrote:
>
> Right now if some LSM such as Smack denies an AF_UNIX socket peer to
> receive an SCM_RIGHTS fd, the SCM_RIGHTS fd array will be cut short at
> that point, and MSG_CTRUNC is set on return of recvmsg(). This is
> highly problematic behaviour, because it leaves the receiver
> wondering what happened. As per man page MSG_CTRUNC is supposed to
> indicate that the control buffer was sized too short, but suddenly
> a permission error might result in the exact same flag being set.
> Moreover, the receiver has no chance to determine how many fds got
> originally sent and how many were suppressed.[1]
>
> Add a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more useful
> handling of LSM denials when receiving SCM_RIGHTS messages: instead of
> truncating the message at the first blocked fd, keep every fd slot
> and store the LSM errno in the blocked slot.
>
> [1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights
>
> Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
> ---
>  fs/file.c                         | 48 ++++++++++++++++++++-----------
>  include/linux/file.h              |  2 ++
>  include/net/af_unix.h             |  1 +

net-next is closed during the merge window, so please repost after that.

a few comments: please

* add cover letter
* separate fs/ and net/ changes
* do not touch tools/testing/selftest/Makefile
* use kselftest_harness.h and system()
* check other local rules (reverse xmas tree order, etc) in
Documentation/process/maintainer-netdev.rst

---
pw-bot: cr

^ permalink raw reply

* [PATCH v2 2/4] net: af_unix: Useful handling of LSM denials on SCM_RIGHTS
From: Jori Koolstra @ 2026-06-16 14:30 UTC (permalink / raw)
  To: brauner, cyphar, Alexander Viro, Jan Kara, Kuniyuki Iwashima,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Arnd Bergmann, Willem de Bruijn
  Cc: linux-fsdevel, Jori Koolstra, Jeff Layton, open list,
	open list:NETWORKING [GENERAL],
	open list:GENERIC INCLUDE/ASM HEADER FILES
In-Reply-To: <20260616143020.3458085-1-jkoolstra@xs4all.nl>

Right now if some LSM such as Smack denies an AF_UNIX socket peer to
receive an SCM_RIGHTS fd, the SCM_RIGHTS fd array will be cut short at
that point, and MSG_CTRUNC is set on return of recvmsg(). This is
highly problematic behaviour, because it leaves the receiver
wondering what happened. As per man page MSG_CTRUNC is supposed to
indicate that the control buffer was sized too short, but suddenly
a permission error might result in the exact same flag being set.
Moreover, the receiver has no chance to determine how many fds got
originally sent and how many were suppressed.[1]

Add a SO_RIGHTS_NOTRUNC option to UNIX sockets to enable more useful
handling of LSM denials when receiving SCM_RIGHTS messages: instead of
truncating the message at the first blocked fd, keep every fd slot
and store the LSM errno in the blocked slot.

[1]: https://github.com/uapi-group/kernel-features#useful-handling-of-lsm-denials-on-scm_rights

Signed-off-by: Jori Koolstra <jkoolstra@xs4all.nl>
---
 fs/file.c                         | 48 ++++++++++++++++++++-----------
 include/linux/file.h              |  2 ++
 include/net/af_unix.h             |  1 +
 include/net/scm.h                 | 15 +++++++---
 include/uapi/asm-generic/socket.h |  3 ++
 net/compat.c                      |  4 +--
 net/core/scm.c                    | 13 +++++----
 net/unix/af_unix.c                |  9 ++++++
 8 files changed, 68 insertions(+), 27 deletions(-)

diff --git a/fs/file.c b/fs/file.c
index 628ca07dc4b1..2bc22cc69e84 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -1367,6 +1367,25 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
 	return err;
 }
 
+static int __receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
+{
+	int error;
+
+	FD_PREPARE(fdf, o_flags, file);
+	if (fdf.err)
+		return fdf.err;
+	get_file(file);
+
+	if (ufd) {
+		error = put_user(fd_prepare_fd(fdf), ufd);
+		if (error)
+			return error;
+	}
+
+	__receive_sock(fd_prepare_file(fdf));
+	return fd_publish(fdf);
+}
+
 /**
  * receive_fd() - Install received file into file descriptor table
  * @file: struct file that was received from another process
@@ -1384,27 +1403,24 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
  */
 int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags)
 {
-	int error;
-
-	error = security_file_receive(file);
+	int error = security_file_receive(file);
 	if (error)
 		return error;
+	return __receive_fd(file, ufd, o_flags);
+}
+EXPORT_SYMBOL_GPL(receive_fd);
 
-	FD_PREPARE(fdf, o_flags, file);
-	if (fdf.err)
-		return fdf.err;
-	get_file(file);
-
-	if (ufd) {
-		error = put_user(fd_prepare_fd(fdf), ufd);
-		if (error)
-			return error;
+int receive_fd_filtered(struct file *file, int __user *ufd, unsigned int o_flags,
+		bool *filtered)
+{
+	int error = security_file_receive(file);
+	if (error) {
+		*filtered = true;
+		return error;
 	}
-
-	__receive_sock(fd_prepare_file(fdf));
-	return fd_publish(fdf);
+	*filtered = false;
+	return __receive_fd(file, ufd, o_flags);
 }
-EXPORT_SYMBOL_GPL(receive_fd);
 
 int receive_fd_replace(int new_fd, struct file *file, unsigned int o_flags)
 {
diff --git a/include/linux/file.h b/include/linux/file.h
index 27484b444d31..748f08470bb4 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -119,6 +119,8 @@ DEFINE_FREE(fput, struct file *, if (!IS_ERR_OR_NULL(_T)) fput(_T))
 extern void fd_install(unsigned int fd, struct file *file);
 
 int receive_fd(struct file *file, int __user *ufd, unsigned int o_flags);
+int receive_fd_filtered(struct file *file, int __user *ufd, unsigned int o_flags,
+		bool *filtered);
 
 int receive_fd_replace(int new_fd, struct file *file, unsigned int o_flags);
 
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 34f53dde65ce..bb1b3dee02e8 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -49,6 +49,7 @@ struct unix_sock {
 	struct scm_stat		scm_stat;
 	int			inq_len;
 	bool			recvmsg_inq;
+	bool			scm_rights_notrunc;
 #if IS_ENABLED(CONFIG_AF_UNIX_OOB)
 	struct sk_buff		*oob_skb;
 #endif
diff --git a/include/net/scm.h b/include/net/scm.h
index c52519669349..761cda0803fb 100644
--- a/include/net/scm.h
+++ b/include/net/scm.h
@@ -50,8 +50,8 @@ struct scm_cookie {
 #endif
 };
 
-void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm);
-void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm);
+void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, bool notrunc);
+void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm, bool notrunc);
 int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm);
 void __scm_destroy(struct scm_cookie *scm);
 struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl);
@@ -108,11 +108,18 @@ void scm_recv_unix(struct socket *sock, struct msghdr *msg,
 		   struct scm_cookie *scm, int flags);
 
 static inline int scm_recv_one_fd(struct file *f, int __user *ufd,
-				  unsigned int flags)
+				  unsigned int flags, bool notrunc)
 {
+	bool filtered;
+	int error;
+
 	if (!ufd)
 		return -EFAULT;
-	return receive_fd(f, ufd, flags);
+
+	error = receive_fd_filtered(f, ufd, flags, &filtered);
+	if (filtered && notrunc)
+		return put_user(error, ufd);
+	return error;
 }
 
 #endif /* __LINUX_NET_SCM_H */
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 53b5a8c002b1..c5fb2ee96830 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -150,6 +150,9 @@
 #define SO_INQ			84
 #define SCM_INQ			SO_INQ
 
+#define SO_RIGHTS_NOTRUNC	85
+#define SCM_RIGHTS_NOTRUNC	SO_RIGHTS_NOTRUNC
+
 #if !defined(__KERNEL__)
 
 #if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__))
diff --git a/net/compat.c b/net/compat.c
index d68cf9c3aad5..6bdf4a2c9077 100644
--- a/net/compat.c
+++ b/net/compat.c
@@ -286,7 +286,7 @@ static int scm_max_fds_compat(struct msghdr *msg)
 	return (msg->msg_controllen - sizeof(struct compat_cmsghdr)) / sizeof(int);
 }
 
-void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
+void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm, bool notrunc)
 {
 	struct compat_cmsghdr __user *cm =
 		(struct compat_cmsghdr __user *)msg->msg_control_user;
@@ -296,7 +296,7 @@ void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm)
 	int err = 0, i;
 
 	for (i = 0; i < fdmax; i++) {
-		err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
+		err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags, notrunc);
 		if (err < 0)
 			break;
 	}
diff --git a/net/core/scm.c b/net/core/scm.c
index a73b1eb30fd2..1ef4e9431661 100644
--- a/net/core/scm.c
+++ b/net/core/scm.c
@@ -351,7 +351,7 @@ static int scm_max_fds(struct msghdr *msg)
 	return (msg->msg_controllen - sizeof(struct cmsghdr)) / sizeof(int);
 }
 
-void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
+void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm, bool notrunc)
 {
 	struct cmsghdr __user *cm =
 		(__force struct cmsghdr __user *)msg->msg_control_user;
@@ -365,12 +365,12 @@ void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm)
 		return;
 
 	if (msg->msg_flags & MSG_CMSG_COMPAT) {
-		scm_detach_fds_compat(msg, scm);
+		scm_detach_fds_compat(msg, scm, notrunc);
 		return;
 	}
 
 	for (i = 0; i < fdmax; i++) {
-		err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags);
+		err = scm_recv_one_fd(scm->fp->fp[i], cmsg_data + i, o_flags, notrunc);
 		if (err < 0)
 			break;
 	}
@@ -542,8 +542,11 @@ void scm_recv_unix(struct socket *sock, struct msghdr *msg,
 	if (!__scm_recv_common(sock->sk, msg, scm, flags))
 		return;
 
-	if (scm->fp)
-		scm_detach_fds(msg, scm);
+	if (scm->fp) {
+		struct unix_sock *u = unix_sk(sock->sk);
+		bool notrunc = READ_ONCE(u->scm_rights_notrunc);
+		scm_detach_fds(msg, scm, notrunc);
+	}
 
 	if (sock->sk->sk_scm_pidfd)
 		scm_pidfd_recv(msg, scm);
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 0d9cd977c7b7..4e1463ee2815 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -921,6 +921,7 @@ static bool unix_custom_sockopt(int optname)
 {
 	switch (optname) {
 	case SO_INQ:
+	case SO_RIGHTS_NOTRUNC:
 		return true;
 	default:
 		return false;
@@ -956,6 +957,14 @@ static int unix_setsockopt(struct socket *sock, int level, int optname,
 
 		WRITE_ONCE(u->recvmsg_inq, val);
 		break;
+
+	case SO_RIGHTS_NOTRUNC:
+		if (val > 1 || val < 0)
+			return -EINVAL;
+
+		WRITE_ONCE(u->scm_rights_notrunc, val);
+		break;
+
 	default:
 		return -ENOPROTOOPT;
 	}
-- 
2.54.0


^ permalink raw reply related

* Re: [PATCH v13 0/4] kunit: Add support for suppressing warning backtraces
From: David Gow @ 2026-06-16 12:06 UTC (permalink / raw)
  To: Albert Esteve, Arnd Bergmann, Brendan Higgins, Rae Moar,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
	workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
	Guenter Roeck, Kees Cook, Linux Kernel Functional Testing,
	Maíra Canal, Dan Carpenter, Simona Vetter
In-Reply-To: <CADSE00+typ3Zi5Vf0Z276+e0G7PuS7mt7oA9h5awBu3YgYKw0g@mail.gmail.com>

Le 16/06/2026 à 7:44 PM, Albert Esteve a écrit :
> On Fri, May 15, 2026 at 2:29 PM Albert Esteve <aesteve@redhat.com> wrote:
>>
>> Some unit tests intentionally trigger warning backtraces by passing bad
>> parameters to kernel API functions. Such unit tests typically check the
>> return value from such calls, not the existence of the warning backtrace.
>>
>> Such intentionally generated warning backtraces are neither desirable
>> nor useful for a number of reasons:
>> - They can result in overlooked real problems.
>> - A warning that suddenly starts to show up in unit tests needs to be
>>   investigated and has to be marked to be ignored, for example by
>>   adjusting filter scripts. Such filters are ad hoc because there is
>>   no real standard format for warnings. On top of that, such filter
>>   scripts would require constant maintenance.
>>
>> One option to address the problem would be to add messages such as
>> "expected warning backtraces start/end here" to the kernel log.
>> However, that would again require filter scripts, might result in
>> missing real problematic warning backtraces triggered while the test
>> is running, and the irrelevant backtrace(s) would still clog the
>> kernel log.
>>
>> Solve the problem by providing a means to suppress warning backtraces
>> originating from the current kthread while executing test code.
>> Since each KUnit test runs in its own kthread, this effectively scopes
>> suppression to the test that enabled it, without requiring any
>> architecture-specific code.
>>
>> Overview:
>> Patch#1 Introduces the suppression infrastructure integrated into
>>         KUnit's hook mechanism.
>> Patch#2 Adds selftests to validate the functionality.
>> Patch#3 Demonstrates real-world usage in the DRM subsystem.
>> Patch#4 Documents the new API and usage guidelines.
>>
>> Design Notes:
>> Suppression is integrated into the existing KUnit hooks infrastructure,
>> reusing the kunit_running static branch for zero overhead
>> when no tests are running. The implementation lives entirely in the
>> kunit module; only a static-inline wrapper and a function pointer
>> slot are added to built-in code.
>>
>> Suppression is checked at three points in the warning path:
>> - In `warn_slowpath_fmt()` (kernel/panic.c), for architectures without
>>   __WARN_FLAGS. The check runs before any output, fully suppressing
>>   both message and backtrace.
>> - In `__warn_printk()` (kernel/panic.c), for architectures that define
>>   __WARN_FLAGS but not their own __WARN_printf (arm64, loongarch,
>>   parisc, powerpc, riscv, sh). The check suppresses the warning message
>>   text that is printed before the trap enters __report_bug().
>> - In `__report_bug()` (lib/bug.c), for architectures that define
>>   __WARN_FLAGS. The check runs before `__warn()` is called, suppressing
>>   the backtrace and stack dump.
>>
>> To avoid double-counting on architectures where both `__warn_printk()`
>> and `__report_bug()` run for the same warning, the hook takes a bool
>> parameter: true to increment the suppression counter, false to suppress
>> without counting.
>>
>> The suppression state is dynamically allocated via kunit_kzalloc() and
>> tied to the KUnit test lifecycle via `kunit_add_action()`, ensuring
>> automatic cleanup at test exit. Writer-side access to the global
>> suppression list is serialized with a spinlock; readers use RCU.
>>
>> Two API forms are provided:
>> - kunit_warning_suppress(test) { ... }: scoped blocks with automatic
>>   cleanup. The suppression handle is not accessible outside the block,
>>   so warning counts (if needed) must be checked inside. Multiple
>>   sequential suppression blocks are allowed.
>> - kunit_start/end_suppress_warning(test): direct functions that return
>>   an explicit handle. Use when the handle needs to be retained, or passed
>>   across helpers. Multiple sequential suppression blocks are allowed.
>>
>> This series is based on the RFC patch and subsequent discussion at
>> https://patchwork.kernel.org/project/linux-kselftest/patch/02546e59-1afe-4b08-ba81-d94f3b691c9a@moroto.mountain/
>> and offers a more comprehensive solution of the problem discussed there.
>>
>> Changes since RFC:
>> - Introduced CONFIG_KUNIT_SUPPRESS_BACKTRACE
>> - Minor cleanups and bug fixes
>> - Added support for all affected architectures
>> - Added support for counting suppressed warnings
>> - Added unit tests using those counters
>> - Added patch to suppress warning backtraces in dev_addr_lists tests
>>
>> Changes since v1:
>> - Rebased to v6.9-rc1
>> - Added Tested-by:, Acked-by:, and Reviewed-by: tags
>>   [I retained those tags since there have been no functional changes]
>> - Introduced KUNIT_SUPPRESS_BACKTRACE configuration option, enabled by
>>   default.
>>
>> Changes since v2:
>> - Rebased to v6.9-rc2
>> - Added comments to drm warning suppression explaining why it is needed.
>> - Added patch to move conditional code in arch/sh/include/asm/bug.h
>>   to avoid kerneldoc warning
>> - Added architecture maintainers to Cc: for architecture specific patches
>> - No functional changes
>>
>> Changes since v3:
>> - Rebased to v6.14-rc6
>> - Dropped net: "kunit: Suppress lock warning noise at end of dev_addr_lists tests"
>>   since 3db3b62955cd6d73afde05a17d7e8e106695c3b9
>> - Added __kunit_ and KUNIT_ prefixes.
>> - Tested on interessed architectures.
>>
>> Changes since v4:
>> - Rebased to v6.15-rc7
>> - Dropped all code in __report_bug()
>> - Moved all checks in WARN*() macros.
>> - Dropped all architecture specific code.
>> - Made __kunit_is_suppressed_warning nice to noinstr functions.
>>
>> Changes since v5:
>> - Rebased to v7.0-rc3
>> - Added RCU protection for the suppressed warnings list.
>> - Added static key and branching optimization.
>> - Removed custom `strcmp` implementation and reworked
>>   __kunit_is_suppressed_warning() entrypoint function.
>>
>> Changes since v6:
>> - Moved suppression checks from WARN*() macros to warn_slowpath_fmt()
>>   and __report_bug().
>> - Replaced stack-allocated suppression struct with kunit_kzalloc() heap
>>   allocation tied to the KUnit test lifecycle.
>> - Changed suppression strategy from function-name matching to task-scoped:
>>   all warnings on the current task are suppressed between START and END,
>>   rather than only warnings originating from a specific named function.
>> - Simplified macro API: removed KUNIT_DECLARE_SUPPRESSED_WARNING(),
>>   the START macro now takes (test) and handles allocation internally.
>> - Removed static key and branching optiomization, as by the time it
>>   was executed, callers are already in warn slowpaths.
>> - Link to v6: https://lore.kernel.org/r/20260317-kunit_add_support-v6-0-dd22aeb3fe5d@redhat.com
>>
>> Changes since v7:
>> - Integrated suppression into existing KUnit hooks infrastructure
>> - Removed CONFIG_KUNIT_SUPPRESS_BACKTRACE
>> - Added suppression check in __warn_printk()
>> - Added spinlock for writer-side RCU protection
>> - Replaced explicit rcu_read_lock/unlock with guard(rcu)()
>> - Added scoped API (kunit_warning_suppress) using __cleanup attribute
>> - Updated DRM patch to use scoped API
>> - Expanded self-tests: incremental counting, cross-kthread isolation
>> - Rewrote documentation covering all three API forms with examples
>> - Link to v7: https://lore.kernel.org/r/20260420-kunit_add_support-v7-0-e8bc6e0f70de@redhat.com
>>
>> Changes since v8:
>> - Rebased to v7.1-rc2
>> - Remove KUNIT_START/END_SUPPRESSED_WARNING() macros
>> - Add KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT checks to drm tests
>> - Link to v8: https://lore.kernel.org/r/20260504-kunit_add_support-v8-0-3e5957cdd235@redhat.com
>>
>> Changes since v9:
>> - Fix silent false-pass when kunit_start_suppress_warning() returns NULL
>> - Fix RCU lockdep splat for kunit_is_suppressed_warning() calls
>> - Move disable_trace_on_warning() in __report_bug()
>> - Make suppress counter atomic
>> - Mark helper warn functions in selftest as noinline
>> - Add kunit_skip() for CONFIG_BUG=n in selftests
>> - Fix potentially uninitialized data.was_active in kthread seltest
>> - Add kthread_stop() in kthread selftest early exit
>> - Initialize scaling_factor to INT_MIN in DRM scaling tests
>> - Add include for bool in test-bug.h to fix CONFIG_KUNIT=n case
>> - Link to v9: https://lore.kernel.org/r/20260508-kunit_add_support-v9-0-99df7aa880f6@redhat.com
>>
>> Changes since v10:
>> - Remove synchronize_rcu() to avoid sleeping in atomic context
>> - Pin task_struct refcount to prevent ABA false-positive matches
>> - Loop in suppression selftest to prevent use-after-free on kthread exit
>> - Skip DRM rect tests on CONFIG_BUG=n
>> - Link to v10: https://lore.kernel.org/r/20260513-kunit_add_support-v10-0-e379d206c8cd@redhat.com
>>
>> Changes since v11:
>> - Use call_rcu() to defer free without blocking
>> - Remove #ifdef CONFIG_KUNIT guard in lib/bug.c
>> - Remove stale config checks from selftest
>> - Replace skip on DRM rect tests with conditional expectation
>> - Link to v11: https://lore.kernel.org/r/20260514-kunit_add_support-v11-0-b36a530a6d8f@redhat.com
>>
>> Changes since v12:
>> - Reverted to the v9 synchronize_rcu() approach
>> - Add in_task() check at the top of __kunit_is_suppressed_warning_impl()
>> - Link to v12: https://lore.kernel.org/r/20260515-kunit_add_support-v12-0-a216dc228be8@redhat.com
> 
> Hi all,
> 
> I am not sure if there is a decision to merge this series or if any
> work remains to be done.
> 
> I reckon I sent a few versions back-to-back last time as I was
> struggling with Sashiko. However, there are no significant changes,
> the core strategy remains unchanged, involving only the addition of
> safety checks and the removal of some redundancies to satisfy the AI.
> I am just clarifying in case the last versions/respins were unclear. I
> tried running AI reviews locally but Sashiko always found more issues
> than my local model could.
> 
The latest version was fine. It's just landed for 7.2:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=42eb3a5ef6bc56192bf450c79a3f274e081f8131

Thanks for all of your work,
-- David

^ permalink raw reply

* Re: [PATCH v13 0/4] kunit: Add support for suppressing warning backtraces
From: Albert Esteve @ 2026-06-16 11:44 UTC (permalink / raw)
  To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
	workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
	Guenter Roeck, Kees Cook, Linux Kernel Functional Testing,
	Maíra Canal, Dan Carpenter, Simona Vetter
In-Reply-To: <20260515-kunit_add_support-v13-0-18ee42f96e7b@redhat.com>

On Fri, May 15, 2026 at 2:29 PM Albert Esteve <aesteve@redhat.com> wrote:
>
> Some unit tests intentionally trigger warning backtraces by passing bad
> parameters to kernel API functions. Such unit tests typically check the
> return value from such calls, not the existence of the warning backtrace.
>
> Such intentionally generated warning backtraces are neither desirable
> nor useful for a number of reasons:
> - They can result in overlooked real problems.
> - A warning that suddenly starts to show up in unit tests needs to be
>   investigated and has to be marked to be ignored, for example by
>   adjusting filter scripts. Such filters are ad hoc because there is
>   no real standard format for warnings. On top of that, such filter
>   scripts would require constant maintenance.
>
> One option to address the problem would be to add messages such as
> "expected warning backtraces start/end here" to the kernel log.
> However, that would again require filter scripts, might result in
> missing real problematic warning backtraces triggered while the test
> is running, and the irrelevant backtrace(s) would still clog the
> kernel log.
>
> Solve the problem by providing a means to suppress warning backtraces
> originating from the current kthread while executing test code.
> Since each KUnit test runs in its own kthread, this effectively scopes
> suppression to the test that enabled it, without requiring any
> architecture-specific code.
>
> Overview:
> Patch#1 Introduces the suppression infrastructure integrated into
>         KUnit's hook mechanism.
> Patch#2 Adds selftests to validate the functionality.
> Patch#3 Demonstrates real-world usage in the DRM subsystem.
> Patch#4 Documents the new API and usage guidelines.
>
> Design Notes:
> Suppression is integrated into the existing KUnit hooks infrastructure,
> reusing the kunit_running static branch for zero overhead
> when no tests are running. The implementation lives entirely in the
> kunit module; only a static-inline wrapper and a function pointer
> slot are added to built-in code.
>
> Suppression is checked at three points in the warning path:
> - In `warn_slowpath_fmt()` (kernel/panic.c), for architectures without
>   __WARN_FLAGS. The check runs before any output, fully suppressing
>   both message and backtrace.
> - In `__warn_printk()` (kernel/panic.c), for architectures that define
>   __WARN_FLAGS but not their own __WARN_printf (arm64, loongarch,
>   parisc, powerpc, riscv, sh). The check suppresses the warning message
>   text that is printed before the trap enters __report_bug().
> - In `__report_bug()` (lib/bug.c), for architectures that define
>   __WARN_FLAGS. The check runs before `__warn()` is called, suppressing
>   the backtrace and stack dump.
>
> To avoid double-counting on architectures where both `__warn_printk()`
> and `__report_bug()` run for the same warning, the hook takes a bool
> parameter: true to increment the suppression counter, false to suppress
> without counting.
>
> The suppression state is dynamically allocated via kunit_kzalloc() and
> tied to the KUnit test lifecycle via `kunit_add_action()`, ensuring
> automatic cleanup at test exit. Writer-side access to the global
> suppression list is serialized with a spinlock; readers use RCU.
>
> Two API forms are provided:
> - kunit_warning_suppress(test) { ... }: scoped blocks with automatic
>   cleanup. The suppression handle is not accessible outside the block,
>   so warning counts (if needed) must be checked inside. Multiple
>   sequential suppression blocks are allowed.
> - kunit_start/end_suppress_warning(test): direct functions that return
>   an explicit handle. Use when the handle needs to be retained, or passed
>   across helpers. Multiple sequential suppression blocks are allowed.
>
> This series is based on the RFC patch and subsequent discussion at
> https://patchwork.kernel.org/project/linux-kselftest/patch/02546e59-1afe-4b08-ba81-d94f3b691c9a@moroto.mountain/
> and offers a more comprehensive solution of the problem discussed there.
>
> Changes since RFC:
> - Introduced CONFIG_KUNIT_SUPPRESS_BACKTRACE
> - Minor cleanups and bug fixes
> - Added support for all affected architectures
> - Added support for counting suppressed warnings
> - Added unit tests using those counters
> - Added patch to suppress warning backtraces in dev_addr_lists tests
>
> Changes since v1:
> - Rebased to v6.9-rc1
> - Added Tested-by:, Acked-by:, and Reviewed-by: tags
>   [I retained those tags since there have been no functional changes]
> - Introduced KUNIT_SUPPRESS_BACKTRACE configuration option, enabled by
>   default.
>
> Changes since v2:
> - Rebased to v6.9-rc2
> - Added comments to drm warning suppression explaining why it is needed.
> - Added patch to move conditional code in arch/sh/include/asm/bug.h
>   to avoid kerneldoc warning
> - Added architecture maintainers to Cc: for architecture specific patches
> - No functional changes
>
> Changes since v3:
> - Rebased to v6.14-rc6
> - Dropped net: "kunit: Suppress lock warning noise at end of dev_addr_lists tests"
>   since 3db3b62955cd6d73afde05a17d7e8e106695c3b9
> - Added __kunit_ and KUNIT_ prefixes.
> - Tested on interessed architectures.
>
> Changes since v4:
> - Rebased to v6.15-rc7
> - Dropped all code in __report_bug()
> - Moved all checks in WARN*() macros.
> - Dropped all architecture specific code.
> - Made __kunit_is_suppressed_warning nice to noinstr functions.
>
> Changes since v5:
> - Rebased to v7.0-rc3
> - Added RCU protection for the suppressed warnings list.
> - Added static key and branching optimization.
> - Removed custom `strcmp` implementation and reworked
>   __kunit_is_suppressed_warning() entrypoint function.
>
> Changes since v6:
> - Moved suppression checks from WARN*() macros to warn_slowpath_fmt()
>   and __report_bug().
> - Replaced stack-allocated suppression struct with kunit_kzalloc() heap
>   allocation tied to the KUnit test lifecycle.
> - Changed suppression strategy from function-name matching to task-scoped:
>   all warnings on the current task are suppressed between START and END,
>   rather than only warnings originating from a specific named function.
> - Simplified macro API: removed KUNIT_DECLARE_SUPPRESSED_WARNING(),
>   the START macro now takes (test) and handles allocation internally.
> - Removed static key and branching optiomization, as by the time it
>   was executed, callers are already in warn slowpaths.
> - Link to v6: https://lore.kernel.org/r/20260317-kunit_add_support-v6-0-dd22aeb3fe5d@redhat.com
>
> Changes since v7:
> - Integrated suppression into existing KUnit hooks infrastructure
> - Removed CONFIG_KUNIT_SUPPRESS_BACKTRACE
> - Added suppression check in __warn_printk()
> - Added spinlock for writer-side RCU protection
> - Replaced explicit rcu_read_lock/unlock with guard(rcu)()
> - Added scoped API (kunit_warning_suppress) using __cleanup attribute
> - Updated DRM patch to use scoped API
> - Expanded self-tests: incremental counting, cross-kthread isolation
> - Rewrote documentation covering all three API forms with examples
> - Link to v7: https://lore.kernel.org/r/20260420-kunit_add_support-v7-0-e8bc6e0f70de@redhat.com
>
> Changes since v8:
> - Rebased to v7.1-rc2
> - Remove KUNIT_START/END_SUPPRESSED_WARNING() macros
> - Add KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT checks to drm tests
> - Link to v8: https://lore.kernel.org/r/20260504-kunit_add_support-v8-0-3e5957cdd235@redhat.com
>
> Changes since v9:
> - Fix silent false-pass when kunit_start_suppress_warning() returns NULL
> - Fix RCU lockdep splat for kunit_is_suppressed_warning() calls
> - Move disable_trace_on_warning() in __report_bug()
> - Make suppress counter atomic
> - Mark helper warn functions in selftest as noinline
> - Add kunit_skip() for CONFIG_BUG=n in selftests
> - Fix potentially uninitialized data.was_active in kthread seltest
> - Add kthread_stop() in kthread selftest early exit
> - Initialize scaling_factor to INT_MIN in DRM scaling tests
> - Add include for bool in test-bug.h to fix CONFIG_KUNIT=n case
> - Link to v9: https://lore.kernel.org/r/20260508-kunit_add_support-v9-0-99df7aa880f6@redhat.com
>
> Changes since v10:
> - Remove synchronize_rcu() to avoid sleeping in atomic context
> - Pin task_struct refcount to prevent ABA false-positive matches
> - Loop in suppression selftest to prevent use-after-free on kthread exit
> - Skip DRM rect tests on CONFIG_BUG=n
> - Link to v10: https://lore.kernel.org/r/20260513-kunit_add_support-v10-0-e379d206c8cd@redhat.com
>
> Changes since v11:
> - Use call_rcu() to defer free without blocking
> - Remove #ifdef CONFIG_KUNIT guard in lib/bug.c
> - Remove stale config checks from selftest
> - Replace skip on DRM rect tests with conditional expectation
> - Link to v11: https://lore.kernel.org/r/20260514-kunit_add_support-v11-0-b36a530a6d8f@redhat.com
>
> Changes since v12:
> - Reverted to the v9 synchronize_rcu() approach
> - Add in_task() check at the top of __kunit_is_suppressed_warning_impl()
> - Link to v12: https://lore.kernel.org/r/20260515-kunit_add_support-v12-0-a216dc228be8@redhat.com

Hi all,

I am not sure if there is a decision to merge this series or if any
work remains to be done.

I reckon I sent a few versions back-to-back last time as I was
struggling with Sashiko. However, there are no significant changes,
the core strategy remains unchanged, involving only the addition of
safety checks and the removal of some redundancies to satisfy the AI.
I am just clarifying in case the last versions/respins were unclear. I
tried running AI reviews locally but Sashiko always found more issues
than my local model could.

BR,
Albert.

> --
> 2.34.1
>
> ---
> To: Brendan Higgins <brendan.higgins@linux.dev>
> To: David Gow <david@davidgow.net>
> To: Rae Moar <raemoar63@gmail.com>
> To: Andrew Morton <akpm@linux-foundation.org>
> To: Paul Walmsley <pjw@kernel.org>
> To: Palmer Dabbelt <palmer@dabbelt.com>
> To: Albert Ou <aou@eecs.berkeley.edu>
> To: Alexandre Ghiti <alex@ghiti.fr>
> To: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> To: Maxime Ripard <mripard@kernel.org>
> To: Thomas Zimmermann <tzimmermann@suse.de>
> To: David Airlie <airlied@gmail.com>
> To: Simona Vetter <simona@ffwll.ch>
> To: Jonathan Corbet <corbet@lwn.net>
> To: Shuah Khan <skhan@linuxfoundation.org>
> Cc: linux-kernel@vger.kernel.org
> Cc: linux-kselftest@vger.kernel.org
> Cc: kunit-dev@googlegroups.com
> Cc: linux-riscv@lists.infradead.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: workflows@vger.kernel.org
> Cc: linux-doc@vger.kernel.org
>
> ---
>
> ---
> Alessandro Carminati (1):
>       bug/kunit: Core support for suppressing warning backtraces
>
> Guenter Roeck (3):
>       kunit: Add backtrace suppression self-tests
>       drm: Suppress intentional warning backtraces in scaling unit tests
>       kunit: Add documentation for warning backtrace suppression API
>
>  Documentation/dev-tools/kunit/usage.rst |  46 +++++++-
>  drivers/gpu/drm/tests/drm_rect_test.c   |  36 +++++-
>  include/kunit/test-bug.h                |  26 +++++
>  include/kunit/test.h                    |  98 ++++++++++++++++
>  kernel/panic.c                          |  11 ++
>  lib/bug.c                               |  12 +-
>  lib/kunit/Makefile                      |   4 +-
>  lib/kunit/backtrace-suppression-test.c  | 192 ++++++++++++++++++++++++++++++++
>  lib/kunit/bug.c                         | 127 +++++++++++++++++++++
>  lib/kunit/hooks-impl.h                  |   2 +
>  10 files changed, 544 insertions(+), 10 deletions(-)
> ---
> base-commit: 74fe02ce122a6103f207d29fafc8b3a53de6abaf
> change-id: 20260312-kunit_add_support-2f35806b19dd
>
> Best regards,
> --
> Albert Esteve <aesteve@redhat.com>
>


^ permalink raw reply

* Re: [PATCH] arm64: tlb: Flush walk cache when unsharing PMD tables
From: David Hildenbrand (Arm) @ 2026-06-15 19:00 UTC (permalink / raw)
  To: Catalin Marinas, Zeng Heng
  Cc: will, akpm, npiggin, aneesh.kumar, peterz, linux-kernel,
	wangkefeng.wang, linux-arm-kernel, linux-mm, linux-arch,
	Paul Walmsley, Palmer Dabbelt, Albert Ou
In-Reply-To: <ag8fHYL-S26uO0yZ@arm.com>

On 5/21/26 17:05, Catalin Marinas wrote:
> + David H.
> 
> On Thu, May 21, 2026 at 03:30:11PM +0800, Zeng Heng wrote:
>> From: Zeng Heng <zengheng4@huawei.com>
>>
>> When huge_pmd_unshare() is called to unshare a PMD table, the
>> tlb_unshare_pmd_ptdesc() function sets tlb->unshared_tables=true
>> but the aarch64 tlb_flush() only checked tlb->freed_tables to
>> determine whether to use TLBF_NONE (vae1is, invalidates walk
>> cache) or TLBF_NOWALKCACHE (vale1is, leaf-only).
>>
>> This caused the stale PMD page table entry to remain in the walk cache
>> after unshare, potentially leading to incorrect page table walks.
>>
>> Fix by including unshared_tables in the check, so that when
>> unsharing tables, TLBF_NONE is used and the walk cache is properly
>> invalidated.
>>
>> Here is the detailed distinction between vae1is and vale1is:
>>
>> | Instruction Combination  | Actual Invalidation Scope                         |
>> | ------------------------ | --------------------------------------------------|
>> | `VAE1IS`  + TTL=`0`      | All entries at all levels (full invalidation)     |
>> | `VAE1IS`  + TTL=`2` (L2) | Non-leaf at Level 0/1 + leaf at Level 2           |
>> | `VALE1IS` + TTL=`0`      | Leaf entries at all levels (non-leaf not cleared) |
>> | `VALE1IS` + TTL=`2` (L2) | Leaf entry at Level 2 only                        |
>>
>> Signed-off-by: Zeng Heng <zengheng4@huawei.com>
> 
> The fix looks fine but does it need:

I'm late ... just stumbled over this in my inbox while digging though a pile.

> 
> Fixes: 8ce720d5bd91 ("mm/hugetlb: fix excessive IPI broadcasts when unsharing PMD tables using mmu_gather")
> Cc: <stable@vger.kernel.org>

Very likely, yes.

> 
>> ---
>>  arch/arm64/include/asm/tlb.h | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
>> index 10869d7731b8..751bd57bc3ba 100644
>> --- a/arch/arm64/include/asm/tlb.h
>> +++ b/arch/arm64/include/asm/tlb.h
>> @@ -53,7 +53,8 @@ static inline int tlb_get_level(struct mmu_gather *tlb)
>>  static inline void tlb_flush(struct mmu_gather *tlb)
>>  {
>>  	struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
>> -	tlbf_t flags = tlb->freed_tables ? TLBF_NONE : TLBF_NOWALKCACHE;
>> +	tlbf_t flags = (tlb->freed_tables || tlb->unshared_tables) ?
>> +			TLBF_NONE : TLBF_NOWALKCACHE;
>>  	unsigned long stride = tlb_get_unmap_size(tlb);
>>  	int tlb_level = tlb_get_level(tlb);
>>  

Right, the old code would have effectively called flush_tlb_range() ->
flush_tlb_mm_range() with freed_tables=true.

I recall that being a tricky bit. The commit documents that as:

    (1) tlb_remove_table_sync_one() is a NOP on architectures without
        CONFIG_MMU_GATHER_RCU_TABLE_FREE.

        Here, the assumption is that the previous TLB flush would send an
        IPI to all relevant CPUs. Careful: some architectures like x86 only
        send IPIs to all relevant CPUs when tlb->freed_tables is set.

        The relevant architectures should be selecting
        MMU_GATHER_RCU_TABLE_FREE, but x86 might not do that in stable
        kernels and it might have been problematic before this patch.

        Also, the arch flushing behavior (independent of IPIs) is different
        when tlb->freed_tables is set. Do we have to enlighten them to also
        take care of tlb->unshared_tables? So far we didn't care, so
        hopefully we are fine. Of course, we could be setting
        tlb->freed_tables as well, but that might then unnecessarily flush
        too much, because the semantics of tlb->freed_tables are a bit
        fuzzy.


Turns out I was thinking too much in terms of optimizing IPIs.

Besides arm64 and x86, powerpc and riscv also rely on "tlb->freed_tables"
in tlb_flush(). But only arm64, x86 and riscv support ARCH_WANT_HUGE_PMD_SHARE.

Which makes me wonder whether we also need:


diff --git a/arch/riscv/include/asm/tlb.h b/arch/riscv/include/asm/tlb.h
index 50b63b5c15bd..17c551322b5d 100644
--- a/arch/riscv/include/asm/tlb.h
+++ b/arch/riscv/include/asm/tlb.h
@@ -16,7 +16,8 @@ static void tlb_flush(struct mmu_gather *tlb);
 static inline void tlb_flush(struct mmu_gather *tlb)
 {
 #ifdef CONFIG_MMU
-       if (tlb->fullmm || tlb->need_flush_all || tlb->freed_tables)
+       if (tlb->fullmm || tlb->need_flush_all || tlb->freed_tables ||
+           tlb->unshared_tables)
                flush_tlb_mm(tlb->mm);
        else
                flush_tlb_mm_range(tlb->mm, tlb->start, tlb->end,

CCing riscv maintainers.

-- 
Cheers,

David

^ permalink raw reply related

* Re: [PATCH v12 07/15] atomic: Add atomic_cond_read_*_timeout()
From: Ankur Arora @ 2026-06-15  7:41 UTC (permalink / raw)
  To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
  Cc: Ankur Arora, bpf, arnd, catalin.marinas, will, peterz, akpm,
	mark.rutland, harisokn, cl, ast, rafael, daniel.lezcano, memxor,
	zhenglifeng1, xueshuai, rdunlap, david.laight.linux, broonie,
	joao.m.martins, boris.ostrovsky, konrad.wilk, ashok.bhat,
	Ankur Arora, Boqun Feng, sashiko-bot
In-Reply-To: <20260608082304.ADEA61F00893@smtp.kernel.org>


sashiko-bot@kernel.org writes:

> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] The `atomic64_cond_read_acquire_timeout` and `atomic64_cond_read_relaxed_timeout` macros can cause torn reads and synchronization failures on 32-bit architectures.
> --
>
> commit aafb3af0335d368d82aaca86bf6b2a18f8ae6033
> Author: Ankur Arora <ankur.a.arora@oracle.com>
>
> atomic: Add atomic_cond_read_*_timeout()
>
> Add atomic load wrappers, atomic_cond_read_*_timeout() and
> atomic64_cond_read_*_timeout() for the cond-load timeout interfaces. Also
> add a short description for the interfaces.
>
>> diff --git a/include/linux/atomic.h b/include/linux/atomic.h
>> index 8dd57c3a99e9b..5bcb86e077845 100644
>> --- a/include/linux/atomic.h
>> +++ b/include/linux/atomic.h
>
> [ ... ]
>
>> @@ -31,6 +31,16 @@
>>  #define atomic64_cond_read_acquire(v, c) smp_cond_load_acquire(&(v)->counter, (c))
>>  #define atomic64_cond_read_relaxed(v, c) smp_cond_load_relaxed(&(v)->counter, (c))
>>
>> +#define atomic_cond_read_acquire_timeout(v, c, e, t) \
>> +	smp_cond_load_acquire_timeout(&(v)->counter, (c), (e), (t))
>> +#define atomic_cond_read_relaxed_timeout(v, c, e, t) \
>> +	smp_cond_load_relaxed_timeout(&(v)->counter, (c), (e), (t))
>> +
>> +#define atomic64_cond_read_acquire_timeout(v, c, e, t) \
>> +	smp_cond_load_acquire_timeout(&(v)->counter, (c), (e), (t))
>> +#define atomic64_cond_read_relaxed_timeout(v, c, e, t) \
>> +	smp_cond_load_relaxed_timeout(&(v)->counter, (c), (e), (t))
>
> [Severity: High]
> Will this cause torn reads and synchronization failures on 32-bit
> architectures?
>
> On 32-bit platforms, atomic64_t operations typically rely on spinlocks or
> specific instructions to prevent tearing. These new macros bypass the
> architecture-specific atomic64_read() and directly use
> smp_cond_load_acquire_timeout() and smp_cond_load_relaxed_timeout() on the
> counter member.
>
> These macros poll using a lockless READ_ONCE(). On 32-bit systems, a 64-bit
> READ_ONCE() compiles into two separate 32-bit memory loads. If concurrent
> writers modify the counter via spinlocked atomic64 operations, the lockless
> polling loop could observe torn (partially updated) reads.


So, yes 32bit would run into torn reads but it shouldn't really be using
atomic64_cond_* interfaces.

Those interfaces are typically used via atomic_long_cond -- which should
be using atomic64_cond_* only if CONFIG_64BIT is defined.

Ankur

> If a torn read spuriously satisfies the polling condition, the loop might exit
> prematurely with a corrupt value.

^ permalink raw reply

* Re: [PATCH v12 06/15] asm-generic: barrier: Add smp_cond_load_acquire_timeout()
From: Ankur Arora @ 2026-06-15  7:32 UTC (permalink / raw)
  To: linux-kernel, linux-arch, linux-arm-kernel, linux-pm, bpf
  Cc: arnd, catalin.marinas, will, peterz, akpm, mark.rutland, harisokn,
	cl, ast, rafael, daniel.lezcano, memxor, zhenglifeng1, xueshuai,
	rdunlap, david.laight.linux, broonie, joao.m.martins,
	boris.ostrovsky, konrad.wilk, ashok.bhat, sashiko-bot
In-Reply-To: <20260608082746.399BB1F00898@smtp.kernel.org>


sashiko-bot@kernel.org writes:

> Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
> - [High] ACQUIRE semantics violation in `smp_cond_load_acquire_timeout()` on weakly-ordered architectures.
> --
>
> commit 0c67207964772b92d28f5af7e4a97ea44a103e9b
> Author: Ankur Arora <ankur.a.arora@oracle.com>
>
> asm-generic: barrier: Add smp_cond_load_acquire_timeout()
>
> This commit adds the acquire variant of smp_cond_load_relaxed_timeout().
> It attempts to provide acquire ordering by reusing the relaxed variant and
> adding a control dependency combined with smp_acquire__after_ctrl_dep().
>
>> diff --git a/include/asm-generic/barrier.h b/include/asm-generic/barrier.h
>> index c56df9513a084..0ab26e98842c0 100644
>> --- a/include/asm-generic/barrier.h
>> +++ b/include/asm-generic/barrier.h
>
> [ ... ]
>
>> +/**
>> + * smp_cond_load_acquire_timeout() - (Spin) wait for cond with ACQUIRE ordering
>> + * until a timeout expires.
>> + * @ptr: pointer to the variable to wait on.
>> + * @cond_expr: boolean expression to wait for.
>> + * @time_expr_ns: monotonic expression that evaluates to time in ns or,
>> + *  on failure, returns a negative value.
>> + * @timeout_ns: timeout value in ns
>> + * (Both of the above are assumed to be compatible with s64.)
>> + *
>> + * Equivalent to using smp_cond_load_acquire() on the condition variable with
>> + * a timeout.
>> + */
>> +#ifndef smp_cond_load_acquire_timeout
>> +#define smp_cond_load_acquire_timeout(ptr, cond_expr,			\
>> +				      time_expr_ns, timeout_ns)		\
>> +({									\
>> +	__unqual_scalar_typeof(*(ptr)) VAL;				\
>> +	VAL = smp_cond_load_relaxed_timeout(ptr, cond_expr,		\
>> +					     time_expr_ns,		\
>> +					     timeout_ns);		\
>> +	if (cond_expr)							\
>> +		barrier();						\
>> +	smp_acquire__after_ctrl_dep();					\
>
> [Severity: High]
> Does this sequence correctly establish a control dependency for the caller's
> subsequent instructions?
>
> According to Documentation/memory-barriers.txt, control dependencies only
> apply to stores executed strictly within the conditional clauses (the true
> or false branches), not to code following the if statement. Since the
> caller's subsequent stores reside outside this conditional block, they
> appear unconditional to the CPU.

Yes, this is a problem. One way to fix this would be to add a full
acquire barrier in the failure path:

	VAL = smp_cond_load_relaxed_timeout(ptr, cond_expr,
					     time_expr_ns,
					     timeout_ns);
	if (!cond_expr)
		VAL = smp_load_acquire();
	else
                smp_acquire__after_ctrl_dep();
        (typeof(*(ptr)))VAL;

However, this seems like overkill since there are likely few situations
where we need an acquire barrier on the failure path.

AFAICT rqspinlock doesn't seem to need one.

Unless someone has an objection that's what I plan to do.

Ankur

> Furthermore, smp_acquire__after_ctrl_dep() typically falls back to
> smp_rmb(). On weakly-ordered architectures like RISC-V, where smp_rmb() is
> implemented as "fence r, r" and only enforces load-to-load ordering, could
> the CPU speculatively execute subsequent stores before the final load of VAL
> completes?
>
> Could this violate the expected acquire semantics if the caller relies on
> the barrier in the timeout or failure path?
>
>> +	(typeof(*(ptr)))VAL;						\
>> +})
>> +#endif


--
ankur

^ permalink raw reply

* Re: [PATCH] init/main: Expose built-in initcalls and blacklist status via debugfs
From: Aaron Tomlin @ 2026-06-13 21:05 UTC (permalink / raw)
  To: arnd, mcgrof, petr.pavlu, da.gomez, samitolvanen
  Cc: neelx, kees, peterz, akpm, sean, chjohnst, steve, mproche,
	nick.lane, linux-arch, linux-modules, linux-kernel
In-Reply-To: <20260510061301.41341-1-atomlin@atomlin.com>

[-- Attachment #1: Type: text/plain, Size: 1388 bytes --]

On Sun, May 10, 2026 at 02:13:01AM -0400, Aaron Tomlin wrote:
> At present, identifying the correct function name to supply to the
> "initcall_blacklist=" kernel command-line parameter requires manual
> inspection of the source code or kernel symbol tables. Furthermore,
> administrators lack a reliable runtime mechanism to verify whether a
> specified built-in module has been successfully blacklisted.
> 
> To resolve this, introduce a new debugfs interface at
> /sys/kernel/debug/modules/builtin_initcalls. This file enumerates all
> built-in modules alongside their corresponding initialisation callbacks
> (e.g., those specified by module_init()) in a simple format:
> "module_name init_callback". If a built-in module has been actively
> blacklisted, the entry is explicitly appended with a " [blacklisted]"
> suffix.

Dear maintainers,

I am writing to politely follow up on this patch, as it has been just over
a month since its initial submission.

To briefly reiterate, this patch introduces a reliable runtime mechanism to
identify built-in initcalls and verify their blacklisted status, thereby
significantly improving the usability of the "initcall_blacklist="
parameter.

I would be most grateful for any feedback, or to know whether any further
refinements are required for it to be considered for inclusion.

Kind regards,
-- 
Aaron Tomlin

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* Re: [PATCH bpf-next] rqspinlock: Fix order in raw_res_spin_(un)lock_irq to allow schedule
From: patchwork-bot+netdevbpf @ 2026-06-13  3:40 UTC (permalink / raw)
  To: Gabriele Monaco
  Cc: ast, daniel, andrii, eddyz87, memxor, arnd, bpf, linux-arch,
	linux-kernel, stable, longman
In-Reply-To: <20260610090431.32427-1-gmonaco@redhat.com>

Hello:

This patch was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Wed, 10 Jun 2026 11:04:29 +0200 you wrote:
> raw_res_spin_unlock_irqrestore() calls raw_res_spin_unlock() and then
> restores interrupts, this means preemption is enabled when interrupts
> are still disabled (as part of raw_res_spin_unlock()) so this cannot
> trigger an actual preemption.
> This is inconsistent with other spinlock implementations
> (raw_spin_unlock_irqrestore() and bpf_res_spin_unlock_irqrestore()
> itself).
> 
> [...]

Here is the summary with links:
  - [bpf-next] rqspinlock: Fix order in raw_res_spin_(un)lock_irq to allow schedule
    https://git.kernel.org/bpf/bpf-next/c/b48bd16eb9fc

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply

* [PATCH v2] audit: add missing syscalls to PERM class tables
From: Ricardo Robaina @ 2026-06-12 14:14 UTC (permalink / raw)
  To: audit, linux-kernel, linux-arch
  Cc: paul, eparis, arnd, sgrubb, Ricardo Robaina

Add missing file metadata syscalls to the audit PERM class tables,
addressing gaps where certain file operations were not properly
classified for audit rule matching.

Changes:
- audit_change_attr.h: Add file_setattr

- audit_read.h: Add quotactl_fd, file_getattr, stat, stat64, lstat,
  lstat64, fstat, fstat64, newfstatat, fstatat64, and statx

- audit_write.h: Add quotactl_fd

Architecture-specific and conditionally-compiled syscalls are guarded
with #ifdef.

Signed-off-by: Steve Grubb <sgrubb@redhat.com>
Signed-off-by: Ricardo Robaina <rrobaina@redhat.com>
---
Changes in v2:
- Added stat64 family syscalls (stat64, lstat64, fstat64, fstatat64) to
  audit_read.h for 32-bit architecture support.
- Dropped timestamp-related syscalls (utime, utimes, utimensat, etc.)
  due to potential audit log volume increase impact. Those will be
  addressed in a separate patch after closer investigation.

 include/asm-generic/audit_change_attr.h |  3 +++
 include/asm-generic/audit_read.h        | 31 +++++++++++++++++++++++++
 include/asm-generic/audit_write.h       |  3 +++
 3 files changed, 37 insertions(+)

diff --git a/include/asm-generic/audit_change_attr.h b/include/asm-generic/audit_change_attr.h
index ddd90bbe40df..94388da3490c 100644
--- a/include/asm-generic/audit_change_attr.h
+++ b/include/asm-generic/audit_change_attr.h
@@ -40,3 +40,6 @@ __NR_link,
 #ifdef __NR_linkat
 __NR_linkat,
 #endif
+#ifdef __NR_file_setattr
+__NR_file_setattr,
+#endif
diff --git a/include/asm-generic/audit_read.h b/include/asm-generic/audit_read.h
index fb9991f53fb6..d8dc3dd6bf63 100644
--- a/include/asm-generic/audit_read.h
+++ b/include/asm-generic/audit_read.h
@@ -3,6 +3,9 @@
 __NR_readlink,
 #endif
 __NR_quotactl,
+#ifdef __NR_quotactl_fd
+__NR_quotactl_fd,
+#endif
 __NR_listxattr,
 #ifdef __NR_listxattrat
 __NR_listxattrat,
@@ -18,3 +21,31 @@ __NR_fgetxattr,
 #ifdef __NR_readlinkat
 __NR_readlinkat,
 #endif
+#ifdef __NR_file_getattr
+__NR_file_getattr,
+#endif
+#ifdef __NR_stat
+__NR_stat,
+#endif
+#ifdef __NR_stat64
+__NR_stat64,
+#endif
+#ifdef __NR_lstat
+__NR_lstat,
+#endif
+#ifdef __NR_lstat64
+__NR_lstat64,
+#endif
+#ifdef __NR_fstat
+__NR_fstat,
+#endif
+#ifdef __NR_fstat64
+__NR_fstat64,
+#endif
+#ifdef __NR_newfstatat
+__NR_newfstatat,
+#endif
+#ifdef __NR_fstatat64
+__NR_fstatat64,
+#endif
+__NR_statx,
diff --git a/include/asm-generic/audit_write.h b/include/asm-generic/audit_write.h
index f9f1d0ae11d9..378128dc31e3 100644
--- a/include/asm-generic/audit_write.h
+++ b/include/asm-generic/audit_write.h
@@ -5,6 +5,9 @@ __NR_acct,
 __NR_swapon,
 #endif
 __NR_quotactl,
+#ifdef __NR_quotactl_fd
+__NR_quotactl_fd,
+#endif
 #ifdef __NR_truncate
 __NR_truncate,
 #endif
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH] audit: add missing syscalls to PERM class tables
From: kernel test robot @ 2026-06-12  1:20 UTC (permalink / raw)
  To: Ricardo Robaina, audit, linux-kernel, linux-arch
  Cc: oe-kbuild-all, paul, eparis, arnd, sgrubb, Ricardo Robaina
In-Reply-To: <20260610164719.2668906-1-rrobaina@redhat.com>

Hi Ricardo,

kernel test robot noticed the following build errors:

[auto build test ERROR on pcmoore-audit/next]
[also build test ERROR on linus/master v7.1-rc7 next-20260610]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Ricardo-Robaina/audit-add-missing-syscalls-to-PERM-class-tables/20260611-024240
base:   https://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/audit.git next
patch link:    https://lore.kernel.org/r/20260610164719.2668906-1-rrobaina%40redhat.com
patch subject: [PATCH] audit: add missing syscalls to PERM class tables
config: riscv-randconfig-001-20260611 (https://download.01.org/0day-ci/archive/20260612/202606120946.0eNy5YXB-lkp@intel.com/config)
compiler: riscv32-linux-gcc (GCC) 8.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260612/202606120946.0eNy5YXB-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202606120946.0eNy5YXB-lkp@intel.com/

All errors (new ones prefixed by >>):

   In file included from lib/audit.c:23:
>> include/asm-generic/audit_change_attr.h:52:1: error: '__NR_utimensat' undeclared here (not in a function); did you mean 'vfs_utimes'?
    __NR_utimensat,
    ^~~~~~~~~~~~~~
    vfs_utimes


vim +52 include/asm-generic/audit_change_attr.h

  > 52	__NR_utimensat,

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH] vfs: missing inode operation should return a consistent error code
From: Jori Koolstra @ 2026-06-11 20:31 UTC (permalink / raw)
  To: Jan Kara, Christian Brauner
  Cc: Jeff Layton, Alexander Viro, Arnd Bergmann,
	open list:FILESYSTEMS (VFS and infrastructure), open list,
	open list:GENERIC INCLUDE/ASM HEADER FILES
In-Reply-To: <m5fqzr2ny4zb36u6zhmrrxgl36ycsxvlqnzf5idvsq4lxpfh3i@g276qtqgfv3f>

@Christian, since you suggested equalizing the error codes for missing
inode ops, what is your opinion?

> Op 01-06-2026 18:50 CEST schreef Jan Kara <jack@suse.cz>:
> 
> We certainly can (and sometimes do) modify the returned errors. It is
> always just a balancing act between the benefit of the change and chances
> somebody will get broken by it. In this case I don't quite see the
> benefit, not that I'd be too worried about the a regression but there's
> always the chance...
> 
> 								Honza

No, I get that, and maybe you are right. I feel in this case it would be
really odd if this breaks anyone's application. It would mean you are
rigorously testing for receiving specific error codes, without handling
a general error case. That just seems odd, especially since some of these
error codes are not even listed as a possibility for missing ops (like EACCES).
I would say we change this and revert if anyone complains. I believe that was
also Christian's view in another thread, but I may be mistaken.

But regardless, it's just a nice to have, and I can definitely live without.
It is just a clean-up I came across while working on O_CREAT|O_DIRECTORY.

Best,
Jori.

^ permalink raw reply

* Re: [RFC PATCH v1 00/13] exec: add spawn templates for repeated executable startup
From: John Ericson @ 2026-06-11 18:53 UTC (permalink / raw)
  To: Mateusz Guzik, Li Chen
  Cc: Andy Lutomirski, Christian Brauner, Kees Cook, Al Viro,
	linux-fsdevel, linux-api, LKML, linux-mm, linux-arch, linux-doc,
	linux-kselftest, x86, Arnd Bergmann, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, H. Peter Anvin, Jan Kara,
	Jonathan Corbet, Shuah Khan
In-Reply-To: <hd3i6pxxohsjesyid7nhuic6ppp6nyoxxpwa4mny6riqvpyqec@mylfprni2yaw>

On Wed, Jun 10, 2026, at 7:40 PM, Mateusz Guzik wrote:
> [...]
>
> As I tried to explain in my previous e-mail this approach does not cut
> it because of NUMA.
>
> Suppose you have a machine with 2 nodes. The parent-to-be is running
> on node 0 and the child is intended to exec something on node 1.
>
> When the parent-to-be allocates and populates stuff, it takes place with
> memory backed by node 0. If you allocate task_struct, the file table and
> other frequently used (and modified!) objs in this way, you are
> guaranteeing performance loss due to interconnect traffic to access it.
>
> Trying to add plumbing so that all allocations respect numa placement is
> probably too cumbersome.

Are we sure that last part is true?

Let's also assume when this stuff was initially implemented, we didn't
have it. If the basic thrust of this work is to replace functions that
previously only worked on the current thread with those that worked on
either arbitrary (not yet started) threads or the current thread, would
that not prepare us for slowly migrating the allocation choice to
reflect the node of the target task (new parameter) rather than the node
of the current task over time?

(This assumes the task is pre-placed on a node before it is actually run
there, and that pre-placement happens as early in the allocation process
as possible, so subsequent allocations can read off the
partially-initialized task's node.)

"Slowly migrating" is good here! It doesn't need to be the fastest thing
out of the gate, but if this new proper spawning API gets popular as I
think it would, and there is a clear path to optimizing it per the
above, then I am confident that over the years it will happen.

> The primary example for that is looking up the binary to exec in the
> first place.
>
> userspace likes to pass paths which don't exist, meaning checking for
> the binary before any hard work is a useful optimization. Suppose the
> binary to be executed is in a container bound with a taskset using
> node 1 and the content of the fs part of the container is currently
> fully uncached.
>
> When you perform the lookup on node 0, you are populating a bunch of
> metadata (inode, dentry) using memory from that domain. But the intended
> user will only execute on node 1, again resulting in a performance loss.
>
> In order to not do it you would need to convince VFS to allocate memory
> elsewhere.

One thing I don't get about this is that isn't the cost doing a bunch of
work searching the PATH for the directories where the executable
*doesn't* exist? In the case of something like a shell that is going to
spawn a lot of processes, I would think it is *good* to keep all that
PATH crawling VFS filling to be on the shell's node, rather than the
child processes' nodes.

It is only the executable itself, the final step of the VFS crawl, that
should be loaded into the other NUMA nodes. Insofar as (unless I am
missing something) creating the process means finding the inode for the
executable but not loading those pages, aren't we OK here? Only when the
new process is actually scheduled and run must the ELF be paged into
memory, and then that will happen on the correct node.

> So I stand by my previous claim that ultimately a pristine child has to
> be created (like in this patch), but which also has to do the work on
> its own.

I have not been a kernel dev, so my apologies if I am missing things.
But in conclusion for me, the FS and other resource access patterns of
*creating a process* vs *that process itself running* do not seem
necessarily coincident to me. What you are describing as for sure a
problem might possibly be a *good thing*, if they are in fact quite
different.

> Suppose there is no explicit placement requested anywhere. Even in that
> case there are legitimate workloads which will eventually be forced to
> exec stuff on another node. Even these have a better chance retaining
> full locality if the child process does all the work.
>
> Per my previous message I don't see a clean interface to do it.
> something quasi-posix_spawn is probably the least bad way out, it will
> also allow userspace to easily wrap the new thing with posix_spawn
> itself.
>
> Also note there is another issue with the fd-based approach: the fd will
> get inherited on fork and will hang out in the child afterwards unless
> explicitly closed. Suppose you have a multithreaded program which likes
> to both fork(+no exec) and fork+exec. With the fd-based approach you
> have no means of stopping another thread from grabbing your state thanks
> to unix defaulting to copying everything. There was an attempt to fix
> this aspect with O_CLOFORK, but this got rejected.

I would think we don't need to worry about clone/fork very much, right?
I think the premise of your emails, and just about everyone else's in
this thread too, is that we agree fork+exec is bad, and the problem of
unnecessarily sharing resources is inherent to fork. Furthermore, I
think we all agree that while `O_CLOEXEC` and `O_CLOFORK` may help, both
are unsatisfying solutions because they are opt-out not opt-in, and
global to the parent process / preexec state (respectively) rather than
local to the specific fork / exec in question.

pidfds encounter these problems no more than any other
file-descriptor-based UAPI, right? And I don't think it is good to blame
any such file-descriptor-based UAPI when fork/exec are at fault.

Maybe during the transition, when some things use fork and some things
use this new API, stuff will be awkward, but I would rather that just be
an incentive to complete the transition away from fork, not a reason to
second-guess the plan.

Once the transition is complete, and everyone is diligently assembling
their child processes from scratch as is proposed, `O_CLOEXEC` and
`O_CLOFORK` are both unneeded, and oversharing privileges will be much
less common simply because "lazy coding"/"minimal typing" will only
share what is needed --- anything else is more code/keystrokes!

> Whatever exactly happens, NUMA is a sad fact of computing and needs to
> be accounted for. The approach as proposed not only does not do it, but
> it actively hinders such deployments.

Despite everything I said, I want to be clear that I do agree that NUMA
performance should be accounted for. Even if the first version isn't as
great as it could be on that metric, there should be a clear plan for
how future work can conclusively address it.

Cheers,

John

^ permalink raw reply

* Re: [PATCH v6 5/7] locking: Add contended_release tracepoint to qspinlock
From: Peter Zijlstra @ 2026-06-11 13:44 UTC (permalink / raw)
  To: Dmitry Ilvokhin
  Cc: Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long,
	Thomas Bogendoerfer, Juergen Gross, Ajay Kaher, Alexey Makhalov,
	Broadcom internal kernel review list, Thomas Gleixner,
	Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Arnd Bergmann,
	Dennis Zhou, Tejun Heo, Christoph Lameter, Steven Rostedt,
	Masami Hiramatsu, Mathieu Desnoyers, linux-kernel, linux-mips,
	virtualization, linux-arch, linux-mm, linux-trace-kernel,
	kernel-team, Paul E. McKenney
In-Reply-To: <aiphFXe_TPNPxZ_n@shell.ilvokhin.com>

On Thu, Jun 11, 2026 at 07:17:41AM +0000, Dmitry Ilvokhin wrote:
> On Wed, Jun 03, 2026 at 02:08:11PM +0200, Peter Zijlstra wrote:
> > Also, I think someone should go do some performance runs with
> > ARCH_INLINE_SPIN_* set for x86 just like for s390.
> 
> As promised, I set ARCH_INLINE_SPIN_UNLOCK{,_BH,_IRQ,_IRQRESTORE} for
> x86 and measured the effect on a few real workloads.
> 
> Short version: inlining of _raw_spin_unlock() adds measurable kernel
> i-cache pressure on every workload I tried, and on a
> kernel-i-cache-bound one (nginx connection churn) it costs ~1.27%
> throughput. I did not find a workload where it helps.

Thanks for checking!

^ permalink raw reply

* Re: [PATCH v4 6/8] string: introduce memcpy_streaming() helpers
From: Li Zhe @ 2026-06-11  9:38 UTC (permalink / raw)
  To: bp
  Cc: akpm, apopple, arnd, dave.hansen, david, kees, linux-arch,
	linux-hardening, linux-kernel, linux-mm, lizhe.67, mingo, rppt,
	tglx, x86
In-Reply-To: <20260610191920.GBaim4uMX3z6OqJwHr@fat_crate.local>

On Wed, Jun 10, 2026 at 12:19:20 -0700, bp@alien8.de wrote:

> On Tue, Jun 09, 2026 at 08:01:32PM +0800, Li Zhe wrote:
> > That said, I see your layering point. If arch/x86/include/asm/string.h
> > is the preferred place for the arch-visible wrapper, I can move the
> > wrapper there in the next revision while keeping the x86_64-specific
> > implementation details in string_64.h.
> 
> No, 64-bit only's fine. We don't put any new features into 32-bit already
> anyway but that wasn't clear from the commit message what your goal is.

Thanks, that makes sense.

> > Thinking about it more, I agree that this is hard to justify for a
> > generic helper. For this series, what really matters is that the
> > struct page copies in patch 8 can use the existing x86
> > memcpy_flushcache() fastpaths where that is beneficial; I do not need
> > patch 6 to impose extra selection policy on unrelated callers.
> 
> What I am asking is, you need to show numbers why those helpers exist.
> 
> Your 0th message is talking about measuring this in VMs. If this workload is
> not VM-specific, then those numbers don't matter. They're just handwaving.
> 
> So I'd need a good justification why we need the changes before we go any
> further.

Understood.

I do not currently have access to physical PMEM hardware on my side, so
the numbers I posted so far were all from a VM-based setup. I agree that
this is not sufficient justification for introducing the helper / x86 nt
part of the series.

For the next resend, I will first split out and resend the mm-only
subset, and drop the helper / x86 nt part for now.

If anyone  has access to real PMEM hardware and is willing to test
whether that part shows a measurable benefit there, I would greatly
appreciate it.

Otherwise, is there a preferred way to justify or validate that part
without physical PMEM measurements, or is the right approach simply to
keep it out of the series until such data is available?

Thanks,
Zhe

^ permalink raw reply

* Re: [PATCH v6 5/7] locking: Add contended_release tracepoint to qspinlock
From: Dmitry Ilvokhin @ 2026-06-11  7:17 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Ingo Molnar, Will Deacon, Boqun Feng, Waiman Long,
	Thomas Bogendoerfer, Juergen Gross, Ajay Kaher, Alexey Makhalov,
	Broadcom internal kernel review list, Thomas Gleixner,
	Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Arnd Bergmann,
	Dennis Zhou, Tejun Heo, Christoph Lameter, Steven Rostedt,
	Masami Hiramatsu, Mathieu Desnoyers, linux-kernel, linux-mips,
	virtualization, linux-arch, linux-mm, linux-trace-kernel,
	kernel-team, Paul E. McKenney
In-Reply-To: <20260603120811.GW3493090@noisy.programming.kicks-ass.net>

On Wed, Jun 03, 2026 at 02:08:11PM +0200, Peter Zijlstra wrote:
> Also, I think someone should go do some performance runs with
> ARCH_INLINE_SPIN_* set for x86 just like for s390.

As promised, I set ARCH_INLINE_SPIN_UNLOCK{,_BH,_IRQ,_IRQRESTORE} for
x86 and measured the effect on a few real workloads.

Short version: inlining of _raw_spin_unlock() adds measurable kernel
i-cache pressure on every workload I tried, and on a
kernel-i-cache-bound one (nginx connection churn) it costs ~1.27%
throughput. I did not find a workload where it helps.

HOW BENCHMARKS WERE CHOSEN

The cost of inlining unlock is text footprint increase. Every unlock
site grows, and the extra bytes compete for the shared L1i. The bill is
paid by unrelated code, in both kernel and userspace.

Locktorture and similar microbenchmarks can't see this, because they
usually hammer a tiny loop that stays L1i-resident, so they measure
fast-path cycles, where inlining (fewer instructions per unlock) looks
neutral-to-good.

To make the cost visible, the workload has to have real instruction
cache pressure. To achieve that, it has to touch a lot of code.

A good way to screen benchmarks: look for high tma_frontend_bound
fraction from 'perf stat -M TopdownL1' and simultaneously require it to
spend non-trivial time in the kernel (be syscall-heavy).

SETUP

Hardware: 2x Intel Xeon Gold 6138 (Skylake-SP), 20 cores/socket, 40C/80T
with kernel built from locking/core branch. Baseline _raw_spin_unlock()
is out-of-line via UNINLINE_SPIN_UNLOCK=y. Experiment adds the four
selects above (exact patch is at the end of this message). Cache
geometry (lscpu -C):

NAME ONE-SIZE ALL-SIZE WAYS TYPE        LEVEL  SETS PHY-LINE COHERENCY-SIZE
L1d       32K     1.3M    8 Data            1    64        1             64
L1i       32K     1.3M    8 Instruction     1    64        1             64
L2         1M      40M   16 Unified         2  1024        1             64
L3      27.5M      55M   11 Unified         3 40960        1             64

Per run I collected cycles, instructions and L1i-misses. To stay within
the available PMU counters, each run used only 3 events: cycles,
instructions and one L1i filter (:u or :k). The NMI watchdog was off and
every run reported 100% counter enablement (no multiplexing). Userspace
and kernel misses therefore come from separate runs. Each benchmark was
run 20x per side: 10 with the :u counter, 10 with :k.  Cycles,
instructions and throughput are pooled across all 20, each L1i split
comes from its 10.

KERNEL IMAGE SIZE

To give a sense of the code-footprint increase, scripts/bloat-o-meter on
vmlinux, GCC 11, x86_64, defconfig + CONFIG_PARAVIRT_SPINLOCKS=y:

    Total: Before=23838694, After=23977159, chg +0.58%

ROCKSDB (DELETESEQ)

    db_bench -benchmarks=deleteseq

Metric                       Baseline      Experiment     Delta   Sig
----------------------------------------------------------------------
Instructions (total)    9,574,476,543   9,573,602,441    -0.01%   flat
L1i-miss :k (kernel)      198,588,165     216,672,536    +9.11%   **
L1i-miss :u (userspace)   593,276,235     616,433,813    +3.90%   **
Throughput ops/s            431,398         432,897      +0.35%   ns
Cycles (total)          4,681,002,302   4,665,106,876    -0.34%   ns
IPC                          2.045           2.052       +0.33%   ns
Time elapsed (s)            2.4012          2.3865       -0.62%   ns
----------------------------------------------------------------------
L1i-miss: higher = worse. Throughput: higher = better.
** = beyond per-run noise (+-0.1..0.36%), ns = within noise.

At constant instructions, inlining raises L1i misses +9.11% (kernel) and
+3.90% (userspace), both well beyond noise. Throughput, cycles, IPC and
wall-time all stay within run-to-run noise. So the i-cache cost is real,
but at IPC ~2 db_bench isn't fetch-bound at the app level, so it doesn't
surface.

No benefit from _raw_spin_unlock() inlining.

KERNEL BUILD

Building locking/core (defconfig), GCC 11.

    make -j80

Metric              Baseline      Experiment     Delta   Sig
-------------------------------------------------------------
L1i-miss :k          36.72G        37.51G       +2.16%   **
L1i-miss :u         246.99G       246.06G       -0.38%   **
Sys (s)             478.250       482.420       +0.87%   **
Time elapsed (s)    105.221       105.373       +0.14%   ns
User (s)           4022.046      4024.012       +0.05%   flat
Cycles            8,894.10G     8,902.12G       +0.09%   flat
Instructions      8,424.28G     8,426.48G       +0.03%   flat
IPC                   0.947         0.947       -0.06%   flat
-------------------------------------------------------------
L1i-miss/Sys: higher = worse.
** = beyond per-run noise, ns = within noise.

Kernel i-cache misses (+2.16%) and sys time (+0.87%) both rise and are
significant. Wall-time and userspace L1i are flat. Kernel build is
GCC/userspace-bound (User 4022s vs Sys 478s), so the added kernel fetch
cost is real but appears to sit off the critical path.

No benefit from _raw_spin_unlock() inlining.

NGINX

I ran nginx with taskset -c 2.

    perf stat -C 2 ... -- ab -n 100000 -c 80 http://127.0.0.1:8080/

Config for nginx was the following.

  worker_processes 1;
  error_log /tmp/ngx/error.log;
  pid       /tmp/ngx/nginx.pid;
  events { worker_connections 16384; }
  http {
      access_log off;
      server { listen 8080 reuseport; location / { return 200 "ok\n"; } }
  }


I used nginx version 1.20.1 (prebuilt, from CentOS repo).

Metric              Baseline      Experiment     Delta   Sig
------------------------------------------------------------
req/s (ab)           25,113        24,795       -1.27%   **
L1i MPKI :k          70.06         72.10        +2.92%   **
L1i MPKI :u          20.16         20.66        +2.50%   **
instructions          5.86G         5.83G       -0.50%   **
L1i-miss :k           0.41G         0.42G       +2.44%   **
L1i-miss :u           0.12G         0.12G       +1.95%   **
cycles                4.82G         4.81G       -0.28%   ns
IPC                   1.215         1.213       -0.22%   ns
perf time (s)         4.077         4.129       +1.26%   **
failed reqs              0             0          -      valid
------------------------------------------------------------
req/s: higher=better. MPKI: higher=worse.
** = beyond per-run noise, ns = within noise.

nginx connection-churn is the one workload that is genuinely
kernel-fetch-bound: MPKI:k ~70 and IPC ~1.2 (vs db_bench's 2.05). Here
the cost surfaces: req/s −1.27%. Misses rise in both domains (+2.9%
MPKI:k, +2.5% MPKI:u). Unlike kernel build, userspace is hit too,
because nginx runs user and kernel hot on the same core and the kernel
bloat pollutes the shared L1i.

And the kicker: instructions fell 0.5% (inlining removed the call/ret)
yet throughput dropped.

Caveat: ab is single-threaded, so it seems the worker core is
under-saturated: cycles is flat (−0.28%, ns) while wall-time rose
(+1.26%).

Measurable throughput regression from _raw_spin_unlock() inlining.

CONCLUSION

Inlining _raw_spin_unlock() raises kernel L1i misses on every workload.
It's an unconditional cost. Whether it costs the application throughput
depends on how kernel-fetch-bound the workload is.
  
The cost is real everywhere. It only surfaces as throughput regression
where the kernel is on the fetch critical path. And inlining did not
help in any workload I measured. The one micro-effect inlining produced
(-0.5% instructions on nginx) was erased by the added i-cache pressure.


From 99502328caed3c195e20cf194a1e8aa1563f3896 Mon Sep 17 00:00:00 2001
From: Dmitry Ilvokhin <d@ilvokhin.com>
Date: Thu, 4 Jun 2026 07:43:00 -0700
Subject: [PATCH] x86/locking: Inline the spin_unlock()

Signed-off-by: Dmitry Ilvokhin <d@ilvokhin.com>
---
 arch/x86/Kconfig | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index fdaef60b46d6..c9a0638225fd 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -113,6 +113,10 @@ config X86
 	select ARCH_HAS_ZONE_DMA_SET if EXPERT
 	select ARCH_HAVE_NMI_SAFE_CMPXCHG
 	select ARCH_HAVE_EXTRA_ELF_NOTES
+	select ARCH_INLINE_SPIN_UNLOCK
+	select ARCH_INLINE_SPIN_UNLOCK_BH
+	select ARCH_INLINE_SPIN_UNLOCK_IRQ
+	select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE
 	select ARCH_MEMORY_ORDER_TSO
 	select ARCH_MHP_MEMMAP_ON_MEMORY_ENABLE
 	select ARCH_MIGHT_HAVE_ACPI_PDC		if ACPI
-- 
2.53.0-Meta


^ permalink raw reply related

* Re: [RFC PATCH v1 00/13] exec: add spawn templates for repeated executable startup
From: Mateusz Guzik @ 2026-06-10 23:40 UTC (permalink / raw)
  To: Li Chen
  Cc: John Ericson, Andy Lutomirski, Christian Brauner, Kees Cook,
	Al Viro, linux-fsdevel, linux-api, LKML, linux-mm, linux-arch,
	linux-doc, linux-kselftest, x86, Arnd Bergmann, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Jan Kara, Jonathan Corbet, Shuah Khan
In-Reply-To: <19eb181fdd4.6d028f442844776.3737831021032223216@linux.beauty>

On Wed, Jun 10, 2026 at 08:29:06PM +0800, Li Chen wrote:
>  ---- On Wed, 10 Jun 2026 01:27:47 +0800  John Ericson <mail@johnericson.me> wrote --- 
>  > Hope the above answers your question? I suppose my ideas lean more on the
>  > "future" than "empty" side --- there is indeed a thread in the thread group,
>  > with real VM/namespace/file descriptor etc. state. Moreover, state gets
>  > initialized before the process is started, so the actual start is a pretty
>  > lightweight step of just letting the scheduler know the now-ready process can
>  > be scheduled. The only thing that distinguishes the embryonic process from a
>  > real one is simply that it isn't running --- i.e. isn't (yet) available to be
>  > scheduled --- so the pidfds holders are free to poke at its state.
>  > 
> 
> Thanks, this helped a lot. I looked at FreeBSD/OpenBSD/XNU after your
> note. FreeBSD has P_INEXEC, OpenBSD has PS_INEXEC, and XNU seems even
> closer with P_LINTRANSIT, described as "process in exec or in creation".
> Linux does not seem to have a single equivalent today: current->in_execve
> is only an LSM hint, while the real synchronization is spread across
> exec_update_lock, cred_guard_mutex, and the exec path.
> 
> I am switching my local WIP from the two-fd builder model to one fd,
> closer to Christian's sketch:
> 
> fd = pidfd_open(0, PIDFD_EMPTY);
> pidfd_config(fd, ...);
> pidfd_spawn_run(fd, ...);
> 
> In my current local version, I still use copy_process(), so the fd points
> at a real task_struct/pid that is not woken until run. Following
> Christian's point that existing APIs can handle this not-yet-running case
> with ESRCH, I currently make ordinary pidfd operations that need a real
> started process return -ESRCH before start.
> 
> I am not sure yet whether Linux should grow a general exec/creation
> transition state like that, or whether a narrower future-process
> lifecycle is enough for this API. I will think more about that when
> working on the pristine process version.
> 

As I tried to explain in my previous e-mail this approach does not cut
it because of NUMA.

Suppose you have a machine with 2 nodes. The parent-to-be is running
on node 0 and the child is intended to exec something on node 1.

When the parent-to-be allocates and populates stuff, it takes place with
memory backed by node 0. If you allocate task_struct, the file table and
other frequently used (and modified!) objs in this way, you are
guaranteeing performance loss due to interconnect traffic to access it.

Trying to add plumbing so that all allocations respect numa placement is
probably too cumbersome.

The primary example for that is looking up the binary to exec in the
first place.

userspace likes to pass paths which don't exist, meaning checking for
the binary before any hard work is a useful optimizaiton. Suppose the
binary to be executed is in a container bound with a taskset using
node 1 and the content of the fs part of the container is currently
fully uncached.

When you perform the lookup on node 0, you are populating a bunch of
metadata (inode, dentry) using memory from that domain. But the intended
user will only execute on node 1, again resulting in a performance loss.

In order to not do it you would need to convince VFS to allocate memory
elsewhere.

So I stand by my previous claim that ultimately a pristine child has to
be created (like in this patch), but which also has to do the work on
its own.

Suppose there is no explicit placement requested anywhere. Even in that
case there are legitimate workloads which will eventually be forced to
exec stuff on another node. Even these have a better chance retaining
full locality if the child process does all the work.

Per my previous message I don't see a clean interface to do it.
something quasi-posix_spawn is probably the least bad way out, it will
also allow userspace to easily wrap the new thing with posix_spawn
itself.

Also note there is another issue with the fd-based approach: the fd will
get inherited on fork and will hang out in the child afterwards unless
explicitly closed. Suppose you have a multithreaded program which likes
to both fork(+no exec) and fork+exec. With the fd-based approach you
have no means of stopping another thread from grabbing your state thanks
to unix defaulting to copying everything. There was an attempt to fix
this aspect with O_CLOFORK, but this got rejected.

Whatever exactly happens, NUMA is a sad fact of computing and needs to
be accounted for. The approach as proposed not only does not do it, but
it actively hinders such deployments.

^ permalink raw reply

* Re: [RFC PATCH v1 00/13] exec: add spawn templates for repeated executable startup
From: Mateusz Guzik @ 2026-06-10 22:59 UTC (permalink / raw)
  To: Jann Horn
  Cc: Christian Brauner, Li Chen, Kees Cook, Alexander Viro,
	linux-fsdevel, linux-api, linux-kernel, linux-mm, linux-arch,
	linux-doc, linux-kselftest, x86, Arnd Bergmann, Andy Lutomirski,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
	H. Peter Anvin, Jan Kara, Jonathan Corbet, Shuah Khan
In-Reply-To: <CAG48ez38OEE8ZPLyU6nr9=cYx-hMsdoh5WRrv-GMZGMDKyyOTA@mail.gmail.com>

On Mon, Jun 8, 2026 at 5:02 PM Jann Horn <jannh@google.com> wrote:
>
> On Thu, May 28, 2026 at 2:55 PM Mateusz Guzik <mjguzik@gmail.com> wrote:
> > This problem is dear to my heart and I have been pondering it on and off
> > for some time now. The entire fork + exec idiom is terrible and needs to
> > be retired.
>
> It seems to me like vfork+exec is a decent UAPI building block, on
> which you can build nice-looking userspace APIs, though I agree that
> this is not an ideal direct interface for application code.
>
> > Additionally there is a known problem where transiently copied file
> > descriptors on fork + exec cause a headache in multithreaded programs
> > doing something like this in parallel. I only did cursory reading, it
> > seems your patchset keeps the same problem in place.
>
> I think we almost have UAPI that would let you avoid this issue?
> You can use clone() with CLONE_FILES, then unshare the FD table with
> close_range(3, UINT_MAX, CLOSE_RANGE_UNSHARE). That is not currently
> implemented to be atomic with stuff that happens on other threads, but
> if we changed that, and it doesn't provide a good way to carry some
> FDs across, but it feels to me like this could be fixed with a variant
> of close_range() that removes O_CLOEXEC FDs except ones listed in an
> array.

Suppose you want to exec a binary with the following fd set:
0 is /dev/null
1 is fd 1023 in your process
2 is fd 1023 in your process

You have tons of other fds and you don't want any of them anywhere near this.

Clean interface from my standpoint would avoid any unnecessary
overhead and would allow you to clearly specify what do you want.

In this case whatever the interface it should provide the ability to
map 1023 to 1 and 2 in the child. With the current syscall set you get
refs taken on these on clone, then you have to manually dup2 these
which is separate syscalls with extra atomics on top. A fast & elegant
solution would allow you to tell the kernel directly where to install
the 2 files.

Also note in practical terms userspace likes to closefrom/close_range
anyway to get rid of unwanted fds which happen to not have the cloexec
bit which is yet another syscall to invoke on the way to exec. A
better interface would instantly avoid the problem by not copying the
unwanted fds if not asked. For viability for use as foundation to
build posix_spawn over it such copying would have to be supported of
course.

>
> > There are numerous impactful ways to speed up execs both in terms of
> > single-threaded cost and their multicore scalability, most of which
> > would be immediately usable by all programs without an opt-in. imo these
> > needs to be exhausted before something like a "template" can be
> > considered.
>
> (I think probably a large part of this would be stuff that happens in
> userspace, like dynamic linking.)

I have not investigated userspace, even putting specific APIs aside
the kernel has *a lot* of avoidable overhead.

>
> > Per the above, the primary win would stem from *NOT* messing with mm.
>
> As you write below, I think we have that with CLONE_MM? The C function
> vfork() is kind of a terrible API because of its returns-twice
> behavior, but I think if process cloning with CLONE_VM|CLONE_VFORK was
> wrapped by libc in a way similar to clone() (with the child executing
> a separate handler function), or if it was used in the implementation
> of some higher-level process-spawning API, it would be a perfectly
> fine API?
>
> Or am I misunderstanding what you mean by "messing with mm"?
>

I was not aware of this functionality, let's assume it indeed works.
You still have the file issue described above.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox