* Copyright (c) 2008 Vijay Kumar B. <vijaykumar@bravegnu.org>
* Copyright (c) International Business Machines Corp., 2001
*/
* Verify that move_pages() properly reports failures when the memory area is
* not valid, no page is mapped yet or the shared zero page is mapped.
*
* [Algorithm]
*
* #. Pass the address of a valid memory area where no page is
* mapped yet (not read/written), the address of a valid memory area
* where the shared zero page is mapped (read, but not written to)
* and the address of an invalid memory area as page addresses to
* move_pages().
* #. Check if the corresponding status for "no page mapped" is set to
* -ENOENT. Note that kernels >= 4.3 [1] and < 6.12 [2] wrongly returned
* -EFAULT by accident.
* #. Check if the corresponding status for "shared zero page" is set to:
* -EFAULT. Note that kernels < 4.3 [1] wrongly returned -ENOENT.
* #. Check if the corresponding status for "invalid memory area" is set
* to -EFAULT.
*
* - [1] d899844e9c98 "mm: fix status code which move_pages() returns for zero page"
* - [2] 7dff875c9436 "mm/migrate: convert add_page_for_migration() from follow_page() to folio_walk"
*/
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include "tst_test.h"
#include "move_pages_support.h"
#define TEST_PAGES 4
#define TEST_NODES 2
#define TOUCHED_PAGES 1
#define NO_PAGE TOUCHED_PAGES
#define ZERO_PAGE (NO_PAGE + 1)
#define INVALID_PAGE (ZERO_PAGE + 1)
static void run(void)
{
#ifdef HAVE_NUMA_V2
unsigned int i;
unsigned int from_node;
unsigned int to_node;
int ret;
void *pages[TEST_PAGES] = { 0 };
int nodes[TEST_PAGES];
int status[TEST_PAGES];
unsigned long onepage = get_page_size();
char tmp;
ret = get_allowed_nodes(NH_MEMS, 2, &from_node, &to_node);
if (ret < 0)
tst_brk(TBROK | TERRNO, "get_allowed_nodes: %d", ret);
ret = alloc_pages_on_node(pages, TOUCHED_PAGES, from_node);
if (ret == -1)
tst_brk(TBROK, "failed allocating memory on node %d",
from_node);
* Allocate memory and do not touch it. Consequently, no
* page will be faulted in / mapped into the page tables.
*/
pages[NO_PAGE] = numa_alloc_onnode(onepage, from_node);
if (pages[NO_PAGE] == NULL)
tst_brk(TBROK, "failed allocating memory on node %d",
from_node);
* Allocate memory, read from it, but do not write to it. This
* will populate the shared zeropage.
*/
pages[ZERO_PAGE] = numa_alloc_onnode(onepage, from_node);
if (pages[ZERO_PAGE] == NULL)
tst_brk(TBROK, "failed allocating memory on node %d",
from_node);
tmp = *((char *)pages[ZERO_PAGE]);
asm volatile("" : "+r" (tmp));
* Temporarily allocate memory and free it immediately. Do this
* as the last step so the area won't get reused before we're
* done.
*/
pages[INVALID_PAGE] = numa_alloc_onnode(onepage, from_node);
if (pages[INVALID_PAGE] == NULL)
tst_brk(TBROK, "failed allocating memory on node %d",
from_node);
numa_free(pages[INVALID_PAGE], onepage);
for (i = 0; i < TEST_PAGES; i++)
nodes[i] = to_node;
ret = numa_move_pages(0, TEST_PAGES, pages, nodes,
status, MPOL_MF_MOVE);
if (ret == -1) {
tst_res(TFAIL | TERRNO,
"move_pages unexpectedly failed");
goto err_free_pages;
} else if (ret > 0) {
tst_res(TINFO, "move_pages() returned %d", ret);
}
if (status[NO_PAGE] == -ENOENT) {
tst_res(TPASS, "status[%d] has expected value",
NO_PAGE);
} else {
tst_res(TFAIL, "status[%d] is %s, expected %s",
NO_PAGE,
tst_strerrno(-status[NO_PAGE]),
tst_strerrno(ENOENT));
}
if (status[ZERO_PAGE] == -EFAULT) {
tst_res(TPASS, "status[%d] has expected value",
ZERO_PAGE);
} else {
tst_res(TFAIL, "status[%d] is %s, expected %s",
ZERO_PAGE,
tst_strerrno(-status[ZERO_PAGE]),
tst_strerrno(EFAULT));
}
if (status[INVALID_PAGE] == -EFAULT) {
tst_res(TPASS, "status[%d] has expected value",
INVALID_PAGE);
} else {
tst_res(TFAIL, "status[%d] is %s, expected %s",
INVALID_PAGE,
tst_strerrno(-status[INVALID_PAGE]),
tst_strerrno(EFAULT));
}
err_free_pages:
pages[INVALID_PAGE] = NULL;
free_pages(pages, TEST_PAGES);
#else
tst_res(TCONF, NUMA_ERROR_MSG);
#endif
}
void setup(void)
{
check_config(TEST_NODES);
}
static struct tst_test test = {
.test_all = run,
.setup = setup,
.tags = (const struct tst_tag[]) {
{"linux-git", "d899844e9c98"},
{"linux-git", "7dff875c9436"},
{}
}
};