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
41 static void
print_page_array(const void ** const pages,const unsigned long count,const unsigned int offset)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
print_node_array(const int * const nodes,const unsigned long count,const unsigned int offset)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
print_status_array(const int * const status,const unsigned long count)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
print_stat_pages(const unsigned long pid,const unsigned long count,const void ** const pages,int * const status)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
print_move_pages(const unsigned long pid,unsigned long count,const unsigned int offset,const void ** const pages,int * const nodes,int * const status)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
main(void)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