On Wed, Oct 9, 2024 at 9:04 AM Avi Kivity <avi@xxxxxxxxxxxx> wrote: > > On Linux 6.10.10 with CONFIG_READ_ONLY_THP_FOR_FS=y, > madvise(MADV_COLLAPSE) on program text fails with EINVAL. > > To reproduce, compile the reproducer with > > clang -g -o text-hugepage text-hugepage.c \ > -fuse-ld=lld \ > -Wl,-zcommon-page-size=2097152 -Wl,-zmax-page-size=2097152 \ > -Wl,-z,separate-loadable-segments > > and run: Didn't clang make the page cache dirty? Having sync between clang and the execution made the problem go away for me. > > $ strace -e trace=madvise ./text-hugepage > madvise(0x400000, 2097152, MADV_HUGEPAGE) = 0 > madvise(0x400000, 2097152, MADV_POPULATE_READ) = 0 > madvise(0x400000, 2097152, MADV_COLLAPSE) = -1 EINVAL (Invalid > argument) > > (the funky linker options are needed to make sure the .text vma spans a > hugepage). > > > I say "possible regression" since I haven't tried it with an older > kernel, but I believe it worked at some point or other seeing that > others managed to get it to work. > > ==== text-hugepage.c ==== > #include <stdlib.h> > #include <stdint.h> > #include <stdio.h> > #include <string.h> > > #include <sys/mman.h> > > static > void > try_remap_text_segment() { > FILE *fp = fopen("/proc/self/maps", "r"); > if (!fp) { > return; > } > char *buf = NULL; > size_t n; > while (getline(&buf, &n, fp) >= 0) { > char *lstart = buf; > char *lmid = strchr(lstart, '-'); > if (!lmid) { > continue; > } > *lmid++ = '\0'; > char *lend = strchr(lmid, ' '); > if (!lend) { > continue; > } > *lend = '\0'; > > size_t start = strtoul(lstart, NULL, 16); > size_t end = strtoul(lmid, NULL, 16); > uintptr_t some_text_addr = (uintptr_t)&try_remap_text_segment; > if (some_text_addr >= start && some_text_addr < end) { > end &= ~(uintptr_t)0x1fffff; > madvise((void*)start, end - start, MADV_HUGEPAGE); > madvise((void*)start, end - start, MADV_POPULATE_READ); > madvise((void*)start, end - start, MADV_COLLAPSE); > break; > } > } > free(buf); > fclose(fp); > } > > void > huge_function() { > // Make sure .text is has a huge page full of stuff > asm volatile (".fill 4000000, 1, 0x90"); > } > > int > main() { > try_remap_text_segment(); > } > ==== end text-hugepage.c ==== >