Linux-mm Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [BUG/RFC] mm/madvise: MADV_WILLNEED skips swapped file-backed COW pages
@ 2026-08-31 18:24 Mike Kaplinskiy
  2026-09-03  7:05 ` zhaozhengzhuo
  2026-09-03 19:03 ` [BUG/RFC] mm/madvise: MADV_WILLNEED skips swapped file-backed COW pages Lorenzo Stoakes (ARM)
  0 siblings, 2 replies; 6+ messages in thread
From: Mike Kaplinskiy @ 2026-08-31 18:24 UTC (permalink / raw)
  To: linux-mm; +Cc: linux-kernel, akpm, liam, ljs, david, vbabka, jannh

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

Hi,

I'm seeing a strange behavior when using MADV_WILLNEED to schedule
swap page-in. It seems MADV_WILLNEED does not schedule swap reads for
swapped-out COW pages in an ordinary file-backed MAP_PRIVATE mapping.

I reproduced this on Linux 7.0.14 on aarch64, but I think this code
hasn't changed in a while. mm/madvise.c:madvise_willneed walks swap
PTEs only when vma->vm_file is NULL, and sends other file-backed
mappings to vfs_fadvise(POSIX_FADV_WILLNEED). This skips the case of
MAP_PRIVATE mappings with changes, which frequently happens for
libraries/binaries with relocations and/or writable globals.

The code is at the top of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/mm/madvise.c#n282
.

Minimal reproducer attached. Would there be interest in changing this
path to prefetch private copies in addition to the readahead?

Thanks,
Mike

[-- Attachment #2: madvise-willneed-cow-repro.c --]
[-- Type: text/x-csrc, Size: 1766 bytes --]

#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

#define SIZE (64UL << 20)

static size_t swap_kib(void *mapping)
{
	FILE *f = fopen("/proc/self/smaps", "r");
	char line[256], perms[5];
	unsigned long start, end, value = 0;
	int ours = 0;

	assert(f);
	while (fgets(line, sizeof(line), f)) {
		if (sscanf(line, "%lx-%lx %4s", &start, &end, perms) == 3)
			ours = start == (unsigned long)mapping;
		else if (ours && sscanf(line, "Swap: %lu kB", &value) == 1)
			break;
	}
	fclose(f);
	return value;
}

static unsigned long pswpin(void)
{
	FILE *f = fopen("/proc/vmstat", "r");
	char name[32];
	unsigned long value = 0;

	assert(f);
	while (fscanf(f, "%31s %lu", name, &value) == 2)
		if (!strcmp(name, "pswpin"))
			break;
	fclose(f);
	return value;
}

int main(void)
{
	char path[] = "/tmp/madvise-cow-XXXXXX";
	int fd = mkstemp(path);
	char *p;
	unsigned long before;
	volatile unsigned long sum = 0;

	assert(fd >= 0 && !ftruncate(fd, SIZE));
	p = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
	assert(p != MAP_FAILED);
	unlink(path);

	for (size_t i = 0; i < SIZE; i += getpagesize())
		p[i] = i / getpagesize() + 1; /* create private COW pages */
	assert(!madvise(p, SIZE, MADV_PAGEOUT));
	usleep(500000);
	printf("after PAGEOUT:  Swap=%zu kB\n", swap_kib(p));

	before = pswpin();
	assert(!madvise(p, SIZE, MADV_WILLNEED));
	sleep(2); /* WILLNEED is asynchronous */
	printf("after WILLNEED: Swap=%zu kB, pswpin=+%lu\n",
	       swap_kib(p), pswpin() - before);

	before = pswpin();
	for (size_t i = 0; i < SIZE; i += getpagesize())
		sum += p[i];
	printf("after touch:    pswpin=+%lu (sum=%lu)\n",
	       pswpin() - before, sum);
}

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-09-04 14:52 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-31 18:24 [BUG/RFC] mm/madvise: MADV_WILLNEED skips swapped file-backed COW pages Mike Kaplinskiy
2026-09-03  7:05 ` zhaozhengzhuo
2026-09-03 17:03   ` Mike Kaplinskiy
2026-09-04 10:09     ` [RFC PATCH v1] mm/madvise: prefetch private file COW swap entries zhaozhengzhuo
2026-09-04 14:52       ` Lorenzo Stoakes (ARM)
2026-09-03 19:03 ` [BUG/RFC] mm/madvise: MADV_WILLNEED skips swapped file-backed COW pages Lorenzo Stoakes (ARM)

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