Currently, some of uvtop() functions on x86, x86_64 and ia64 lacks
checking whether in pte _PAGE_PROTNONE bit is set or not. The flag is
set to pte when specifying to the corresponding memory space PROT_NONE
using mprotect(), and then _PAGE_PRESENT bit in the pte is unset in
order to make hardware cause segmentation fault
intensionally. Important is the fact that besides _PAGE_PRESENT set,
_PAGE_PROTNONE indicates the page is present (not swapped out).
The architectures fixed are x86, x86_64 and ia64 except for Xen.
The patchset based on crash 5.1.4 consists of 5 patches, which are
divided into the ones extending machine dependent data on x86 and
x86_64, and the ones actually adding _PAGE_PROTNONE checking into each
uvtop().
defs.h | 6 ++++--
ia64.c | 6 +++---
x86.c | 10 ++++++++--
x86_64.c | 11 +++++++++--
4 files changed, 24 insertions(+), 9 deletions(-)
More two files attached are the programs I used in order to create
dumps for tests: testpro.c allocates 5 kinds of memory spaces in
combination with mprotect()ed, mlock()ed or hugepage; mempres.c can be
used to cause memory pressure to force pages to be swapped out.
By the way, the issue I faced but have yet fixed is that on ia64,
vtop() operation on mlock()ed hugepage memory space fails. The
situation can be reproduced using the attached program.
Thanks.
HATAYAMA, Daisuke
/*
* Take the following step before you run this program:
*
* 1. set up the environment to be able to use hugetlb feature.
*
* $ echo 10 > /proc/sys/vm/nr_hugepages
*
* - This operation is intended to change the number of
* hugepages that system can allocate from physical memory.
*
* - You can check a single huge page size from /proc/meminfo
*
* $ grep "Huge" /proc/meminfo
* HugePages_Total: 128
* HugePages_Free: 128
* HugePages_Rsvd: 0
* Hugepagesize: 2048 kB
*
* - You need to set up the number of hugepages enough for required memory size.
*
* $ mkdir -p /media/hugetlb
* $ mount -t hugetlbfs none /media/hugetlb -o uid=n,gid=m,mode=0777
* $ echo m > /proc/sys/vm/hugetlb_shm_group
*
* - Both n and m are 0 for root user; so it's easy to specify this by
* doing as root user.
*
* 2. Use mmap or shmget to map hugepages via /media/hugetlb.
*
* Reference
*
* [1] linux-2.6/Documentation/vm/hugetlbpage.txt
*
*/
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
static void pmapx(void);
static size_t get_hugepagesize(void);
static void *hugepage_alloc(size_t size);
int main(int argc, char **argv)
{
unsigned long i;
char *obj_swap, *obj_locked, *obj_huge_swap, *obj_huge_locked,
*obj_huge_locked_nonprotect;
long pagesize;
size_t hugepagesize;
if ((pagesize = sysconf(_SC_PAGESIZE)) < 0)
goto error;
if (!(hugepagesize = get_hugepagesize()))
goto error;
if (!(obj_swap = valloc(pagesize)))
goto error;
if (!(obj_locked = valloc(pagesize)))
goto error;
if (!(obj_huge_swap = hugepage_alloc(hugepagesize)))
goto error;
if (!(obj_huge_locked = hugepage_alloc(hugepagesize)))
goto error;
if (!(obj_huge_locked_nonprotect = hugepage_alloc(hugepagesize)))
goto error;
memset(obj_swap, 's', pagesize);
memset(obj_locked, 'l', pagesize);
memset(obj_huge_swap, 'S', hugepagesize);
memset(obj_huge_locked, 'L', hugepagesize);
memset(obj_huge_locked_nonprotect, 'N', hugepagesize);
if (mlock(obj_locked, pagesize))
goto error;
if (mlock(obj_huge_locked, hugepagesize))
goto error;
if (mlock(obj_huge_locked_nonprotect, hugepagesize))
goto error;
if (mprotect(obj_locked, pagesize, PROT_NONE) < 0)
goto error;
if (mprotect(obj_swap, pagesize, PROT_NONE) < 0)
goto error;
if (mprotect(obj_huge_locked, hugepagesize, PROT_NONE) < 0)
goto error;
if (mprotect(obj_huge_swap, hugepagesize, PROT_NONE) < 0)
goto error;
for (;;) {
sleep(100);
}
return EXIT_SUCCESS;
error:
fprintf(stderr, "%s: %s\n", basename(argv[0]), strerror(errno));
return EXIT_FAILURE;
}
static size_t get_hugepagesize(void)
{
char buf[128];
FILE *meminfo;
size_t hugepagesize;
meminfo = fopen("/proc/meminfo", "r");
if (!meminfo)
return 0;
for (;;) {
fgets(buf, sizeof(buf), meminfo);
if (ferror(meminfo))
return 0;
if (strstr(buf, "Hugepagesize:"))
break;
if (feof(meminfo))
return 0;
}
fclose(meminfo);
sscanf(buf, "Hugepagesize: %lu kB", &hugepagesize);
hugepagesize *= 1024; /* kB => B */
return hugepagesize;
}
static void *hugepage_alloc(size_t size)
{
int c, fd;
void *obj;
fd = open("/media/hugetlb/hugepage_protnone", O_CREAT | O_RDWR, 0755);
if (fd < 0)
return NULL;
c = 'K';
write(fd, &c, 1);
obj = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
if (obj < 0)
return NULL;
return obj;
}
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <unistd.h>
int main(int argc, char **argv)
{
size_t memsize = (1UL << 30UL);
long pagesize;
int i;
char *obj;
pagesize = sysconf(_SC_PAGESIZE);
obj = memalign(pagesize, memsize);
if (!obj) {
perror("malloc");
exit(EXIT_FAILURE);
}
for (;;) {
for (i = 0; i < memsize; ++i) {
obj[i] = 'O';
}
}
return 0;
}