Home | History | Annotate | Download | only in msync
      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