1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * Copyright (c) 2014 Fujitsu Ltd. 4 * Author: Xiaoguang Wang <wangxg.fnst (at) 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 53 static void setup(void); 54 static void cleanup(void); 55 56 static int fd; 57 static char *addr1; 58 static char *addr2; 59 static char *addr3; 60 61 #if !defined(UCLINUX) 62 static char *addr4; 63 #endif 64 65 static size_t page_sz; 66 67 static struct test_case_t { 68 char **addr; 69 int flags; 70 int exp_errno; 71 } test_cases[] = { 72 { &addr1, MS_INVALIDATE, EBUSY }, 73 { &addr1, MS_ASYNC | MS_SYNC, EINVAL }, 74 { &addr1, INV_SYNC, EINVAL }, 75 { &addr2, MS_SYNC, EINVAL }, 76 { &addr3, MS_SYNC, EINVAL }, 77 #if !defined(UCLINUX) 78 { &addr4, MS_SYNC, ENOMEM }, 79 #endif 80 }; 81 82 static void msync_verify(struct test_case_t *tc); 83 84 char *TCID = "msync03"; 85 int TST_TOTAL = ARRAY_SIZE(test_cases); 86 87 int main(int ac, char **av) 88 { 89 int i, lc; 90 91 tst_parse_opts(ac, av, NULL, NULL); 92 93 setup(); 94 95 for (lc = 0; TEST_LOOPING(lc); lc++) { 96 tst_count = 0; 97 98 for (i = 0; i < TST_TOTAL; i++) 99 msync_verify(&test_cases[i]); 100 } 101 102 cleanup(); 103 tst_exit(); 104 } 105 106 static void setup(void) 107 { 108 size_t nwrite = 0; 109 char write_buf[BUF_SIZE]; 110 struct rlimit rl; 111 112 tst_sig(NOFORK, DEF_HANDLER, cleanup); 113 114 tst_tmpdir(); 115 116 TEST_PAUSE; 117 118 page_sz = (size_t)sysconf(_SC_PAGESIZE); 119 120 fd = SAFE_OPEN(cleanup, TEMPFILE, O_RDWR | O_CREAT, 0666); 121 122 memset(write_buf, 'a', BUF_SIZE); 123 while (nwrite < page_sz) { 124 SAFE_WRITE(cleanup, 1, fd, write_buf, BUF_SIZE); 125 nwrite += BUF_SIZE; 126 } 127 128 addr1 = SAFE_MMAP(cleanup, 0, page_sz, PROT_READ | PROT_WRITE, 129 MAP_SHARED | MAP_LOCKED, fd, 0); 130 131 /* addr2 is not a multiple of PAGESIZE */ 132 addr2 = addr1 + 1; 133 134 /* addr3 is outside the address space of the process */ 135 if (getrlimit(RLIMIT_DATA, &rl) < 0) 136 tst_brkm(TBROK | TERRNO, NULL, "getrlimit failed"); 137 addr3 = (char *)rl.rlim_max; 138 139 #if !defined(UCLINUX) 140 /* memory pointed to by addr4 was not mapped */ 141 addr4 = get_high_address(); 142 #endif 143 } 144 145 static void msync_verify(struct test_case_t *tc) 146 { 147 TEST(msync(*(tc->addr), page_sz, tc->flags)); 148 if (TEST_RETURN != -1) { 149 tst_resm(TFAIL, "msync succeeded unexpectedly"); 150 return; 151 } 152 153 if (TEST_ERRNO == tc->exp_errno) { 154 tst_resm(TPASS | TTERRNO, "msync failed as expected"); 155 } else { 156 tst_resm(TFAIL | TTERRNO, 157 "msync failed unexpectedly; expected: " 158 "%d - %s", tc->exp_errno, 159 strerror(tc->exp_errno)); 160 } 161 } 162 163 static void cleanup(void) 164 { 165 if (addr1 && munmap(addr1, page_sz) < 0) 166 tst_resm(TWARN | TERRNO, "munmap() failed"); 167 168 if (fd > 0 && close(fd) < 0) 169 tst_resm(TWARN | TERRNO, "close() failed"); 170 171 tst_rmdir(); 172 } 173