/*
* libhugetlbfs - Easy use of Linux hugepages
* Copyright (C) 2013 Joonsoo Kim, LG Electronics.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/mman.h>
#include <hugetlbfs.h>
#include "hugetests.h"
#define P "noresv-preserve-resv-page"
#define DESC \
"* Test to preserve a reserved page against no-reserved maping. *\n"\
"* If all hugepages are reserved, access to no-reserved shared *\n"\
"* mapping cause a process die, instead of stealing a hugepage *\n"\
"* which is reserved for other process *\n"
static sigjmp_buf sig_escape;
static void *sig_expected = MAP_FAILED;
static void sig_handler(int signum, siginfo_t *si, void *uc)
{
if (signum == SIGBUS) {
verbose_printf("SIGBUS at %p (sig_expected=%p)\n", si->si_addr,
sig_expected);
if (si->si_addr == sig_expected) {
siglongjmp(sig_escape, 1);
}
FAIL("SIGBUS somewhere unexpected");
}
FAIL("Unexpected signal %s", strsignal(signum));
}
static void test_write(void *p)
{
volatile char *pl = p;
if (sigsetjmp(sig_escape, 1)) {
/* We got a SIGBUS */
PASS();
}
sig_expected = p;
barrier();
*pl = 's';
}
int main(int argc, char *argv[])
{
long hpage_size;
int nr_hugepages;
int surp_hugepages;
int fd1, fd2, err;
char *p, *q;
struct sigaction sa = {
.sa_sigaction = sig_handler,
.sa_flags = SA_SIGINFO,
};
test_init(argc, argv);
hpage_size = check_hugepagesize();
nr_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_FREE);
fd1 = hugetlbfs_unlinked_fd();
if (fd1 < 0)
FAIL("hugetlbfs_unlinked_fd()");
fd2 = hugetlbfs_unlinked_fd();
if (fd2 < 0)
FAIL("hugetlbfs_unlinked_fd()");
err = sigaction(SIGBUS, &sa, NULL);
if (err)
FAIL("Can't install SIGBUS handler: %s", strerror(errno));
p = mmap(NULL, hpage_size * nr_hugepages,
PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0);
if (p == MAP_FAILED)
FAIL("mmap() 1: %s", strerror(errno));
verbose_printf("Reserve all hugepages %d\n", nr_hugepages);
q = mmap(NULL, hpage_size,
PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd2, 0);
if (q == MAP_FAILED)
FAIL("mmap() 2: %s", strerror(errno));
verbose_printf("Write to %p to steal reserved page\n", q);
surp_hugepages = get_huge_page_counter(hpage_size, HUGEPAGES_SURP);
test_write(q);
/* Provisioning succeeded because of overcommit */
if (get_huge_page_counter(hpage_size, HUGEPAGES_SURP) ==
surp_hugepages + 1)
PASS();
FAIL("Steal reserved page");
}