Home | History | Annotate | Download | only in tests
      1 /*
      2  * Check decoding of move_pages syscall.
      3  *
      4  * Copyright (c) 2016 Dmitry V. Levin <ldv (at) altlinux.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include "tests.h"
     31 #include <asm/unistd.h>
     32 
     33 #ifdef __NR_move_pages
     34 
     35 # include <errno.h>
     36 # include <stdio.h>
     37 # include <unistd.h>
     38 
     39 # define MAX_STRLEN 3
     40 
     41 static void
     42 print_page_array(const void **const pages,
     43 		 const unsigned long count,
     44 		 const unsigned int offset)
     45 {
     46 	if (!count) {
     47 		printf("%s", pages ? "[]" : "NULL");
     48 		return;
     49 	}
     50 	if (count <= offset) {
     51 		printf("%p", pages);
     52 		return;
     53 	}
     54 	printf("[");
     55 	unsigned long i;
     56 	for (i = 0; i < count; ++i) {
     57 		if (i)
     58 			printf(", ");
     59 		if (i + offset < count) {
     60 			if (i >= MAX_STRLEN) {
     61 				printf("...");
     62 				break;
     63 			}
     64 		} else {
     65 			printf("%p", pages + i);
     66 			break;
     67 		}
     68 		const void *const addr = pages[i];
     69 		if (addr)
     70 			printf("%p", addr);
     71 		else
     72 			printf("NULL");
     73 	}
     74 	printf("]");
     75 }
     76 
     77 static void
     78 print_node_array(const int *const nodes,
     79 		 const unsigned long count,
     80 		 const unsigned int offset)
     81 {
     82 	if (!count) {
     83 		printf("%s", nodes ? "[]" : "NULL");
     84 		return;
     85 	}
     86 	if (count <= offset) {
     87 		printf("%p", nodes);
     88 		return;
     89 	}
     90 	printf("[");
     91 	unsigned long i;
     92 	for (i = 0; i < count; ++i) {
     93 		if (i)
     94 			printf(", ");
     95 		if (i + offset < count) {
     96 			if (i >= MAX_STRLEN) {
     97 				printf("...");
     98 				break;
     99 			}
    100 		} else {
    101 			printf("%p", nodes + i);
    102 			break;
    103 		}
    104 		printf("%d", nodes[i]);
    105 	}
    106 	printf("]");
    107 }
    108 
    109 static void
    110 print_status_array(const int *const status, const unsigned long count)
    111 {
    112 	if (!count) {
    113 		printf("%s", status ? "[]" : "NULL");
    114 		return;
    115 	}
    116 	printf("[");
    117 	unsigned long i;
    118 	for (i = 0; i < count; ++i) {
    119 		if (i)
    120 			printf(", ");
    121 		if (i >= MAX_STRLEN) {
    122 			printf("...");
    123 			break;
    124 		}
    125 		if (status[i] >= 0) {
    126 			printf("%d", status[i]);
    127 		} else {
    128 			errno = -status[i];
    129 			printf("%s", errno2name());
    130 		}
    131 	}
    132 	printf("]");
    133 }
    134 
    135 static void
    136 print_stat_pages(const unsigned long pid, const unsigned long count,
    137 		 const void **const pages, int *const status)
    138 {
    139 	const unsigned long flags = (unsigned long) 0xfacefeed00000002ULL;
    140 
    141 	long rc = syscall(__NR_move_pages,
    142 			  pid, count, pages, NULL, status, flags);
    143 	const char *errstr = sprintrc(rc);
    144 	printf("move_pages(%d, %lu, ", (int) pid, count);
    145 	print_page_array(pages, count, 0);
    146 	printf(", NULL, ");
    147 	if (rc) {
    148 		if (count)
    149 			printf("%p", status);
    150 		else
    151 			printf("[]");
    152 	} else {
    153 		print_status_array(status, count);
    154 	}
    155 	printf(", MPOL_MF_MOVE) = %s\n", errstr);
    156 }
    157 
    158 static void
    159 print_move_pages(const unsigned long pid,
    160 		 unsigned long count,
    161 		 const unsigned int offset,
    162 		 const void **const pages,
    163 		 int *const nodes,
    164 		 int *const status)
    165 {
    166 	const unsigned long flags = (unsigned long) 0xfacefeed00000004ULL;
    167 	count += offset;
    168 
    169 	long rc = syscall(__NR_move_pages,
    170 			  pid, count, pages, nodes, status, flags);
    171 	const char *errstr = sprintrc(rc);
    172 	printf("move_pages(%d, %lu, ", (int) pid, count);
    173 	print_page_array(pages, count, offset);
    174 	printf(", ");
    175 	print_node_array(nodes, count, offset);
    176 	printf(", ");
    177 	if (count)
    178 		printf("%p", status);
    179 	else
    180 		printf("[]");
    181 	printf(", MPOL_MF_MOVE_ALL) = %s\n", errstr);
    182 }
    183 
    184 int
    185 main(void)
    186 {
    187 	const unsigned long pid =
    188 		(unsigned long) 0xfacefeed00000000ULL | getpid();
    189 	unsigned long count = 1;
    190 	const unsigned page_size = get_page_size();
    191 	const void *const page = tail_alloc(page_size);
    192 	const void *const efault = page + page_size;
    193 	const void **pages = tail_alloc(sizeof(*pages));
    194 	int *nodes = tail_alloc(sizeof(*nodes));
    195 	int *status = tail_alloc(sizeof(*status));
    196 
    197 	print_stat_pages(pid, 0, pages, status);
    198 	print_move_pages(pid, 0, 0, pages, nodes, status);
    199 	print_move_pages(pid, 0, 1, pages + 1, nodes + 1, status + 1);
    200 
    201 	*pages = page;
    202 	print_stat_pages(pid, count, pages, status);
    203 	*nodes = 0xdeadbee1;
    204 	print_move_pages(pid, count, 0, pages, nodes, status);
    205 	print_move_pages(pid, count, 1, pages, nodes, status);
    206 
    207 	++count;
    208 	--status;
    209 	*(--pages) = efault;
    210 	print_stat_pages(pid, count, pages, status);
    211 	*(--nodes) = 0xdeadbee2;
    212 	print_move_pages(pid, count, 0, pages, nodes, status);
    213 	print_move_pages(pid, count, 1, pages, nodes, status);
    214 
    215 	++count;
    216 	--status;
    217 	*(--pages) = nodes;
    218 	print_stat_pages(pid, count, pages, status);
    219 	*(--nodes) = 0xdeadbee3;
    220 	print_move_pages(pid, count, 0, pages, nodes, status);
    221 	print_move_pages(pid, count, 1, pages, nodes, status);
    222 
    223 	++count;
    224 	--status;
    225 	*(--pages) = status;
    226 	print_stat_pages(pid, count, pages, status);
    227 	*(--nodes) = 0xdeadbee4;
    228 	print_move_pages(pid, count, 0, pages, nodes, status);
    229 	print_move_pages(pid, count, 1, pages, nodes, status);
    230 
    231 	puts("+++ exited with 0 +++");
    232 	return 0;
    233 }
    234 
    235 #else
    236 
    237 SKIP_MAIN_UNDEFINED("__NR_move_pages")
    238 
    239 #endif
    240