1/*
2 * Check decoding of move_pages syscall.
3 *
4 * Copyright (c) 2016 Dmitry V. Levin <ldv@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
41static void
42print_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
77static void
78print_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
109static void
110print_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
135static void
136print_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
158static void
159print_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
184int
185main(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
237SKIP_MAIN_UNDEFINED("__NR_move_pages")
238
239#endif
240