1/* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Copyright (c) 2014 Fujitsu Ltd. 4 * Author: Xiaoguang Wang <wangxg.fnst@cn.fujitsu.com> 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms of version 2 of the GNU General Public License as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it would be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 * 14 * You should have received a copy of the GNU General Public License along 15 * with this program; if not, write the Free Software Foundation, Inc., 16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 17 */ 18 19/* 20 * Description: 21 * Verify that, 22 * 1. msync() fails with -1 return value and sets errno to EBUSY 23 * if MS_INVALIDATE was specified in flags, and a memory lock 24 * exists for the specified address range. 25 * 2. msync() fails with -1 return value and sets errno to EINVAL 26 * if addr is not a multiple of PAGESIZE; or any bit other than 27 * MS_ASYNC | MS_INVALIDATE | MS_SYNC is set in flags; or both 28 * MS_SYNC and MS_ASYNC are set in flags. 29 * 3. msync() fails with -1 return value and sets errno to ENOMEM 30 * if the indicated memory (or part of it) was not mapped. 31 */ 32 33#include <stdio.h> 34#include <errno.h> 35#include <unistd.h> 36#include <fcntl.h> 37#include <string.h> 38#include <signal.h> 39#include <sys/types.h> 40#include <sys/stat.h> 41#include <sys/mman.h> 42#include <sys/mount.h> 43#include <pwd.h> 44#include <sys/resource.h> 45 46#include "test.h" 47#include "safe_macros.h" 48 49#define INV_SYNC -1 50#define TEMPFILE "msync_file" 51#define BUF_SIZE 256 52 53static void setup(void); 54static void cleanup(void); 55 56static int fd; 57static char *addr1; 58static char *addr2; 59static char *addr3; 60static char *addr4; 61 62static size_t page_sz; 63 64static struct test_case_t { 65 char **addr; 66 int flags; 67 int exp_errno; 68} test_cases[] = { 69 { &addr1, MS_INVALIDATE, EBUSY }, 70 { &addr1, MS_ASYNC | MS_SYNC, EINVAL }, 71 { &addr1, INV_SYNC, EINVAL }, 72 { &addr2, MS_SYNC, EINVAL }, 73 { &addr3, MS_SYNC, EINVAL }, 74 { &addr4, MS_SYNC, ENOMEM }, 75}; 76 77static void msync_verify(struct test_case_t *tc); 78 79char *TCID = "msync03"; 80int TST_TOTAL = ARRAY_SIZE(test_cases); 81 82int main(int ac, char **av) 83{ 84 int i, lc; 85 86 tst_parse_opts(ac, av, NULL, NULL); 87 88 setup(); 89 90 for (lc = 0; TEST_LOOPING(lc); lc++) { 91 tst_count = 0; 92 93 for (i = 0; i < TST_TOTAL; i++) 94 msync_verify(&test_cases[i]); 95 } 96 97 cleanup(); 98 tst_exit(); 99} 100 101static void setup(void) 102{ 103 size_t nwrite = 0; 104 char write_buf[BUF_SIZE]; 105 struct rlimit rl; 106 107 tst_sig(NOFORK, DEF_HANDLER, cleanup); 108 109 tst_tmpdir(); 110 111 TEST_PAUSE; 112 113 page_sz = (size_t)sysconf(_SC_PAGESIZE); 114 115 fd = SAFE_OPEN(cleanup, TEMPFILE, O_RDWR | O_CREAT, 0666); 116 117 memset(write_buf, 'a', BUF_SIZE); 118 while (nwrite < page_sz) { 119 SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, write_buf, BUF_SIZE); 120 nwrite += BUF_SIZE; 121 } 122 123 addr1 = SAFE_MMAP(cleanup, 0, page_sz, PROT_READ | PROT_WRITE, 124 MAP_SHARED | MAP_LOCKED, fd, 0); 125 126 /* addr2 is not a multiple of PAGESIZE */ 127 addr2 = addr1 + 1; 128 129 /* addr3 is outside the address space of the process */ 130 SAFE_GETRLIMIT(NULL, RLIMIT_DATA, &rl); 131 addr3 = (char *)rl.rlim_max; 132 133 /* memory pointed to by addr4 was not mapped */ 134 addr4 = sbrk(0) + (4 * page_sz); 135} 136 137static void msync_verify(struct test_case_t *tc) 138{ 139 TEST(msync(*(tc->addr), page_sz, tc->flags)); 140 if (TEST_RETURN != -1) { 141 tst_resm(TFAIL, "msync succeeded unexpectedly"); 142 return; 143 } 144 145 if (TEST_ERRNO == tc->exp_errno) { 146 tst_resm(TPASS | TTERRNO, "msync failed as expected"); 147 } else { 148 tst_resm(TFAIL | TTERRNO, 149 "msync failed unexpectedly; expected: " 150 "%d - %s", tc->exp_errno, 151 strerror(tc->exp_errno)); 152 } 153} 154 155static void cleanup(void) 156{ 157 if (addr1 && munmap(addr1, page_sz) < 0) 158 tst_resm(TWARN | TERRNO, "munmap() failed"); 159 160 if (fd > 0 && close(fd) < 0) 161 tst_resm(TWARN | TERRNO, "close() failed"); 162 163 tst_rmdir(); 164} 165