1 /*-
2 * Copyright (c) 2006 Robert N. M. Watson
3 * All rights reserved.
4 *
5 * Copyright (c) 2021 The FreeBSD Foundation
6 *
7 * Portions of this software were developed by Ka Ho Ng
8 * under sponsorship from the FreeBSD Foundation.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <sys/resource.h>
36 #include <sys/socket.h>
37 #include <sys/stat.h>
38 #include <sys/syscall.h>
39 #include <sys/sysctl.h>
40 #include <sys/wait.h>
41
42 #ifdef __amd64__
43 #include <machine/cpufunc.h>
44 #include <machine/specialreg.h>
45 #include <machine/sysarch.h>
46 #endif
47
48 #include <ctype.h>
49 #include <errno.h>
50 #include <fcntl.h>
51 #include <paths.h>
52 #include <setjmp.h>
53 #include <signal.h>
54 #include <stdatomic.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59
60 #include <atf-c.h>
61
62 #include "posixshm.h"
63
64 #define TEST_PATH_LEN 256
65 static char test_path[TEST_PATH_LEN];
66 static char test_path2[TEST_PATH_LEN];
67 static unsigned int test_path_idx = 0;
68
69 static void
gen_a_test_path(char * path)70 gen_a_test_path(char *path)
71 {
72 snprintf(path, TEST_PATH_LEN, "/%s/tmp.XXXXXX%d",
73 getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR"),
74 test_path_idx);
75
76 test_path_idx++;
77
78 ATF_REQUIRE_MSG(mkstemp(path) != -1,
79 "mkstemp failed; errno=%d", errno);
80 ATF_REQUIRE_MSG(unlink(path) == 0,
81 "unlink failed; errno=%d", errno);
82 }
83
84 static void
gen_test_path(void)85 gen_test_path(void)
86 {
87 gen_a_test_path(test_path);
88 }
89
90 static void
gen_test_path2(void)91 gen_test_path2(void)
92 {
93 gen_a_test_path(test_path2);
94 }
95
96 /*
97 * Attempt a shm_open() that should fail with an expected error of 'error'.
98 */
99 static void
shm_open_should_fail(const char * path,int flags,mode_t mode,int error)100 shm_open_should_fail(const char *path, int flags, mode_t mode, int error)
101 {
102 int fd;
103
104 fd = shm_open(path, flags, mode);
105 ATF_CHECK_MSG(fd == -1, "shm_open didn't fail");
106 ATF_CHECK_MSG(error == errno,
107 "shm_open didn't fail with expected errno; errno=%d; expected "
108 "errno=%d", errno, error);
109 }
110
111 /*
112 * Attempt a shm_unlink() that should fail with an expected error of 'error'.
113 */
114 static void
shm_unlink_should_fail(const char * path,int error)115 shm_unlink_should_fail(const char *path, int error)
116 {
117
118 ATF_CHECK_MSG(shm_unlink(path) == -1, "shm_unlink didn't fail");
119 ATF_CHECK_MSG(error == errno,
120 "shm_unlink didn't fail with expected errno; errno=%d; expected "
121 "errno=%d", errno, error);
122 }
123
124 /*
125 * Open the test object and write a value to the first byte. Returns valid fd
126 * on success and -1 on failure.
127 */
128 static int
scribble_object(const char * path,char value)129 scribble_object(const char *path, char value)
130 {
131 char *page;
132 int fd, pagesize;
133
134 ATF_REQUIRE(0 < (pagesize = getpagesize()));
135
136 fd = shm_open(path, O_CREAT|O_EXCL|O_RDWR, 0777);
137 if (fd < 0 && errno == EEXIST) {
138 if (shm_unlink(test_path) < 0)
139 atf_tc_fail("shm_unlink");
140 fd = shm_open(test_path, O_CREAT | O_EXCL | O_RDWR, 0777);
141 }
142 if (fd < 0)
143 atf_tc_fail("shm_open failed; errno=%d", errno);
144 if (ftruncate(fd, pagesize) < 0)
145 atf_tc_fail("ftruncate failed; errno=%d", errno);
146
147 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
148 if (page == MAP_FAILED)
149 atf_tc_fail("mmap failed; errno=%d", errno);
150
151 page[0] = value;
152 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
153 errno);
154
155 return (fd);
156 }
157
158 /*
159 * Fail the test case if the 'path' does not refer to an shm whose first byte
160 * is equal to expected_value
161 */
162 static void
verify_object(const char * path,char expected_value)163 verify_object(const char *path, char expected_value)
164 {
165 int fd;
166 int pagesize;
167 char *page;
168
169 ATF_REQUIRE(0 < (pagesize = getpagesize()));
170
171 fd = shm_open(path, O_RDONLY, 0777);
172 if (fd < 0)
173 atf_tc_fail("shm_open failed in verify_object; errno=%d, path=%s",
174 errno, path);
175
176 page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0);
177 if (page == MAP_FAILED)
178 atf_tc_fail("mmap(1)");
179 if (page[0] != expected_value)
180 atf_tc_fail("Renamed object has incorrect value; has"
181 "%d (0x%x, '%c'), expected %d (0x%x, '%c')\n",
182 page[0], page[0], isprint(page[0]) ? page[0] : ' ',
183 expected_value, expected_value,
184 isprint(expected_value) ? expected_value : ' ');
185 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
186 errno);
187 close(fd);
188 }
189
190 static off_t shm_max_pages = 32;
191 static const char byte_to_fill = 0x5f;
192
193 static int
shm_fill(int fd,off_t offset,off_t len)194 shm_fill(int fd, off_t offset, off_t len)
195 {
196 int error;
197 size_t blen, page_size;
198 char *buf;
199
200 error = 0;
201 page_size = getpagesize();
202 buf = malloc(page_size);
203 if (buf == NULL)
204 return (1);
205
206 while (len > 0) {
207 blen = len < (off_t)page_size ? (size_t)len : page_size;
208 memset(buf, byte_to_fill, blen);
209 if (pwrite(fd, buf, blen, offset) != (ssize_t)blen) {
210 error = 1;
211 break;
212 }
213 len -= blen;
214 offset += blen;
215 }
216
217 free(buf);
218 return (error);
219 }
220
221 static int
check_content_dealloc(int fd,off_t hole_start,off_t hole_len,off_t shm_sz)222 check_content_dealloc(int fd, off_t hole_start, off_t hole_len, off_t shm_sz)
223 {
224 int error;
225 size_t blen, page_size;
226 off_t offset, resid;
227 struct stat statbuf;
228 char *buf, *sblk;
229
230 error = 0;
231 page_size = getpagesize();
232 buf = malloc(page_size * 2);
233 if (buf == NULL)
234 return (1);
235 sblk = buf + page_size;
236
237 memset(sblk, 0, page_size);
238
239 if ((uint64_t)hole_start + hole_len > (uint64_t)shm_sz)
240 hole_len = shm_sz - hole_start;
241
242 /*
243 * Check hole is zeroed.
244 */
245 offset = hole_start;
246 resid = hole_len;
247 while (resid > 0) {
248 blen = resid < (off_t)page_size ? (size_t)resid : page_size;
249 if (pread(fd, buf, blen, offset) != (ssize_t)blen) {
250 error = 1;
251 break;
252 }
253 if (memcmp(buf, sblk, blen) != 0) {
254 error = 1;
255 break;
256 }
257 resid -= blen;
258 offset += blen;
259 }
260
261 memset(sblk, byte_to_fill, page_size);
262
263 /*
264 * Check file region before hole is zeroed.
265 */
266 offset = 0;
267 resid = hole_start;
268 while (resid > 0) {
269 blen = resid < (off_t)page_size ? (size_t)resid : page_size;
270 if (pread(fd, buf, blen, offset) != (ssize_t)blen) {
271 error = 1;
272 break;
273 }
274 if (memcmp(buf, sblk, blen) != 0) {
275 error = 1;
276 break;
277 }
278 resid -= blen;
279 offset += blen;
280 }
281
282 /*
283 * Check file region after hole is zeroed.
284 */
285 offset = hole_start + hole_len;
286 resid = shm_sz - offset;
287 while (resid > 0) {
288 blen = resid < (off_t)page_size ? (size_t)resid : page_size;
289 if (pread(fd, buf, blen, offset) != (ssize_t)blen) {
290 error = 1;
291 break;
292 }
293 if (memcmp(buf, sblk, blen) != 0) {
294 error = 1;
295 break;
296 }
297 resid -= blen;
298 offset += blen;
299 }
300
301 /*
302 * Check file size matches with expected file size.
303 */
304 if (fstat(fd, &statbuf) == -1)
305 error = -1;
306 if (statbuf.st_size != shm_sz)
307 error = -1;
308
309 free(buf);
310 return (error);
311 }
312
313 ATF_TC_WITHOUT_HEAD(remap_object);
ATF_TC_BODY(remap_object,tc)314 ATF_TC_BODY(remap_object, tc)
315 {
316 char *page;
317 int fd, pagesize;
318
319 ATF_REQUIRE(0 < (pagesize = getpagesize()));
320
321 gen_test_path();
322 fd = scribble_object(test_path, '1');
323
324 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
325 if (page == MAP_FAILED)
326 atf_tc_fail("mmap(2) failed; errno=%d", errno);
327
328 if (page[0] != '1')
329 atf_tc_fail("missing data ('%c' != '1')", page[0]);
330
331 close(fd);
332 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
333 errno);
334
335 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
336 "shm_unlink failed; errno=%d", errno);
337 }
338
339 ATF_TC_WITHOUT_HEAD(rename_from_anon);
ATF_TC_BODY(rename_from_anon,tc)340 ATF_TC_BODY(rename_from_anon, tc)
341 {
342 int rc;
343
344 gen_test_path();
345 rc = shm_rename(SHM_ANON, test_path, 0);
346 if (rc != -1)
347 atf_tc_fail("shm_rename from SHM_ANON succeeded unexpectedly");
348 }
349
350 ATF_TC_WITHOUT_HEAD(rename_bad_path_pointer);
ATF_TC_BODY(rename_bad_path_pointer,tc)351 ATF_TC_BODY(rename_bad_path_pointer, tc)
352 {
353 const char *bad_path;
354 int rc;
355
356 bad_path = (const char *)0x1;
357
358 gen_test_path();
359 rc = shm_rename(test_path, bad_path, 0);
360 if (rc != -1)
361 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
362
363 rc = shm_rename(bad_path, test_path, 0);
364 if (rc != -1)
365 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
366 }
367
368 ATF_TC_WITHOUT_HEAD(rename_from_nonexisting);
ATF_TC_BODY(rename_from_nonexisting,tc)369 ATF_TC_BODY(rename_from_nonexisting, tc)
370 {
371 int rc;
372
373 gen_test_path();
374 gen_test_path2();
375 rc = shm_rename(test_path, test_path2, 0);
376 if (rc != -1)
377 atf_tc_fail("shm_rename of nonexisting shm succeeded unexpectedly");
378
379 if (errno != ENOENT)
380 atf_tc_fail("Expected ENOENT to rename of nonexistent shm; got %d",
381 errno);
382 }
383
384 ATF_TC_WITHOUT_HEAD(rename_to_anon);
ATF_TC_BODY(rename_to_anon,tc)385 ATF_TC_BODY(rename_to_anon, tc)
386 {
387 int rc;
388
389 gen_test_path();
390 rc = shm_rename(test_path, SHM_ANON, 0);
391 if (rc != -1)
392 atf_tc_fail("shm_rename to SHM_ANON succeeded unexpectedly");
393 }
394
395 ATF_TC_WITHOUT_HEAD(rename_to_replace);
ATF_TC_BODY(rename_to_replace,tc)396 ATF_TC_BODY(rename_to_replace, tc)
397 {
398 char expected_value;
399 int fd;
400 int fd2;
401
402 // Some contents we can verify later
403 expected_value = 'g';
404
405 gen_test_path();
406 fd = scribble_object(test_path, expected_value);
407 close(fd);
408
409 // Give the other some different value so we can detect success
410 gen_test_path2();
411 fd2 = scribble_object(test_path2, 'h');
412 close(fd2);
413
414 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2, 0) == 0,
415 "shm_rename failed; errno=%d", errno);
416
417 // Read back renamed; verify contents
418 verify_object(test_path2, expected_value);
419 }
420
421 ATF_TC_WITHOUT_HEAD(rename_to_noreplace);
ATF_TC_BODY(rename_to_noreplace,tc)422 ATF_TC_BODY(rename_to_noreplace, tc)
423 {
424 char expected_value_from;
425 char expected_value_to;
426 int fd_from;
427 int fd_to;
428 int rc;
429
430 // Some contents we can verify later
431 expected_value_from = 'g';
432 gen_test_path();
433 fd_from = scribble_object(test_path, expected_value_from);
434 close(fd_from);
435
436 // Give the other some different value so we can detect success
437 expected_value_to = 'h';
438 gen_test_path2();
439 fd_to = scribble_object(test_path2, expected_value_to);
440 close(fd_to);
441
442 rc = shm_rename(test_path, test_path2, SHM_RENAME_NOREPLACE);
443 ATF_REQUIRE_MSG((rc == -1) && (errno == EEXIST),
444 "shm_rename didn't fail as expected; errno: %d; return: %d", errno,
445 rc);
446
447 // Read back renamed; verify contents
448 verify_object(test_path2, expected_value_to);
449 }
450
451 ATF_TC_WITHOUT_HEAD(rename_to_exchange);
ATF_TC_BODY(rename_to_exchange,tc)452 ATF_TC_BODY(rename_to_exchange, tc)
453 {
454 char expected_value_from;
455 char expected_value_to;
456 int fd_from;
457 int fd_to;
458
459 // Some contents we can verify later
460 expected_value_from = 'g';
461 gen_test_path();
462 fd_from = scribble_object(test_path, expected_value_from);
463 close(fd_from);
464
465 // Give the other some different value so we can detect success
466 expected_value_to = 'h';
467 gen_test_path2();
468 fd_to = scribble_object(test_path2, expected_value_to);
469 close(fd_to);
470
471 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2,
472 SHM_RENAME_EXCHANGE) == 0,
473 "shm_rename failed; errno=%d", errno);
474
475 // Read back renamed; verify contents
476 verify_object(test_path, expected_value_to);
477 verify_object(test_path2, expected_value_from);
478 }
479
480 ATF_TC_WITHOUT_HEAD(rename_to_exchange_nonexisting);
ATF_TC_BODY(rename_to_exchange_nonexisting,tc)481 ATF_TC_BODY(rename_to_exchange_nonexisting, tc)
482 {
483 char expected_value_from;
484 int fd_from;
485
486 // Some contents we can verify later
487 expected_value_from = 'g';
488 gen_test_path();
489 fd_from = scribble_object(test_path, expected_value_from);
490 close(fd_from);
491
492 gen_test_path2();
493
494 ATF_REQUIRE_MSG(shm_rename(test_path, test_path2,
495 SHM_RENAME_EXCHANGE) == 0,
496 "shm_rename failed; errno=%d", errno);
497
498 // Read back renamed; verify contents
499 verify_object(test_path2, expected_value_from);
500 }
501
502 ATF_TC_WITHOUT_HEAD(rename_to_self);
ATF_TC_BODY(rename_to_self,tc)503 ATF_TC_BODY(rename_to_self, tc)
504 {
505 int fd;
506 char expected_value;
507
508 expected_value = 't';
509
510 gen_test_path();
511 fd = scribble_object(test_path, expected_value);
512 close(fd);
513
514 ATF_REQUIRE_MSG(shm_rename(test_path, test_path, 0) == 0,
515 "shm_rename failed; errno=%d", errno);
516
517 verify_object(test_path, expected_value);
518 }
519
520 ATF_TC_WITHOUT_HEAD(rename_bad_flag);
ATF_TC_BODY(rename_bad_flag,tc)521 ATF_TC_BODY(rename_bad_flag, tc)
522 {
523 int fd;
524 int rc;
525
526 /* Make sure we don't fail out due to ENOENT */
527 gen_test_path();
528 gen_test_path2();
529 fd = scribble_object(test_path, 'd');
530 close(fd);
531 fd = scribble_object(test_path2, 'd');
532 close(fd);
533
534 /*
535 * Note: if we end up with enough flags that we use all the bits,
536 * then remove this test completely.
537 */
538 rc = shm_rename(test_path, test_path2, INT_MIN);
539 ATF_REQUIRE_MSG((rc == -1) && (errno == EINVAL),
540 "shm_rename should have failed with EINVAL; got: return=%d, "
541 "errno=%d", rc, errno);
542 }
543
544 ATF_TC_WITHOUT_HEAD(reopen_object);
ATF_TC_BODY(reopen_object,tc)545 ATF_TC_BODY(reopen_object, tc)
546 {
547 char *page;
548 int fd, pagesize;
549
550 ATF_REQUIRE(0 < (pagesize = getpagesize()));
551
552 gen_test_path();
553 fd = scribble_object(test_path, '1');
554 close(fd);
555
556 fd = shm_open(test_path, O_RDONLY, 0777);
557 if (fd < 0)
558 atf_tc_fail("shm_open(2) failed; errno=%d", errno);
559
560 page = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd, 0);
561 if (page == MAP_FAILED)
562 atf_tc_fail("mmap(2) failed; errno=%d", errno);
563
564 if (page[0] != '1')
565 atf_tc_fail("missing data ('%c' != '1')", page[0]);
566
567 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
568 errno);
569 close(fd);
570 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
571 "shm_unlink failed; errno=%d", errno);
572 }
573
574 ATF_TC_WITHOUT_HEAD(readonly_mmap_write);
ATF_TC_BODY(readonly_mmap_write,tc)575 ATF_TC_BODY(readonly_mmap_write, tc)
576 {
577 char *page;
578 int fd, pagesize;
579
580 ATF_REQUIRE(0 < (pagesize = getpagesize()));
581
582 gen_test_path();
583
584 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
585 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
586
587 /* PROT_WRITE should fail with EACCES. */
588 page = mmap(0, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
589 if (page != MAP_FAILED)
590 atf_tc_fail("mmap(PROT_WRITE) succeeded unexpectedly");
591
592 if (errno != EACCES)
593 atf_tc_fail("mmap(PROT_WRITE) didn't fail with EACCES; "
594 "errno=%d", errno);
595
596 close(fd);
597 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
598 "shm_unlink failed; errno=%d", errno);
599 }
600
601 ATF_TC_WITHOUT_HEAD(open_after_link);
ATF_TC_BODY(open_after_link,tc)602 ATF_TC_BODY(open_after_link, tc)
603 {
604 int fd;
605
606 gen_test_path();
607
608 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0777);
609 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
610 close(fd);
611
612 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1, "shm_unlink failed: %d",
613 errno);
614
615 shm_open_should_fail(test_path, O_RDONLY, 0777, ENOENT);
616 }
617
618 ATF_TC_WITHOUT_HEAD(open_invalid_path);
ATF_TC_BODY(open_invalid_path,tc)619 ATF_TC_BODY(open_invalid_path, tc)
620 {
621
622 shm_open_should_fail("blah", O_RDONLY, 0777, EINVAL);
623 }
624
625 ATF_TC_WITHOUT_HEAD(open_write_only);
ATF_TC_BODY(open_write_only,tc)626 ATF_TC_BODY(open_write_only, tc)
627 {
628
629 gen_test_path();
630
631 shm_open_should_fail(test_path, O_WRONLY, 0777, EINVAL);
632 }
633
634 ATF_TC_WITHOUT_HEAD(open_extra_flags);
ATF_TC_BODY(open_extra_flags,tc)635 ATF_TC_BODY(open_extra_flags, tc)
636 {
637
638 gen_test_path();
639
640 shm_open_should_fail(test_path, O_RDONLY | O_DIRECT, 0777, EINVAL);
641 }
642
643 ATF_TC_WITHOUT_HEAD(open_anon);
ATF_TC_BODY(open_anon,tc)644 ATF_TC_BODY(open_anon, tc)
645 {
646 int fd;
647
648 fd = shm_open(SHM_ANON, O_RDWR, 0777);
649 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
650 close(fd);
651 }
652
653 ATF_TC_WITHOUT_HEAD(open_anon_readonly);
ATF_TC_BODY(open_anon_readonly,tc)654 ATF_TC_BODY(open_anon_readonly, tc)
655 {
656
657 shm_open_should_fail(SHM_ANON, O_RDONLY, 0777, EINVAL);
658 }
659
660 ATF_TC_WITHOUT_HEAD(open_bad_path_pointer);
ATF_TC_BODY(open_bad_path_pointer,tc)661 ATF_TC_BODY(open_bad_path_pointer, tc)
662 {
663
664 shm_open_should_fail((char *)1024, O_RDONLY, 0777, EFAULT);
665 }
666
667 ATF_TC_WITHOUT_HEAD(open_path_too_long);
ATF_TC_BODY(open_path_too_long,tc)668 ATF_TC_BODY(open_path_too_long, tc)
669 {
670 char *page;
671
672 page = malloc(MAXPATHLEN + 1);
673 memset(page, 'a', MAXPATHLEN);
674 page[MAXPATHLEN] = '\0';
675 shm_open_should_fail(page, O_RDONLY, 0777, ENAMETOOLONG);
676 free(page);
677 }
678
679 ATF_TC_WITHOUT_HEAD(open_nonexisting_object);
ATF_TC_BODY(open_nonexisting_object,tc)680 ATF_TC_BODY(open_nonexisting_object, tc)
681 {
682
683 shm_open_should_fail("/notreallythere", O_RDONLY, 0777, ENOENT);
684 }
685
686 ATF_TC_WITHOUT_HEAD(open_create_existing_object);
ATF_TC_BODY(open_create_existing_object,tc)687 ATF_TC_BODY(open_create_existing_object, tc)
688 {
689 int fd;
690
691 gen_test_path();
692
693 fd = shm_open(test_path, O_RDONLY|O_CREAT, 0777);
694 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
695 close(fd);
696
697 shm_open_should_fail(test_path, O_RDONLY|O_CREAT|O_EXCL,
698 0777, EEXIST);
699
700 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
701 "shm_unlink failed; errno=%d", errno);
702 }
703
704 ATF_TC_WITHOUT_HEAD(trunc_resets_object);
ATF_TC_BODY(trunc_resets_object,tc)705 ATF_TC_BODY(trunc_resets_object, tc)
706 {
707 struct stat sb;
708 int fd;
709
710 gen_test_path();
711
712 /* Create object and set size to 1024. */
713 fd = shm_open(test_path, O_RDWR | O_CREAT, 0777);
714 ATF_REQUIRE_MSG(fd >= 0, "shm_open(1) failed; errno=%d", errno);
715 ATF_REQUIRE_MSG(ftruncate(fd, 1024) != -1,
716 "ftruncate failed; errno=%d", errno);
717 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
718 "fstat(1) failed; errno=%d", errno);
719 ATF_REQUIRE_MSG(sb.st_size == 1024, "size %d != 1024", (int)sb.st_size);
720 close(fd);
721
722 /* Open with O_TRUNC which should reset size to 0. */
723 fd = shm_open(test_path, O_RDWR | O_TRUNC, 0777);
724 ATF_REQUIRE_MSG(fd >= 0, "shm_open(2) failed; errno=%d", errno);
725 ATF_REQUIRE_MSG(fstat(fd, &sb) != -1,
726 "fstat(2) failed; errno=%d", errno);
727 ATF_REQUIRE_MSG(sb.st_size == 0,
728 "size was not 0 after truncation: %d", (int)sb.st_size);
729 close(fd);
730 ATF_REQUIRE_MSG(shm_unlink(test_path) != -1,
731 "shm_unlink failed; errno=%d", errno);
732 }
733
734 ATF_TC_WITHOUT_HEAD(unlink_bad_path_pointer);
ATF_TC_BODY(unlink_bad_path_pointer,tc)735 ATF_TC_BODY(unlink_bad_path_pointer, tc)
736 {
737
738 shm_unlink_should_fail((char *)1024, EFAULT);
739 }
740
741 ATF_TC_WITHOUT_HEAD(unlink_path_too_long);
ATF_TC_BODY(unlink_path_too_long,tc)742 ATF_TC_BODY(unlink_path_too_long, tc)
743 {
744 char *page;
745
746 page = malloc(MAXPATHLEN + 1);
747 memset(page, 'a', MAXPATHLEN);
748 page[MAXPATHLEN] = '\0';
749 shm_unlink_should_fail(page, ENAMETOOLONG);
750 free(page);
751 }
752
753 ATF_TC_WITHOUT_HEAD(object_resize);
ATF_TC_BODY(object_resize,tc)754 ATF_TC_BODY(object_resize, tc)
755 {
756 pid_t pid;
757 struct stat sb;
758 char *page;
759 int fd, pagesize, status;
760
761 ATF_REQUIRE(0 < (pagesize = getpagesize()));
762
763 /* Start off with a size of a single page. */
764 fd = shm_open(SHM_ANON, O_CREAT|O_RDWR, 0777);
765 if (fd < 0)
766 atf_tc_fail("shm_open failed; errno=%d", errno);
767
768 if (ftruncate(fd, pagesize) < 0)
769 atf_tc_fail("ftruncate(1) failed; errno=%d", errno);
770
771 if (fstat(fd, &sb) < 0)
772 atf_tc_fail("fstat(1) failed; errno=%d", errno);
773
774 if (sb.st_size != pagesize)
775 atf_tc_fail("first resize failed (%d != %d)",
776 (int)sb.st_size, pagesize);
777
778 /* Write a '1' to the first byte. */
779 page = mmap(0, pagesize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
780 if (page == MAP_FAILED)
781 atf_tc_fail("mmap(1)");
782
783 page[0] = '1';
784
785 ATF_REQUIRE_MSG(munmap(page, pagesize) == 0, "munmap failed; errno=%d",
786 errno);
787
788 /* Grow the object to 2 pages. */
789 if (ftruncate(fd, pagesize * 2) < 0)
790 atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
791
792 if (fstat(fd, &sb) < 0)
793 atf_tc_fail("fstat(2) failed; errno=%d", errno);
794
795 if (sb.st_size != pagesize * 2)
796 atf_tc_fail("second resize failed (%d != %d)",
797 (int)sb.st_size, pagesize * 2);
798
799 /* Check for '1' at the first byte. */
800 page = mmap(0, pagesize * 2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
801 if (page == MAP_FAILED)
802 atf_tc_fail("mmap(2) failed; errno=%d", errno);
803
804 if (page[0] != '1')
805 atf_tc_fail("'%c' != '1'", page[0]);
806
807 /* Write a '2' at the start of the second page. */
808 page[pagesize] = '2';
809
810 /* Shrink the object back to 1 page. */
811 if (ftruncate(fd, pagesize) < 0)
812 atf_tc_fail("ftruncate(3) failed; errno=%d", errno);
813
814 if (fstat(fd, &sb) < 0)
815 atf_tc_fail("fstat(3) failed; errno=%d", errno);
816
817 if (sb.st_size != pagesize)
818 atf_tc_fail("third resize failed (%d != %d)",
819 (int)sb.st_size, pagesize);
820
821 /*
822 * Fork a child process to make sure the second page is no
823 * longer valid.
824 */
825 pid = fork();
826 if (pid == -1)
827 atf_tc_fail("fork failed; errno=%d", errno);
828
829 if (pid == 0) {
830 struct rlimit lim;
831 char c;
832
833 /* Don't generate a core dump. */
834 ATF_REQUIRE(getrlimit(RLIMIT_CORE, &lim) == 0);
835 lim.rlim_cur = 0;
836 ATF_REQUIRE(setrlimit(RLIMIT_CORE, &lim) == 0);
837
838 /*
839 * The previous ftruncate(2) shrunk the backing object
840 * so that this address is no longer valid, so reading
841 * from it should trigger a SIGBUS.
842 */
843 c = page[pagesize];
844 fprintf(stderr, "child: page 1: '%c'\n", c);
845 exit(0);
846 }
847
848 if (wait(&status) < 0)
849 atf_tc_fail("wait failed; errno=%d", errno);
850
851 if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS)
852 atf_tc_fail("child terminated with status %x", status);
853
854 /* Grow the object back to 2 pages. */
855 if (ftruncate(fd, pagesize * 2) < 0)
856 atf_tc_fail("ftruncate(2) failed; errno=%d", errno);
857
858 if (fstat(fd, &sb) < 0)
859 atf_tc_fail("fstat(2) failed; errno=%d", errno);
860
861 if (sb.st_size != pagesize * 2)
862 atf_tc_fail("fourth resize failed (%d != %d)",
863 (int)sb.st_size, pagesize);
864
865 /*
866 * Note that the mapping at 'page' for the second page is
867 * still valid, and now that the shm object has been grown
868 * back up to 2 pages, there is now memory backing this page
869 * so the read will work. However, the data should be zero
870 * rather than '2' as the old data was thrown away when the
871 * object was shrunk and the new pages when an object are
872 * grown are zero-filled.
873 */
874 if (page[pagesize] != 0)
875 atf_tc_fail("invalid data at %d: %x != 0",
876 pagesize, (int)page[pagesize]);
877
878 close(fd);
879 }
880
881 /* Signal handler which does nothing. */
882 static void
ignoreit(int sig __unused)883 ignoreit(int sig __unused)
884 {
885 ;
886 }
887
888 ATF_TC_WITHOUT_HEAD(shm_functionality_across_fork);
ATF_TC_BODY(shm_functionality_across_fork,tc)889 ATF_TC_BODY(shm_functionality_across_fork, tc)
890 {
891 char *cp, c;
892 int error, desc, rv;
893 long scval;
894 sigset_t ss;
895 struct sigaction sa;
896 void *region;
897 size_t i, psize;
898
899 #ifndef _POSIX_SHARED_MEMORY_OBJECTS
900 printf("_POSIX_SHARED_MEMORY_OBJECTS is undefined\n");
901 #else
902 printf("_POSIX_SHARED_MEMORY_OBJECTS is defined as %ld\n",
903 (long)_POSIX_SHARED_MEMORY_OBJECTS - 0);
904 if (_POSIX_SHARED_MEMORY_OBJECTS - 0 == -1)
905 printf("***Indicates this feature may be unsupported!\n");
906 #endif
907 errno = 0;
908 scval = sysconf(_SC_SHARED_MEMORY_OBJECTS);
909 if (scval == -1 && errno != 0) {
910 atf_tc_fail("sysconf(_SC_SHARED_MEMORY_OBJECTS) failed; "
911 "errno=%d", errno);
912 } else {
913 printf("sysconf(_SC_SHARED_MEMORY_OBJECTS) returns %ld\n",
914 scval);
915 if (scval == -1)
916 printf("***Indicates this feature is unsupported!\n");
917 }
918
919 errno = 0;
920 scval = sysconf(_SC_PAGESIZE);
921 if (scval == -1 && errno != 0) {
922 atf_tc_fail("sysconf(_SC_PAGESIZE) failed; errno=%d", errno);
923 } else if (scval <= 0) {
924 fprintf(stderr, "bogus return from sysconf(_SC_PAGESIZE): %ld",
925 scval);
926 psize = 4096;
927 } else {
928 printf("sysconf(_SC_PAGESIZE) returns %ld\n", scval);
929 psize = scval;
930 }
931
932 gen_test_path();
933 desc = shm_open(test_path, O_EXCL | O_CREAT | O_RDWR, 0600);
934
935 ATF_REQUIRE_MSG(desc >= 0, "shm_open failed; errno=%d", errno);
936 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
937 "shm_unlink failed; errno=%d", errno);
938 ATF_REQUIRE_MSG(ftruncate(desc, (off_t)psize) != -1,
939 "ftruncate failed; errno=%d", errno);
940
941 region = mmap(NULL, psize, PROT_READ | PROT_WRITE, MAP_SHARED, desc, 0);
942 ATF_REQUIRE_MSG(region != MAP_FAILED, "mmap failed; errno=%d", errno);
943 memset(region, '\377', psize);
944
945 sa.sa_flags = 0;
946 sa.sa_handler = ignoreit;
947 sigemptyset(&sa.sa_mask);
948 ATF_REQUIRE_MSG(sigaction(SIGUSR1, &sa, (struct sigaction *)0) == 0,
949 "sigaction failed; errno=%d", errno);
950
951 sigemptyset(&ss);
952 sigaddset(&ss, SIGUSR1);
953 ATF_REQUIRE_MSG(sigprocmask(SIG_BLOCK, &ss, (sigset_t *)0) == 0,
954 "sigprocmask failed; errno=%d", errno);
955
956 rv = fork();
957 ATF_REQUIRE_MSG(rv != -1, "fork failed; errno=%d", errno);
958 if (rv == 0) {
959 sigemptyset(&ss);
960 sigsuspend(&ss);
961
962 for (cp = region; cp < (char *)region + psize; cp++) {
963 if (*cp != '\151')
964 _exit(1);
965 }
966 if (lseek(desc, 0, SEEK_SET) == -1)
967 _exit(1);
968 for (i = 0; i < psize; i++) {
969 error = read(desc, &c, 1);
970 if (c != '\151')
971 _exit(1);
972 }
973 _exit(0);
974 } else {
975 int status;
976
977 memset(region, '\151', psize - 2);
978 error = pwrite(desc, region, 2, psize - 2);
979 if (error != 2) {
980 if (error >= 0)
981 atf_tc_fail("short write; %d bytes written",
982 error);
983 else
984 atf_tc_fail("shmfd write");
985 }
986 kill(rv, SIGUSR1);
987 waitpid(rv, &status, 0);
988
989 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
990 printf("Functionality test successful\n");
991 } else if (WIFEXITED(status)) {
992 atf_tc_fail("Child process exited with status %d",
993 WEXITSTATUS(status));
994 } else {
995 atf_tc_fail("Child process terminated with %s",
996 strsignal(WTERMSIG(status)));
997 }
998 }
999
1000 ATF_REQUIRE_MSG(munmap(region, psize) == 0, "munmap failed; errno=%d",
1001 errno);
1002 shm_unlink(test_path);
1003 }
1004
1005 ATF_TC_WITHOUT_HEAD(cloexec);
ATF_TC_BODY(cloexec,tc)1006 ATF_TC_BODY(cloexec, tc)
1007 {
1008 int fd;
1009
1010 gen_test_path();
1011
1012 /* shm_open(2) is required to set FD_CLOEXEC */
1013 fd = shm_open(SHM_ANON, O_RDWR, 0777);
1014 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
1015 ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0);
1016 close(fd);
1017
1018 /* Also make sure that named shm is correct */
1019 fd = shm_open(test_path, O_CREAT | O_RDWR, 0600);
1020 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
1021 ATF_REQUIRE((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0);
1022 close(fd);
1023 }
1024
1025 ATF_TC_WITHOUT_HEAD(mode);
ATF_TC_BODY(mode,tc)1026 ATF_TC_BODY(mode, tc)
1027 {
1028 struct stat st;
1029 int fd;
1030 mode_t restore_mask;
1031
1032 gen_test_path();
1033
1034 /* Remove inhibitions from umask */
1035 restore_mask = umask(0);
1036 fd = shm_open(test_path, O_CREAT | O_RDWR, 0600);
1037 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
1038 ATF_REQUIRE(fstat(fd, &st) == 0);
1039 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0600);
1040 close(fd);
1041 ATF_REQUIRE(shm_unlink(test_path) == 0);
1042
1043 fd = shm_open(test_path, O_CREAT | O_RDWR, 0660);
1044 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
1045 ATF_REQUIRE(fstat(fd, &st) == 0);
1046 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0660);
1047 close(fd);
1048 ATF_REQUIRE(shm_unlink(test_path) == 0);
1049
1050 fd = shm_open(test_path, O_CREAT | O_RDWR, 0666);
1051 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
1052 ATF_REQUIRE(fstat(fd, &st) == 0);
1053 ATF_REQUIRE((st.st_mode & ACCESSPERMS) == 0666);
1054 close(fd);
1055 ATF_REQUIRE(shm_unlink(test_path) == 0);
1056
1057 umask(restore_mask);
1058 }
1059
1060 ATF_TC_WITHOUT_HEAD(fallocate);
ATF_TC_BODY(fallocate,tc)1061 ATF_TC_BODY(fallocate, tc)
1062 {
1063 struct stat st;
1064 int error, fd, sz;
1065
1066 /*
1067 * Primitive test case for posix_fallocate with shmd. Effectively
1068 * expected to work like a smarter ftruncate that will grow the region
1069 * as needed in a race-free way.
1070 */
1071 fd = shm_open(SHM_ANON, O_RDWR, 0666);
1072 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno=%d", errno);
1073 /* Set the initial size. */
1074 sz = 32;
1075 ATF_REQUIRE(ftruncate(fd, sz) == 0);
1076
1077 /* Now grow it. */
1078 error = 0;
1079 sz *= 2;
1080 ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz)) == 0,
1081 "posix_fallocate failed; error=%d", error);
1082 ATF_REQUIRE(fstat(fd, &st) == 0);
1083 ATF_REQUIRE(st.st_size == sz);
1084 /* Attempt to shrink it; should succeed, but not change the size. */
1085 ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, sz / 2)) == 0,
1086 "posix_fallocate failed; error=%d", error);
1087 ATF_REQUIRE(fstat(fd, &st) == 0);
1088 ATF_REQUIRE(st.st_size == sz);
1089 /* Grow it using an offset of sz and len of sz. */
1090 ATF_REQUIRE_MSG((error = posix_fallocate(fd, sz, sz)) == 0,
1091 "posix_fallocate failed; error=%d", error);
1092 ATF_REQUIRE(fstat(fd, &st) == 0);
1093 ATF_REQUIRE(st.st_size == sz * 2);
1094
1095 close(fd);
1096 }
1097
1098 ATF_TC_WITHOUT_HEAD(fspacectl);
ATF_TC_BODY(fspacectl,tc)1099 ATF_TC_BODY(fspacectl, tc)
1100 {
1101 struct spacectl_range range;
1102 off_t offset, length, shm_sz;
1103 size_t page_size;
1104 int fd, error;
1105
1106 page_size = getpagesize();
1107 shm_sz = shm_max_pages * page_size;
1108
1109 fd = shm_open("/testtest", O_RDWR | O_CREAT, 0666);
1110 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno:%d", errno);
1111 ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, shm_sz)) == 0,
1112 "posix_fallocate failed; error=%d", error);
1113
1114 /* Aligned fspacectl(fd, SPACECTL_DEALLOC, ...) */
1115 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1116 range.r_offset = offset = page_size;
1117 range.r_len = length = ((shm_max_pages - 1) * page_size) -
1118 range.r_offset;
1119 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1120 "Aligned fspacectl failed; errno=%d", errno);
1121 ATF_CHECK_MSG(check_content_dealloc(fd, offset, length, shm_sz) == 0,
1122 "Aligned fspacectl content checking failed");
1123
1124 /* Unaligned fspacectl(fd, SPACECTL_DEALLOC, ...) */
1125 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1126 range.r_offset = offset = page_size / 2;
1127 range.r_len = length = (shm_max_pages - 1) * page_size +
1128 (page_size / 2) - offset;
1129 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1130 "Unaligned fspacectl failed; errno=%d", errno);
1131 ATF_CHECK_MSG(check_content_dealloc(fd, offset, length, shm_sz) == 0,
1132 "Unaligned fspacectl content checking failed");
1133
1134 /* Aligned fspacectl(fd, SPACECTL_DEALLOC, ...) to OFF_MAX */
1135 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1136 range.r_offset = offset = page_size;
1137 range.r_len = length = OFF_MAX - offset;
1138 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1139 "Aligned fspacectl to OFF_MAX failed; errno=%d", errno);
1140 ATF_CHECK_MSG(check_content_dealloc(fd, offset, length, shm_sz) == 0,
1141 "Aligned fspacectl to OFF_MAX content checking failed");
1142
1143 /* Unaligned fspacectl(fd, SPACECTL_DEALLOC, ...) to OFF_MAX */
1144 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1145 range.r_offset = offset = page_size / 2;
1146 range.r_len = length = OFF_MAX - offset;
1147 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1148 "Unaligned fspacectl to OFF_MAX failed; errno=%d", errno);
1149 ATF_CHECK_MSG(check_content_dealloc(fd, offset, length, shm_sz) == 0,
1150 "Unaligned fspacectl to OFF_MAX content checking failed");
1151
1152 /* Aligned fspacectl(fd, SPACECTL_DEALLOC, ...) past shm_sz */
1153 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1154 range.r_offset = offset = page_size;
1155 range.r_len = length = (shm_max_pages + 1) * page_size - offset;
1156 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1157 "Aligned fspacectl past shm_sz failed; errno=%d", errno);
1158 ATF_CHECK_MSG(check_content_dealloc(fd, offset, length, shm_sz) == 0,
1159 "Aligned fspacectl past shm_sz content checking failed");
1160
1161 /* Unaligned fspacectl(fd, SPACECTL_DEALLOC, ...) past shm_sz */
1162 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1163 range.r_offset = offset = page_size / 2;
1164 range.r_len = length = (shm_max_pages + 1) * page_size - offset;
1165 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1166 "Unaligned fspacectl past shm_sz failed; errno=%d", errno);
1167 ATF_CHECK_MSG(check_content_dealloc(fd, offset, length, shm_sz) == 0,
1168 "Unaligned fspacectl past shm_sz content checking failed");
1169
1170 ATF_REQUIRE(close(fd) == 0);
1171 }
1172
1173 ATF_TC_WITHOUT_HEAD(accounting);
ATF_TC_BODY(accounting,tc)1174 ATF_TC_BODY(accounting, tc)
1175 {
1176 struct spacectl_range range;
1177 struct stat st;
1178 off_t shm_sz, len;
1179 size_t page_size;
1180 int fd, error;
1181
1182 page_size = getpagesize();
1183 shm_sz = shm_max_pages * page_size;
1184
1185 fd = shm_open("/testtest1", O_RDWR | O_CREAT, 0666);
1186 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; errno:%d", errno);
1187 ATF_REQUIRE_MSG((error = posix_fallocate(fd, 0, shm_sz)) == 0,
1188 "posix_fallocate failed; error=%d", error);
1189
1190 ATF_REQUIRE(shm_fill(fd, 0, shm_sz) == 0);
1191 ATF_REQUIRE(fstat(fd, &st) == 0);
1192 printf("blocks %jd shm_sz %jd\n", (uintmax_t)st.st_blocks,
1193 (uintmax_t)shm_sz);
1194 ATF_CHECK_EQ(DEV_BSIZE * st.st_blocks, (blkcnt_t)shm_sz);
1195
1196 range.r_offset = page_size;
1197 range.r_len = len = (shm_max_pages - 1) * page_size -
1198 range.r_offset;
1199 ATF_CHECK_MSG(fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == 0,
1200 "SPACECTL_DEALLOC failed; errno=%d", errno);
1201 ATF_REQUIRE(fstat(fd, &st) == 0);
1202 printf("blocks %jd shm_sz %jd len %jd\n", (uintmax_t)st.st_blocks,
1203 (uintmax_t)shm_sz, (uintmax_t)len);
1204 ATF_CHECK_EQ(DEV_BSIZE * st.st_blocks, (blkcnt_t)(shm_sz - len));
1205
1206 ATF_REQUIRE(close(fd) == 0);
1207 }
1208
1209 ATF_TC_WITHOUT_HEAD(mmap_prot);
ATF_TC_BODY(mmap_prot,tc)1210 ATF_TC_BODY(mmap_prot, tc)
1211 {
1212 void *p;
1213 int fd, pagesize;
1214
1215 ATF_REQUIRE((pagesize = getpagesize()) > 0);
1216
1217 gen_test_path();
1218 fd = shm_open(test_path, O_RDONLY | O_CREAT, 0644);
1219 ATF_REQUIRE(fd >= 0);
1220
1221 p = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, fd, 0);
1222 ATF_REQUIRE(p != MAP_FAILED);
1223 ATF_REQUIRE(munmap(p, pagesize) == 0);
1224 p = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1225 ATF_REQUIRE_ERRNO(EACCES, p == MAP_FAILED);
1226 p = mmap(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
1227 ATF_REQUIRE(p != MAP_FAILED);
1228 ATF_REQUIRE(munmap(p, pagesize) == 0);
1229
1230 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
1231 "shm_unlink failed; errno=%d", errno);
1232 ATF_REQUIRE_MSG(close(fd) == 0,
1233 "close failed; errno=%d", errno);
1234 }
1235
1236 static int
shm_open_large(int psind,int policy,size_t sz)1237 shm_open_large(int psind, int policy, size_t sz)
1238 {
1239 int error, fd;
1240
1241 fd = shm_create_largepage(SHM_ANON, O_CREAT | O_RDWR, psind, policy, 0);
1242 if (fd < 0 && errno == ENOTTY)
1243 atf_tc_skip("no large page support");
1244 ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; errno=%d", errno);
1245
1246 error = ftruncate(fd, sz);
1247 if (error != 0 && errno == ENOMEM)
1248 /*
1249 * The test system might not have enough memory to accommodate
1250 * the request.
1251 */
1252 atf_tc_skip("failed to allocate %zu-byte superpage", sz);
1253 ATF_REQUIRE_MSG(error == 0, "ftruncate failed; errno=%d", errno);
1254
1255 return (fd);
1256 }
1257
1258 ATF_TC_WITHOUT_HEAD(largepage_basic);
ATF_TC_BODY(largepage_basic,tc)1259 ATF_TC_BODY(largepage_basic, tc)
1260 {
1261 char *zeroes;
1262 char *addr, *vec;
1263 size_t ps[MAXPAGESIZES];
1264 int error, fd, pscnt;
1265
1266 pscnt = pagesizes(ps, true);
1267 zeroes = calloc(1, ps[0]);
1268 ATF_REQUIRE(zeroes != NULL);
1269 for (int i = 1; i < pscnt; i++) {
1270 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1271
1272 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1273 0);
1274 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1275 "mmap(%zu bytes) failed; errno=%d", ps[i], errno);
1276 ATF_REQUIRE_MSG(((uintptr_t)addr & (ps[i] - 1)) == 0,
1277 "mmap(%zu bytes) returned unaligned mapping; addr=%p",
1278 ps[i], addr);
1279
1280 /* Force a page fault. */
1281 *(volatile char *)addr = 0;
1282
1283 vec = malloc(ps[i] / ps[0]);
1284 ATF_REQUIRE(vec != NULL);
1285 error = mincore(addr, ps[i], vec);
1286 ATF_REQUIRE_MSG(error == 0, "mincore failed; errno=%d", errno);
1287
1288 /* Verify that all pages in the run are mapped. */
1289 for (size_t p = 0; p < ps[i] / ps[0]; p++) {
1290 ATF_REQUIRE_MSG((vec[p] & MINCORE_INCORE) != 0,
1291 "page %zu is not mapped", p);
1292 ATF_REQUIRE_MSG((vec[p] & MINCORE_SUPER) ==
1293 MINCORE_PSIND(i),
1294 "page %zu is not in a %zu-byte superpage",
1295 p, ps[i]);
1296 }
1297
1298 /* Validate zeroing. */
1299 for (size_t p = 0; p < ps[i] / ps[0]; p++) {
1300 ATF_REQUIRE_MSG(memcmp(addr + p * ps[0], zeroes,
1301 ps[0]) == 0, "page %zu miscompare", p);
1302 }
1303
1304 free(vec);
1305 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1306 ATF_REQUIRE(close(fd) == 0);
1307 }
1308
1309 free(zeroes);
1310 }
1311
1312 extern int __sys_shm_open2(const char *, int, mode_t, int, const char *);
1313
1314 ATF_TC_WITHOUT_HEAD(largepage_config);
ATF_TC_BODY(largepage_config,tc)1315 ATF_TC_BODY(largepage_config, tc)
1316 {
1317 struct shm_largepage_conf lpc;
1318 char *addr, *buf;
1319 size_t ps[MAXPAGESIZES + 1]; /* silence warnings if MAXPAGESIZES == 1 */
1320 int error, fd;
1321
1322 (void)pagesizes(ps, true);
1323
1324 fd = shm_open(SHM_ANON, O_CREAT | O_RDWR, 0);
1325 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; error=%d", errno);
1326
1327 /*
1328 * Configure a large page policy for an object created without
1329 * SHM_LARGEPAGE.
1330 */
1331 lpc.psind = 1;
1332 lpc.alloc_policy = SHM_LARGEPAGE_ALLOC_DEFAULT;
1333 error = ioctl(fd, FIOSSHMLPGCNF, &lpc);
1334 ATF_REQUIRE(error != 0);
1335 ATF_REQUIRE_MSG(errno == ENOTTY, "ioctl(FIOSSHMLPGCNF) returned %d",
1336 errno);
1337 ATF_REQUIRE(close(fd) == 0);
1338
1339 /*
1340 * Create a largepage object and try to use it without actually
1341 * configuring anything.
1342 */
1343 fd = __sys_shm_open2(SHM_ANON, O_CREAT | O_RDWR, 0, SHM_LARGEPAGE,
1344 NULL);
1345 if (fd < 0 && errno == ENOTTY)
1346 atf_tc_skip("no large page support");
1347 ATF_REQUIRE_MSG(fd >= 0, "shm_open2 failed; error=%d", errno);
1348
1349 error = ftruncate(fd, ps[1]);
1350 ATF_REQUIRE(error != 0);
1351 ATF_REQUIRE_MSG(errno == EINVAL, "ftruncate returned %d", errno);
1352
1353 addr = mmap(NULL, ps[1], PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1354 ATF_REQUIRE(addr == MAP_FAILED);
1355 ATF_REQUIRE_MSG(errno == EINVAL, "mmap returned %d", errno);
1356 addr = mmap(NULL, 0, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1357 ATF_REQUIRE(addr == MAP_FAILED);
1358 ATF_REQUIRE_MSG(errno == EINVAL, "mmap returned %d", errno);
1359
1360 buf = calloc(1, ps[0]);
1361 ATF_REQUIRE(buf != NULL);
1362 ATF_REQUIRE(write(fd, buf, ps[0]) == -1);
1363 ATF_REQUIRE_MSG(errno == EINVAL, "write returned %d", errno);
1364 free(buf);
1365 buf = calloc(1, ps[1]);
1366 ATF_REQUIRE(buf != NULL);
1367 ATF_REQUIRE(write(fd, buf, ps[1]) == -1);
1368 ATF_REQUIRE_MSG(errno == EINVAL, "write returned %d", errno);
1369 free(buf);
1370
1371 error = posix_fallocate(fd, 0, ps[0]);
1372 ATF_REQUIRE_MSG(error == EINVAL, "posix_fallocate returned %d", error);
1373
1374 ATF_REQUIRE(close(fd) == 0);
1375 }
1376
1377 ATF_TC_WITHOUT_HEAD(largepage_fspacectl);
ATF_TC_BODY(largepage_fspacectl,tc)1378 ATF_TC_BODY(largepage_fspacectl, tc)
1379 {
1380 struct spacectl_range range;
1381 size_t ps[MAXPAGESIZES];
1382 int fd, pscnt;
1383
1384 pscnt = pagesizes(ps, true);
1385
1386 for (int i = 1; i < pscnt; i++) {
1387 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1388
1389 range.r_offset = 0;
1390 range.r_len = ps[i];
1391 ATF_REQUIRE_ERRNO(ENOTSUP,
1392 fspacectl(fd, SPACECTL_DEALLOC, &range, 0, &range) == -1);
1393
1394 ATF_REQUIRE(close(fd) == 0);
1395 }
1396 }
1397
1398 ATF_TC_WITHOUT_HEAD(largepage_mmap);
ATF_TC_BODY(largepage_mmap,tc)1399 ATF_TC_BODY(largepage_mmap, tc)
1400 {
1401 char *addr, *addr1, *vec;
1402 size_t ps[MAXPAGESIZES];
1403 int fd, pscnt;
1404
1405 pscnt = pagesizes(ps, true);
1406 for (int i = 1; i < pscnt; i++) {
1407 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1408
1409 /* For mincore(). */
1410 vec = malloc(ps[i]);
1411 ATF_REQUIRE(vec != NULL);
1412
1413 /*
1414 * Wrong mapping size.
1415 */
1416 addr = mmap(NULL, ps[i - 1], PROT_READ | PROT_WRITE, MAP_SHARED,
1417 fd, 0);
1418 ATF_REQUIRE_MSG(addr == MAP_FAILED,
1419 "mmap(%zu bytes) succeeded", ps[i - 1]);
1420 ATF_REQUIRE_MSG(errno == EINVAL,
1421 "mmap(%zu bytes) failed; error=%d", ps[i - 1], errno);
1422
1423 /*
1424 * Fixed mappings.
1425 */
1426 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1427 0);
1428 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1429 "mmap(%zu bytes) failed; errno=%d", ps[i], errno);
1430 ATF_REQUIRE_MSG(((uintptr_t)addr & (ps[i] - 1)) == 0,
1431 "mmap(%zu bytes) returned unaligned mapping; addr=%p",
1432 ps[i], addr);
1433
1434 /* Try mapping a small page with anonymous memory. */
1435 addr1 = mmap(addr, ps[i - 1], PROT_READ | PROT_WRITE,
1436 MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1437 ATF_REQUIRE_MSG(addr1 == MAP_FAILED,
1438 "anon mmap(%zu bytes) succeeded", ps[i - 1]);
1439 ATF_REQUIRE_MSG(errno == EINVAL, "mmap returned %d", errno);
1440
1441 /* Check MAP_EXCL when creating a second largepage mapping. */
1442 addr1 = mmap(addr, ps[i], PROT_READ | PROT_WRITE,
1443 MAP_SHARED | MAP_FIXED | MAP_EXCL, fd, 0);
1444 ATF_REQUIRE_MSG(addr1 == MAP_FAILED,
1445 "mmap(%zu bytes) succeeded", ps[i]);
1446 /* XXX wrong errno */
1447 ATF_REQUIRE_MSG(errno == ENOSPC, "mmap returned %d", errno);
1448
1449 /* Overwrite a largepage mapping with a lagepage mapping. */
1450 addr1 = mmap(addr, ps[i], PROT_READ | PROT_WRITE,
1451 MAP_SHARED | MAP_FIXED, fd, 0);
1452 ATF_REQUIRE_MSG(addr1 != MAP_FAILED,
1453 "mmap(%zu bytes) failed; errno=%d", ps[i], errno);
1454 ATF_REQUIRE_MSG(addr == addr1,
1455 "mmap(%zu bytes) moved from %p to %p", ps[i], addr, addr1);
1456
1457 ATF_REQUIRE(munmap(addr, ps[i] == 0));
1458
1459 /* Clobber an anonymous mapping with a superpage. */
1460 addr1 = mmap(NULL, ps[i], PROT_READ | PROT_WRITE,
1461 MAP_ANON | MAP_PRIVATE | MAP_ALIGNED(ffsl(ps[i]) - 1), -1,
1462 0);
1463 ATF_REQUIRE_MSG(addr1 != MAP_FAILED,
1464 "mmap failed; error=%d", errno);
1465 *(volatile char *)addr1 = '\0';
1466 addr = mmap(addr1, ps[i], PROT_READ | PROT_WRITE,
1467 MAP_SHARED | MAP_FIXED, fd, 0);
1468 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1469 "mmap failed; error=%d", errno);
1470 ATF_REQUIRE_MSG(addr == addr1,
1471 "mmap disobeyed MAP_FIXED, %p %p", addr, addr1);
1472 *(volatile char *)addr = 0; /* fault */
1473 ATF_REQUIRE(mincore(addr, ps[i], vec) == 0);
1474 for (size_t p = 0; p < ps[i] / ps[0]; p++) {
1475 ATF_REQUIRE_MSG((vec[p] & MINCORE_INCORE) != 0,
1476 "page %zu is not resident", p);
1477 ATF_REQUIRE_MSG((vec[p] & MINCORE_SUPER) ==
1478 MINCORE_PSIND(i),
1479 "page %zu is not resident", p);
1480 }
1481
1482 /*
1483 * Copy-on-write mappings are not permitted.
1484 */
1485 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_PRIVATE,
1486 fd, 0);
1487 ATF_REQUIRE_MSG(addr == MAP_FAILED,
1488 "mmap(%zu bytes) succeeded", ps[i]);
1489
1490 ATF_REQUIRE(close(fd) == 0);
1491 }
1492 }
1493
1494 ATF_TC_WITHOUT_HEAD(largepage_munmap);
ATF_TC_BODY(largepage_munmap,tc)1495 ATF_TC_BODY(largepage_munmap, tc)
1496 {
1497 char *addr;
1498 size_t ps[MAXPAGESIZES], ps1;
1499 int fd, pscnt;
1500
1501 pscnt = pagesizes(ps, true);
1502 for (int i = 1; i < pscnt; i++) {
1503 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1504 ps1 = ps[i - 1];
1505
1506 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1507 0);
1508 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1509 "mmap(%zu bytes) failed; errno=%d", ps[i], errno);
1510
1511 /* Try several unaligned munmap() requests. */
1512 ATF_REQUIRE(munmap(addr, ps1) != 0);
1513 ATF_REQUIRE_MSG(errno == EINVAL,
1514 "unexpected error %d from munmap", errno);
1515 ATF_REQUIRE(munmap(addr, ps[i] - ps1));
1516 ATF_REQUIRE_MSG(errno == EINVAL,
1517 "unexpected error %d from munmap", errno);
1518 ATF_REQUIRE(munmap(addr + ps1, ps1) != 0);
1519 ATF_REQUIRE_MSG(errno == EINVAL,
1520 "unexpected error %d from munmap", errno);
1521 ATF_REQUIRE(munmap(addr, 0));
1522 ATF_REQUIRE_MSG(errno == EINVAL,
1523 "unexpected error %d from munmap", errno);
1524
1525 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1526 ATF_REQUIRE(close(fd) == 0);
1527 }
1528 }
1529
1530 static void
largepage_madvise(char * addr,size_t sz,int advice,int error)1531 largepage_madvise(char *addr, size_t sz, int advice, int error)
1532 {
1533 if (error == 0) {
1534 ATF_REQUIRE_MSG(madvise(addr, sz, advice) == 0,
1535 "madvise(%zu, %d) failed; error=%d", sz, advice, errno);
1536 } else {
1537 ATF_REQUIRE_MSG(madvise(addr, sz, advice) != 0,
1538 "madvise(%zu, %d) succeeded", sz, advice);
1539 ATF_REQUIRE_MSG(errno == error,
1540 "unexpected error %d from madvise(%zu, %d)",
1541 errno, sz, advice);
1542 }
1543 }
1544
1545 ATF_TC_WITHOUT_HEAD(largepage_madvise);
ATF_TC_BODY(largepage_madvise,tc)1546 ATF_TC_BODY(largepage_madvise, tc)
1547 {
1548 char *addr;
1549 size_t ps[MAXPAGESIZES];
1550 int fd, pscnt;
1551
1552 pscnt = pagesizes(ps, true);
1553 for (int i = 1; i < pscnt; i++) {
1554 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1555 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1556 0);
1557 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1558 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1559
1560 memset(addr, 0, ps[i]);
1561
1562 /* Advice that requires clipping. */
1563 largepage_madvise(addr, ps[0], MADV_NORMAL, EINVAL);
1564 largepage_madvise(addr, ps[i], MADV_NORMAL, 0);
1565 largepage_madvise(addr, ps[0], MADV_RANDOM, EINVAL);
1566 largepage_madvise(addr, ps[i], MADV_RANDOM, 0);
1567 largepage_madvise(addr, ps[0], MADV_SEQUENTIAL, EINVAL);
1568 largepage_madvise(addr, ps[i], MADV_SEQUENTIAL, 0);
1569 largepage_madvise(addr, ps[0], MADV_NOSYNC, EINVAL);
1570 largepage_madvise(addr, ps[i], MADV_NOSYNC, 0);
1571 largepage_madvise(addr, ps[0], MADV_AUTOSYNC, EINVAL);
1572 largepage_madvise(addr, ps[i], MADV_AUTOSYNC, 0);
1573 largepage_madvise(addr, ps[0], MADV_CORE, EINVAL);
1574 largepage_madvise(addr, ps[i], MADV_CORE, 0);
1575 largepage_madvise(addr, ps[0], MADV_NOCORE, EINVAL);
1576 largepage_madvise(addr, ps[i], MADV_NOCORE, 0);
1577
1578 /* Advice that does not result in clipping. */
1579 largepage_madvise(addr, ps[0], MADV_DONTNEED, 0);
1580 largepage_madvise(addr, ps[i], MADV_DONTNEED, 0);
1581 largepage_madvise(addr, ps[0], MADV_WILLNEED, 0);
1582 largepage_madvise(addr, ps[i], MADV_WILLNEED, 0);
1583 largepage_madvise(addr, ps[0], MADV_FREE, 0);
1584 largepage_madvise(addr, ps[i], MADV_FREE, 0);
1585
1586 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1587 ATF_REQUIRE(close(fd) == 0);
1588 }
1589 }
1590
1591 ATF_TC(largepage_mlock);
ATF_TC_HEAD(largepage_mlock,tc)1592 ATF_TC_HEAD(largepage_mlock, tc)
1593 {
1594 /* Needed to set rlimit. */
1595 atf_tc_set_md_var(tc, "require.user", "root");
1596 }
ATF_TC_BODY(largepage_mlock,tc)1597 ATF_TC_BODY(largepage_mlock, tc)
1598 {
1599 struct rlimit rl;
1600 char *addr;
1601 size_t ps[MAXPAGESIZES], sz;
1602 u_long max_wired, wired;
1603 int fd, error, pscnt;
1604
1605 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
1606 ATF_REQUIRE_MSG(setrlimit(RLIMIT_MEMLOCK, &rl) == 0,
1607 "setrlimit failed; error=%d", errno);
1608
1609 sz = sizeof(max_wired);
1610 error = sysctlbyname("vm.max_user_wired", &max_wired, &sz, NULL, 0);
1611 ATF_REQUIRE_MSG(error == 0,
1612 "sysctlbyname(vm.max_user_wired) failed; error=%d", errno);
1613
1614 sz = sizeof(wired);
1615 error = sysctlbyname("vm.stats.vm.v_user_wire_count", &wired, &sz, NULL,
1616 0);
1617 ATF_REQUIRE_MSG(error == 0,
1618 "sysctlbyname(vm.stats.vm.v_user_wire_count) failed; error=%d",
1619 errno);
1620
1621 pscnt = pagesizes(ps, true);
1622 for (int i = 1; i < pscnt; i++) {
1623 if (ps[i] / ps[0] > max_wired - wired) {
1624 /* Cannot wire past the limit. */
1625 atf_tc_skip("test would exceed wiring limit");
1626 }
1627
1628 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1629 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1630 0);
1631 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1632 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1633
1634 ATF_REQUIRE(mlock(addr, ps[0]) != 0);
1635 ATF_REQUIRE_MSG(errno == EINVAL,
1636 "unexpected error %d from mlock(%zu bytes)", errno, ps[i]);
1637 ATF_REQUIRE(mlock(addr, ps[i] - ps[0]) != 0);
1638 ATF_REQUIRE_MSG(errno == EINVAL,
1639 "unexpected error %d from mlock(%zu bytes)", errno, ps[i]);
1640
1641 ATF_REQUIRE_MSG(mlock(addr, ps[i]) == 0,
1642 "mlock failed; error=%d", errno);
1643
1644 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1645
1646 ATF_REQUIRE(mlockall(MCL_FUTURE) == 0);
1647 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1648 0);
1649 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1650 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1651
1652 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1653 ATF_REQUIRE(close(fd) == 0);
1654 }
1655 }
1656
1657 ATF_TC_WITHOUT_HEAD(largepage_msync);
ATF_TC_BODY(largepage_msync,tc)1658 ATF_TC_BODY(largepage_msync, tc)
1659 {
1660 char *addr;
1661 size_t ps[MAXPAGESIZES];
1662 int fd, pscnt;
1663
1664 pscnt = pagesizes(ps, true);
1665 for (int i = 1; i < pscnt; i++) {
1666 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1667 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1668 0);
1669 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1670 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1671
1672 memset(addr, 0, ps[i]);
1673
1674 /*
1675 * "Sync" requests are no-ops for SHM objects, so small
1676 * PAGE_SIZE-sized requests succeed.
1677 */
1678 ATF_REQUIRE_MSG(msync(addr, ps[0], MS_ASYNC) == 0,
1679 "msync(MS_ASYNC) failed; error=%d", errno);
1680 ATF_REQUIRE_MSG(msync(addr, ps[i], MS_ASYNC) == 0,
1681 "msync(MS_ASYNC) failed; error=%d", errno);
1682 ATF_REQUIRE_MSG(msync(addr, ps[0], MS_SYNC) == 0,
1683 "msync(MS_SYNC) failed; error=%d", errno);
1684 ATF_REQUIRE_MSG(msync(addr, ps[i], MS_SYNC) == 0,
1685 "msync(MS_SYNC) failed; error=%d", errno);
1686
1687 ATF_REQUIRE_MSG(msync(addr, ps[0], MS_INVALIDATE) != 0,
1688 "msync(MS_INVALIDATE) succeeded");
1689 /* XXX wrong errno */
1690 ATF_REQUIRE_MSG(errno == EBUSY,
1691 "unexpected error %d from msync(MS_INVALIDATE)", errno);
1692 ATF_REQUIRE_MSG(msync(addr, ps[i], MS_INVALIDATE) == 0,
1693 "msync(MS_INVALIDATE) failed; error=%d", errno);
1694 memset(addr, 0, ps[i]);
1695
1696 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1697 ATF_REQUIRE(close(fd) == 0);
1698 }
1699 }
1700
1701 static void
largepage_protect(char * addr,size_t sz,int prot,int error)1702 largepage_protect(char *addr, size_t sz, int prot, int error)
1703 {
1704 if (error == 0) {
1705 ATF_REQUIRE_MSG(mprotect(addr, sz, prot) == 0,
1706 "mprotect(%zu, %x) failed; error=%d", sz, prot, errno);
1707 } else {
1708 ATF_REQUIRE_MSG(mprotect(addr, sz, prot) != 0,
1709 "mprotect(%zu, %x) succeeded", sz, prot);
1710 ATF_REQUIRE_MSG(errno == error,
1711 "unexpected error %d from mprotect(%zu, %x)",
1712 errno, sz, prot);
1713 }
1714 }
1715
1716 ATF_TC_WITHOUT_HEAD(largepage_mprotect);
ATF_TC_BODY(largepage_mprotect,tc)1717 ATF_TC_BODY(largepage_mprotect, tc)
1718 {
1719 char *addr, *addr1;
1720 size_t ps[MAXPAGESIZES];
1721 int fd, pscnt;
1722
1723 pscnt = pagesizes(ps, true);
1724 for (int i = 1; i < pscnt; i++) {
1725 /*
1726 * Reserve a contiguous region in the address space to avoid
1727 * spurious failures in the face of ASLR.
1728 */
1729 addr = mmap(NULL, ps[i] * 2, PROT_NONE,
1730 MAP_ANON | MAP_ALIGNED(ffsl(ps[i]) - 1), -1, 0);
1731 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1732 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1733 ATF_REQUIRE(munmap(addr, ps[i] * 2) == 0);
1734
1735 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1736 addr = mmap(addr, ps[i], PROT_READ | PROT_WRITE,
1737 MAP_SHARED | MAP_FIXED, fd, 0);
1738 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1739 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1740
1741 /*
1742 * These should be no-ops from the pmap perspective since the
1743 * page is not yet entered into the pmap.
1744 */
1745 largepage_protect(addr, ps[0], PROT_READ, EINVAL);
1746 largepage_protect(addr, ps[i], PROT_READ, 0);
1747 largepage_protect(addr, ps[0], PROT_NONE, EINVAL);
1748 largepage_protect(addr, ps[i], PROT_NONE, 0);
1749 largepage_protect(addr, ps[0],
1750 PROT_READ | PROT_WRITE | PROT_EXEC, EINVAL);
1751 largepage_protect(addr, ps[i],
1752 PROT_READ | PROT_WRITE | PROT_EXEC, 0);
1753
1754 /* Trigger creation of a mapping and try again. */
1755 *(volatile char *)addr = 0;
1756 largepage_protect(addr, ps[0], PROT_READ, EINVAL);
1757 largepage_protect(addr, ps[i], PROT_READ, 0);
1758 largepage_protect(addr, ps[0], PROT_NONE, EINVAL);
1759 largepage_protect(addr, ps[i], PROT_NONE, 0);
1760 largepage_protect(addr, ps[0],
1761 PROT_READ | PROT_WRITE | PROT_EXEC, EINVAL);
1762 largepage_protect(addr, ps[i],
1763 PROT_READ | PROT_WRITE | PROT_EXEC, 0);
1764
1765 memset(addr, 0, ps[i]);
1766
1767 /* Map two contiguous large pages and merge map entries. */
1768 addr1 = mmap(addr + ps[i], ps[i], PROT_READ | PROT_WRITE,
1769 MAP_SHARED | MAP_FIXED | MAP_EXCL, fd, 0);
1770 ATF_REQUIRE_MSG(addr1 != MAP_FAILED,
1771 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1772
1773 largepage_protect(addr1 - ps[0], ps[0] * 2,
1774 PROT_READ | PROT_WRITE, EINVAL);
1775 largepage_protect(addr, ps[i] * 2, PROT_READ | PROT_WRITE, 0);
1776
1777 memset(addr, 0, ps[i] * 2);
1778
1779 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1780 ATF_REQUIRE(munmap(addr1, ps[i]) == 0);
1781 ATF_REQUIRE(close(fd) == 0);
1782 }
1783 }
1784
1785 ATF_TC_WITHOUT_HEAD(largepage_minherit);
ATF_TC_BODY(largepage_minherit,tc)1786 ATF_TC_BODY(largepage_minherit, tc)
1787 {
1788 char *addr;
1789 size_t ps[MAXPAGESIZES];
1790 pid_t child;
1791 int fd, pscnt, status;
1792
1793 pscnt = pagesizes(ps, true);
1794 for (int i = 1; i < pscnt; i++) {
1795 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1796 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1797 0);
1798 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1799 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1800
1801 ATF_REQUIRE(minherit(addr, ps[0], INHERIT_SHARE) != 0);
1802
1803 ATF_REQUIRE_MSG(minherit(addr, ps[i], INHERIT_SHARE) == 0,
1804 "minherit(%zu bytes) failed; error=%d", ps[i], errno);
1805 child = fork();
1806 ATF_REQUIRE_MSG(child != -1, "fork failed; error=%d", errno);
1807 if (child == 0) {
1808 char v;
1809
1810 *(volatile char *)addr = 0;
1811 if (mincore(addr, ps[0], &v) != 0)
1812 _exit(1);
1813 if ((v & MINCORE_SUPER) == 0)
1814 _exit(2);
1815 _exit(0);
1816 }
1817 ATF_REQUIRE_MSG(waitpid(child, &status, 0) == child,
1818 "waitpid failed; error=%d", errno);
1819 ATF_REQUIRE_MSG(WIFEXITED(status),
1820 "child was killed by signal %d", WTERMSIG(status));
1821 ATF_REQUIRE_MSG(WEXITSTATUS(status) == 0,
1822 "child exited with status %d", WEXITSTATUS(status));
1823
1824 ATF_REQUIRE_MSG(minherit(addr, ps[i], INHERIT_NONE) == 0,
1825 "minherit(%zu bytes) failed; error=%d", ps[i], errno);
1826 child = fork();
1827 ATF_REQUIRE_MSG(child != -1, "fork failed; error=%d", errno);
1828 if (child == 0) {
1829 char v;
1830
1831 if (mincore(addr, ps[0], &v) == 0)
1832 _exit(1);
1833 _exit(0);
1834 }
1835 ATF_REQUIRE_MSG(waitpid(child, &status, 0) == child,
1836 "waitpid failed; error=%d", errno);
1837 ATF_REQUIRE_MSG(WIFEXITED(status),
1838 "child was killed by signal %d", WTERMSIG(status));
1839 ATF_REQUIRE_MSG(WEXITSTATUS(status) == 0,
1840 "child exited with status %d", WEXITSTATUS(status));
1841
1842 /* Copy-on-write is not supported for static large pages. */
1843 ATF_REQUIRE_MSG(minherit(addr, ps[i], INHERIT_COPY) != 0,
1844 "minherit(%zu bytes) succeeded", ps[i]);
1845
1846 ATF_REQUIRE_MSG(minherit(addr, ps[i], INHERIT_ZERO) == 0,
1847 "minherit(%zu bytes) failed; error=%d", ps[i], errno);
1848 child = fork();
1849 ATF_REQUIRE_MSG(child != -1, "fork failed; error=%d", errno);
1850 if (child == 0) {
1851 char v;
1852
1853 *(volatile char *)addr = 0;
1854 if (mincore(addr, ps[0], &v) != 0)
1855 _exit(1);
1856 if ((v & MINCORE_SUPER) != 0)
1857 _exit(2);
1858 _exit(0);
1859 }
1860 ATF_REQUIRE_MSG(waitpid(child, &status, 0) == child,
1861 "waitpid failed; error=%d", errno);
1862 ATF_REQUIRE_MSG(WIFEXITED(status),
1863 "child was killed by signal %d", WTERMSIG(status));
1864 ATF_REQUIRE_MSG(WEXITSTATUS(status) == 0,
1865 "child exited with status %d", WEXITSTATUS(status));
1866
1867 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1868 ATF_REQUIRE(close(fd) == 0);
1869 }
1870 }
1871
1872 ATF_TC_WITHOUT_HEAD(largepage_pipe);
ATF_TC_BODY(largepage_pipe,tc)1873 ATF_TC_BODY(largepage_pipe, tc)
1874 {
1875 size_t ps[MAXPAGESIZES];
1876 char *addr;
1877 ssize_t len;
1878 int fd, pfd[2], pscnt, status;
1879 pid_t child;
1880
1881 pscnt = pagesizes(ps, true);
1882
1883 for (int i = 1; i < pscnt; i++) {
1884 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
1885 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
1886 0);
1887 ATF_REQUIRE_MSG(addr != MAP_FAILED,
1888 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
1889
1890 /* Trigger creation of a mapping. */
1891 *(volatile char *)addr = '\0';
1892
1893 ATF_REQUIRE(pipe(pfd) == 0);
1894 child = fork();
1895 ATF_REQUIRE_MSG(child != -1, "fork() failed; error=%d", errno);
1896 if (child == 0) {
1897 char buf[BUFSIZ];
1898 ssize_t resid;
1899
1900 (void)close(pfd[0]);
1901 for (resid = (size_t)ps[i]; resid > 0; resid -= len) {
1902 len = read(pfd[1], buf, sizeof(buf));
1903 if (len < 0)
1904 _exit(1);
1905 }
1906 _exit(0);
1907 }
1908 ATF_REQUIRE(close(pfd[1]) == 0);
1909 len = write(pfd[0], addr, ps[i]);
1910 ATF_REQUIRE_MSG(len >= 0, "write() failed; error=%d", errno);
1911 ATF_REQUIRE_MSG(len == (ssize_t)ps[i],
1912 "short write; len=%zd", len);
1913 ATF_REQUIRE(close(pfd[0]) == 0);
1914
1915 ATF_REQUIRE_MSG(waitpid(child, &status, 0) == child,
1916 "waitpid() failed; error=%d", errno);
1917 ATF_REQUIRE_MSG(WIFEXITED(status),
1918 "child was killed by signal %d", WTERMSIG(status));
1919 ATF_REQUIRE_MSG(WEXITSTATUS(status) == 0,
1920 "child exited with status %d", WEXITSTATUS(status));
1921
1922 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
1923 ATF_REQUIRE(close(fd) == 0);
1924 }
1925 }
1926
1927 #ifdef __amd64__
1928 static sigjmp_buf jmpbuf;
1929 static _Atomic(void *) faultaddr;
1930 static _Atomic(int) faultsig;
1931
1932 #define KEY_RW 1
1933 #define KEY_RO 2
1934 #define KEY_WO 3
1935 #define KEY_NO 4
1936 #define VAL 0xdeadfacec0debeef
1937 static void
set_keys(void)1938 set_keys(void)
1939 {
1940 int error;
1941
1942 error = x86_pkru_set_perm(KEY_RW, 1, 1);
1943 ATF_REQUIRE(error == 0);
1944 error = x86_pkru_set_perm(KEY_RO, 1, 0);
1945 ATF_REQUIRE(error == 0);
1946 error = x86_pkru_set_perm(KEY_WO, 0, 1);
1947 ATF_REQUIRE(error == 0);
1948 error = x86_pkru_set_perm(KEY_NO, 0, 0);
1949 ATF_REQUIRE(error == 0);
1950 }
1951
1952 static void
sigsegv(int sig,siginfo_t * si,void * uc __unused)1953 sigsegv(int sig, siginfo_t *si, void *uc __unused)
1954 {
1955 faultsig = sig;
1956 faultaddr = si->si_addr;
1957 siglongjmp(jmpbuf, 1);
1958 }
1959
1960 static bool
try_read(volatile uint64_t * p,uint64_t * outp)1961 try_read(volatile uint64_t *p, uint64_t *outp)
1962 {
1963 if (sigsetjmp(jmpbuf, 1) == 0) {
1964 *outp = *p;
1965 return (true);
1966 } else {
1967 atomic_signal_fence(memory_order_relaxed);
1968 ATF_REQUIRE(faultsig == SIGSEGV);
1969 ATF_REQUIRE(faultaddr == p);
1970 set_keys(); /* PKRU is not restored by siglongjmp? */
1971 return (false);
1972 }
1973 }
1974
1975 static bool
try_write(volatile uint64_t * p,uint64_t val)1976 try_write(volatile uint64_t *p, uint64_t val)
1977 {
1978 if (sigsetjmp(jmpbuf, 1) == 0) {
1979 *p = val;
1980 return (true);
1981 } else {
1982 atomic_signal_fence(memory_order_relaxed);
1983 ATF_REQUIRE(faultsig == SIGSEGV);
1984 ATF_REQUIRE(faultaddr == p);
1985 set_keys(); /* PKRU is not restored by siglongjmp? */
1986 return (false);
1987 }
1988 }
1989
1990 ATF_TC_WITHOUT_HEAD(largepage_pkru);
ATF_TC_BODY(largepage_pkru,tc)1991 ATF_TC_BODY(largepage_pkru, tc)
1992 {
1993 size_t ps[MAXPAGESIZES];
1994 struct sigaction sa;
1995 char *addr, *addr1;
1996 int error, fd, pscnt;
1997 u_int regs[4];
1998
1999 do_cpuid(0, regs);
2000 if (regs[0] < 7)
2001 atf_tc_skip("PKU not supported");
2002 cpuid_count(7, 0, regs);
2003 if ((regs[2] & CPUID_STDEXT2_PKU) == 0)
2004 atf_tc_skip("PKU not supported");
2005
2006 memset(&sa, 0, sizeof(sa));
2007 sa.sa_sigaction = sigsegv;
2008 sa.sa_flags = SA_SIGINFO;
2009 sigemptyset(&sa.sa_mask);
2010 error = sigaction(SIGSEGV, &sa, NULL);
2011 ATF_REQUIRE(error == 0);
2012
2013 pscnt = pagesizes(ps, true);
2014
2015 for (int i = 1; i < pscnt; i++) {
2016 uint64_t val;
2017
2018 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT, ps[i]);
2019 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE, MAP_SHARED, fd,
2020 0);
2021 ATF_REQUIRE_MSG(addr != MAP_FAILED,
2022 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
2023
2024 /*
2025 * Ensure that the page is faulted into the pmap.
2026 */
2027 memset(addr, 0, ps[i]);
2028
2029 set_keys();
2030
2031 /*
2032 * Make sure we can't partially cover a largepage mapping.
2033 */
2034 error = x86_pkru_protect_range(addr, PAGE_SIZE, KEY_RW, 0);
2035 ATF_REQUIRE_ERRNO(EINVAL, error != 0);
2036 error = x86_pkru_protect_range(addr, ps[i] - PAGE_SIZE, KEY_RW,
2037 0);
2038 ATF_REQUIRE_ERRNO(EINVAL, error != 0);
2039 error = x86_pkru_protect_range(addr + PAGE_SIZE, ps[i] - PAGE_SIZE,
2040 KEY_RW, 0);
2041 ATF_REQUIRE_ERRNO(EINVAL, error != 0);
2042 error = x86_pkru_protect_range(addr + 1, ps[i], KEY_RW, 0);
2043 ATF_REQUIRE_ERRNO(EINVAL, error != 0);
2044
2045 /*
2046 * Make sure that protections are honoured.
2047 */
2048 for (int j = 1; j <= 4; j++) {
2049 volatile uint64_t *addr64;
2050
2051 error = x86_pkru_protect_range(addr, ps[i], 0, 0);
2052 ATF_REQUIRE(error == 0);
2053
2054 addr64 = (volatile uint64_t *)(void *)addr;
2055 *addr64 = VAL;
2056
2057 error = x86_pkru_protect_range(addr, ps[i], j, 0);
2058 ATF_REQUIRE(error == 0);
2059 switch (j) {
2060 case KEY_RW:
2061 ATF_REQUIRE(try_write(addr64, VAL));
2062 ATF_REQUIRE(try_read(addr64, &val));
2063 ATF_REQUIRE(val == VAL);
2064 break;
2065 case KEY_RO:
2066 ATF_REQUIRE(try_read(addr64, &val));
2067 ATF_REQUIRE(val == VAL);
2068 ATF_REQUIRE(!try_write(addr64, VAL));
2069 break;
2070 case KEY_WO:
2071 /* !access implies !modify */
2072 case KEY_NO:
2073 ATF_REQUIRE(!try_read(addr64, &val));
2074 ATF_REQUIRE(!try_write(addr64, VAL));
2075 break;
2076 default:
2077 __unreachable();
2078 }
2079 }
2080 error = munmap(addr, ps[i]);
2081 ATF_CHECK(error == 0);
2082
2083 /*
2084 * Try mapping a large page in a region partially covered by a
2085 * key.
2086 *
2087 * Rather than detecting the mismatch when the logical mapping
2088 * is created, we currently only fail once pmap_enter() is
2089 * called from the fault handler. This is not ideal and might
2090 * be improved in the future.
2091 */
2092 error = x86_pkru_protect_range(addr, ps[i], 0, 0);
2093 ATF_REQUIRE(error == 0);
2094 error = x86_pkru_protect_range(addr + PAGE_SIZE,
2095 ps[i] - PAGE_SIZE, KEY_RW, 0);
2096 ATF_REQUIRE(error == 0);
2097
2098 addr1 = mmap(addr, ps[i], PROT_READ | PROT_WRITE,
2099 MAP_SHARED | MAP_FIXED, fd, 0);
2100 ATF_REQUIRE(addr1 != MAP_FAILED);
2101 ATF_REQUIRE(addr == addr1);
2102 ATF_REQUIRE(!try_read((volatile uint64_t *)(void *)addr, &val));
2103 ATF_REQUIRE(!try_write((volatile uint64_t *)(void *)addr, VAL));
2104 }
2105 }
2106 #undef KEY_RW
2107 #undef KEY_RO
2108 #undef KEY_WO
2109 #undef KEY_NO
2110 #endif
2111
2112 ATF_TC_WITHOUT_HEAD(largepage_reopen);
ATF_TC_BODY(largepage_reopen,tc)2113 ATF_TC_BODY(largepage_reopen, tc)
2114 {
2115 char *addr, *vec;
2116 size_t ps[MAXPAGESIZES];
2117 int fd, psind;
2118
2119 (void)pagesizes(ps, true);
2120 psind = 1;
2121
2122 gen_test_path();
2123 fd = shm_create_largepage(test_path, O_CREAT | O_RDWR, psind,
2124 SHM_LARGEPAGE_ALLOC_DEFAULT, 0600);
2125 if (fd < 0 && errno == ENOTTY)
2126 atf_tc_skip("no large page support");
2127 ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; error=%d", errno);
2128
2129 ATF_REQUIRE_MSG(ftruncate(fd, ps[psind]) == 0,
2130 "ftruncate failed; error=%d", errno);
2131
2132 ATF_REQUIRE_MSG(close(fd) == 0, "close failed; error=%d", errno);
2133
2134 fd = shm_open(test_path, O_RDWR, 0);
2135 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; error=%d", errno);
2136
2137 addr = mmap(NULL, ps[psind], PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
2138 ATF_REQUIRE_MSG(addr != MAP_FAILED, "mmap failed; error=%d", errno);
2139
2140 /* Trigger a fault and mapping creation. */
2141 *(volatile char *)addr = 0;
2142
2143 vec = malloc(ps[psind] / ps[0]);
2144 ATF_REQUIRE(vec != NULL);
2145 ATF_REQUIRE_MSG(mincore(addr, ps[psind], vec) == 0,
2146 "mincore failed; error=%d", errno);
2147 ATF_REQUIRE_MSG((vec[0] & MINCORE_SUPER) == MINCORE_PSIND(psind),
2148 "page not mapped into a %zu-byte superpage", ps[psind]);
2149
2150 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
2151 "shm_unlink failed; errno=%d", errno);
2152 ATF_REQUIRE_MSG(close(fd) == 0,
2153 "close failed; errno=%d", errno);
2154 }
2155
2156 static unsigned char
largepage_sendfile_expected(size_t off)2157 largepage_sendfile_expected(size_t off)
2158 {
2159
2160 return ((unsigned char)(off * 131 + (off >> 8)));
2161 }
2162
2163 ATF_TC_WITHOUT_HEAD(largepage_sendfile);
ATF_TC_BODY(largepage_sendfile,tc)2164 ATF_TC_BODY(largepage_sendfile, tc)
2165 {
2166 static const int flags[] = { 0, SF_NOCACHE };
2167 char *addr;
2168 off_t sbytes;
2169 size_t ps[MAXPAGESIZES];
2170 int error, fd, pscnt, sd[2], status;
2171 pid_t child;
2172
2173 pscnt = pagesizes(ps, true);
2174
2175 for (int i = 1; i < pscnt; i++) {
2176 for (int fi = 0; fi < (int)nitems(flags); fi++) {
2177 fd = shm_open_large(i, SHM_LARGEPAGE_ALLOC_DEFAULT,
2178 ps[i]);
2179 addr = mmap(NULL, ps[i], PROT_READ | PROT_WRITE,
2180 MAP_SHARED, fd, 0);
2181 ATF_REQUIRE_MSG(addr != MAP_FAILED,
2182 "mmap(%zu bytes) failed; error=%d", ps[i], errno);
2183
2184 /* Fill with a verifiable pattern. */
2185 for (size_t j = 0; j < ps[i]; j++)
2186 addr[j] = largepage_sendfile_expected(j);
2187
2188 ATF_REQUIRE(socketpair(PF_LOCAL, SOCK_STREAM, 0,
2189 sd) == 0);
2190
2191 child = fork();
2192 ATF_REQUIRE_MSG(child != -1,
2193 "fork() failed; error=%d", errno);
2194 if (child == 0) {
2195 char buf[BUFSIZ];
2196 ssize_t len;
2197 size_t off, resid;
2198
2199 (void)close(sd[0]);
2200 off = 0;
2201 for (resid = ps[i]; resid > 0; resid -= len) {
2202 len = read(sd[1], buf, sizeof(buf));
2203 if (len <= 0)
2204 _exit(1);
2205 for (ssize_t k = 0; k < len; k++) {
2206 if ((unsigned char)buf[k] !=
2207 largepage_sendfile_expected(
2208 off + k))
2209 _exit(2);
2210 }
2211 off += len;
2212 }
2213 _exit(0);
2214 }
2215 ATF_REQUIRE(close(sd[1]) == 0);
2216
2217 sbytes = 0;
2218 error = sendfile(fd, sd[0], 0, ps[i], NULL, &sbytes,
2219 flags[fi]);
2220 ATF_REQUIRE_MSG(error == 0,
2221 "sendfile() failed; error=%d flags=%#x",
2222 errno, flags[fi]);
2223 ATF_REQUIRE_MSG(sbytes == (off_t)ps[i],
2224 "sendfile() short; sbytes=%jd expected=%zu flags=%#x",
2225 (intmax_t)sbytes, ps[i], flags[fi]);
2226
2227 ATF_REQUIRE(close(sd[0]) == 0);
2228
2229 ATF_REQUIRE_MSG(waitpid(child, &status, 0) == child,
2230 "waitpid() failed; error=%d", errno);
2231 ATF_REQUIRE_MSG(WIFEXITED(status),
2232 "child killed by signal %d", WTERMSIG(status));
2233 ATF_REQUIRE_MSG(WEXITSTATUS(status) == 0,
2234 "child exited with status %d (flags=%#x)",
2235 WEXITSTATUS(status), flags[fi]);
2236
2237 ATF_REQUIRE(munmap(addr, ps[i]) == 0);
2238 ATF_REQUIRE(close(fd) == 0);
2239 }
2240 }
2241 }
2242
2243 ATF_TC_WITHOUT_HEAD(largepage_truncate);
ATF_TC_BODY(largepage_truncate,tc)2244 ATF_TC_BODY(largepage_truncate, tc)
2245 {
2246 size_t ps[MAXPAGESIZES];
2247 int fd, psind;
2248
2249 (void)pagesizes(ps, true);
2250 psind = 1;
2251
2252 gen_test_path();
2253 fd = shm_create_largepage(test_path, O_CREAT | O_RDWR, psind,
2254 SHM_LARGEPAGE_ALLOC_DEFAULT, 0600);
2255 if (fd < 0 && errno == ENOTTY)
2256 atf_tc_skip("no large page support");
2257 ATF_REQUIRE_MSG(fd >= 0, "shm_create_largepage failed; error=%d", errno);
2258
2259 ATF_REQUIRE_MSG(ftruncate(fd, ps[psind]) == 0,
2260 "ftruncate failed; error=%d", errno);
2261
2262 ATF_REQUIRE_MSG(close(fd) == 0, "close failed; error=%d", errno);
2263
2264 fd = shm_open(test_path, O_RDWR | O_TRUNC, 0);
2265 ATF_REQUIRE_MSG(fd == -1, "shm_open(O_TRUNC) should have failed");
2266 ATF_REQUIRE_ERRNO(ENOTSUP, fd == -1);
2267
2268 fd = shm_open(test_path, O_RDWR, 0);
2269 ATF_REQUIRE_MSG(fd >= 0, "shm_open failed; error=%d", errno);
2270
2271 ATF_REQUIRE_MSG(ftruncate(fd, ps[psind]) == 0,
2272 "ftruncate to same size failed; error=%d", errno);
2273
2274 ATF_REQUIRE_MSG(shm_unlink(test_path) == 0,
2275 "shm_unlink failed; errno=%d", errno);
2276 ATF_REQUIRE_MSG(close(fd) == 0,
2277 "close failed; errno=%d", errno);
2278 }
2279
ATF_TP_ADD_TCS(tp)2280 ATF_TP_ADD_TCS(tp)
2281 {
2282 ATF_TP_ADD_TC(tp, remap_object);
2283 ATF_TP_ADD_TC(tp, rename_from_anon);
2284 ATF_TP_ADD_TC(tp, rename_bad_path_pointer);
2285 ATF_TP_ADD_TC(tp, rename_from_nonexisting);
2286 ATF_TP_ADD_TC(tp, rename_to_anon);
2287 ATF_TP_ADD_TC(tp, rename_to_replace);
2288 ATF_TP_ADD_TC(tp, rename_to_noreplace);
2289 ATF_TP_ADD_TC(tp, rename_to_exchange);
2290 ATF_TP_ADD_TC(tp, rename_to_exchange_nonexisting);
2291 ATF_TP_ADD_TC(tp, rename_to_self);
2292 ATF_TP_ADD_TC(tp, rename_bad_flag);
2293 ATF_TP_ADD_TC(tp, reopen_object);
2294 ATF_TP_ADD_TC(tp, readonly_mmap_write);
2295 ATF_TP_ADD_TC(tp, open_after_link);
2296 ATF_TP_ADD_TC(tp, open_invalid_path);
2297 ATF_TP_ADD_TC(tp, open_write_only);
2298 ATF_TP_ADD_TC(tp, open_extra_flags);
2299 ATF_TP_ADD_TC(tp, open_anon);
2300 ATF_TP_ADD_TC(tp, open_anon_readonly);
2301 ATF_TP_ADD_TC(tp, open_bad_path_pointer);
2302 ATF_TP_ADD_TC(tp, open_path_too_long);
2303 ATF_TP_ADD_TC(tp, open_nonexisting_object);
2304 ATF_TP_ADD_TC(tp, open_create_existing_object);
2305 ATF_TP_ADD_TC(tp, shm_functionality_across_fork);
2306 ATF_TP_ADD_TC(tp, trunc_resets_object);
2307 ATF_TP_ADD_TC(tp, unlink_bad_path_pointer);
2308 ATF_TP_ADD_TC(tp, unlink_path_too_long);
2309 ATF_TP_ADD_TC(tp, object_resize);
2310 ATF_TP_ADD_TC(tp, cloexec);
2311 ATF_TP_ADD_TC(tp, mode);
2312 ATF_TP_ADD_TC(tp, fallocate);
2313 ATF_TP_ADD_TC(tp, fspacectl);
2314 ATF_TP_ADD_TC(tp, accounting);
2315 ATF_TP_ADD_TC(tp, mmap_prot);
2316 ATF_TP_ADD_TC(tp, largepage_basic);
2317 ATF_TP_ADD_TC(tp, largepage_config);
2318 ATF_TP_ADD_TC(tp, largepage_fspacectl);
2319 ATF_TP_ADD_TC(tp, largepage_mmap);
2320 ATF_TP_ADD_TC(tp, largepage_munmap);
2321 ATF_TP_ADD_TC(tp, largepage_madvise);
2322 ATF_TP_ADD_TC(tp, largepage_mlock);
2323 ATF_TP_ADD_TC(tp, largepage_msync);
2324 ATF_TP_ADD_TC(tp, largepage_mprotect);
2325 ATF_TP_ADD_TC(tp, largepage_minherit);
2326 ATF_TP_ADD_TC(tp, largepage_pipe);
2327 #ifdef __amd64__
2328 ATF_TP_ADD_TC(tp, largepage_pkru);
2329 #endif
2330 ATF_TP_ADD_TC(tp, largepage_reopen);
2331 ATF_TP_ADD_TC(tp, largepage_sendfile);
2332 ATF_TP_ADD_TC(tp, largepage_truncate);
2333
2334 return (atf_no_error());
2335 }
2336