Home | History | Annotate | Download | only in mmapstress
      1 /* IBM Corporation */
      2 /* 01/03/2003	Port to LTP avenkat (at) us.ibm.com */
      3 /* 06/30/2001	Port to Linux	nsharoff (at) us.ibm.com */
      4 
      5 /*
      6  *   Copyright (c) International Business Machines  Corp., 2003
      7  *
      8  *   This program is free software;  you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 2 of the License, or
     11  *   (at your option) any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     16  *   the GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program;  if not, write to the Free Software
     20  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     21  */
     22 
     23 /*
     24  *	Mmap a sparse file and then fiddle with the hole in the middle.
     25  *	Then check the file contents.
     26  *
     27  *  Usage: mmapstress07 filename holesize e_pageskip sparseoff
     28  *  EXAMPLE: mmapstress07 myfile 4096 1 4096
     29  */
     30 #include <stdio.h>
     31 #include <sys/types.h>
     32 #include <sys/mman.h>
     33 #include <stdlib.h>
     34 #include <unistd.h>
     35 #include <fcntl.h>
     36 #include <signal.h>
     37 #include <errno.h>
     38 #include <sys/wait.h>
     39 #include "test.h"
     40 #define FAILED 0
     41 #define PASSED 1
     42 
     43 static char *tmpname;
     44 
     45 #define ERROR(M)	(void)fprintf(stderr, "%s: errno = %d: " M "\n", \
     46 			argv[0], errno)
     47 
     48 #define CLEANERROR(M)	(void)close(rofd); \
     49 			(void)close(rwfd); \
     50 			(void)unlink(tmpname); \
     51 			ERROR(M)
     52 
     53 #define CATCH_SIG(SIG) \
     54         if (sigaction(SIG, &sa, 0) == -1) { \
     55                 ERROR("couldn't catch signal " #SIG); \
     56                 exit(1); \
     57         }
     58 
     59 extern time_t time(time_t *);
     60 extern char *ctime(const time_t *);
     61 extern void exit(int);
     62 static int checkchars(int fd, char val, int n);
     63 
     64 char *TCID = "mmapstress07";
     65 
     66 int local_flag = PASSED;
     67 int block_number;
     68 FILE *temp;
     69 int TST_TOTAL = 1;
     70 
     71 int anyfail();
     72 void ok_exit();
     73 
     74  /*ARGSUSED*/ static
     75 void cleanup(int sig)
     76 {
     77 	/*
     78 	 * Don't check error codes - we could be signaled before the file is
     79 	 * created.
     80 	 */
     81 	(void)unlink(tmpname);
     82 	exit(1);
     83 }
     84 
     85 int main(int argc, char **argv)
     86 {
     87 	size_t pagesize = (size_t) sysconf(_SC_PAGE_SIZE);
     88 	caddr_t mapaddr;
     89 	time_t t;
     90 	int rofd, rwfd, i;
     91 	struct sigaction sa;
     92 	int e_pageskip;
     93 #ifdef LARGE_FILE
     94 	off64_t holesize;
     95 	off64_t sparseoff;
     96 #else /* LARGE_FILE */
     97 	off_t holesize;
     98 	off_t sparseoff;
     99 #endif /* LARGE_FILE */
    100 
    101 	(void)time(&t);
    102 //      (void)printf("%s: Started %s", argv[0], ctime(&t));
    103 	/* Test fsync & mmap over a hole in a sparse file & extend fragment */
    104 	if (argc < 2 || argc > 5) {
    105 		fprintf(stderr,
    106 			"Usage: mmapstress07 filename holesize e_pageskip sparseoff\n");
    107 		/*****	**	LTP Port 02/01/03	**	**** */
    108 		fprintf(stderr,
    109 			"\t*holesize should be a multiple of pagesize\n");
    110 		fprintf(stderr, "\t*e_pageskip should be 1 always \n");
    111 		fprintf(stderr,
    112 			"\t*sparseoff should be a multiple of pagesize\n");
    113 		fprintf(stderr, "Example: mmapstress07 myfile 4096 1 8192\n");
    114 		/*****	**	******	*****	*****	**	02/01/03 */
    115 		anyfail();	/* LTP Port */
    116 	}
    117 	tst_tmpdir();
    118 	tmpname = argv[1];
    119 
    120 	if (argc >= 3) {
    121 #ifdef LARGE_FILE
    122 		holesize = atoll(argv[2]);
    123 #else /* LARGE_FILE */
    124 		holesize = atoi(argv[2]);
    125 #endif /* LARGE_FILE */
    126 	} else
    127 		holesize = pagesize;
    128 
    129 	if (argc >= 4)
    130 		e_pageskip = atoi(argv[3]);
    131 	else
    132 		e_pageskip = 1;
    133 
    134 	if (argc >= 5) {
    135 #ifdef LARGE_FILE
    136 		sparseoff = atoll(argv[4]);
    137 #else /* LARGE_FILE */
    138 		sparseoff = atoi(argv[4]);
    139 #endif /* LARGE_FILE */
    140 	} else
    141 		sparseoff = pagesize * 2;
    142 
    143 	sa.sa_handler = cleanup;
    144 	sa.sa_flags = 0;
    145 	if (sigemptyset(&sa.sa_mask)) {
    146 		ERROR("sigemptyset failed");
    147 		return 1;
    148 	}
    149 	CATCH_SIG(SIGINT);
    150 	CATCH_SIG(SIGQUIT);
    151 	CATCH_SIG(SIGTERM);
    152 #ifdef LARGE_FILE
    153 	if ((rofd = open64(tmpname, O_RDONLY | O_CREAT, 0777)) == -1) {
    154 #else /* LARGE_FILE */
    155 	if ((rofd = open(tmpname, O_RDONLY | O_CREAT, 0777)) == -1) {
    156 #endif /* LARGE_FILE */
    157 		ERROR("couldn't reopen rofd for reading");
    158 		anyfail();	/* LTP Port */
    159 	}
    160 #ifdef LARGE_FILE
    161 	if ((rwfd = open64(tmpname, O_RDWR)) == -1) {
    162 #else /* LARGE_FILE */
    163 	if ((rwfd = open(tmpname, O_RDWR)) == -1) {
    164 #endif /* LARGE_FILE */
    165 		CLEANERROR("couldn't reopen rwfd for read/write");
    166 		anyfail();	/* LTP Port */
    167 	}
    168 #ifdef LARGE_FILE
    169 	if (lseek64(rwfd, sparseoff, SEEK_SET) < 0) {
    170 #else /* LARGE_FILE */
    171 	if (lseek(rwfd, sparseoff, SEEK_SET) < 0) {
    172 #endif /* LARGE_FILE */
    173 		perror("lseek");
    174 		anyfail();	/* LTP Port */
    175 	}
    176 	/* fill file with junk. */
    177 	i = 0;
    178 	while (i < pagesize && write(rwfd, "a", 1) == 1)
    179 		i++;
    180 	if (i != pagesize) {
    181 		CLEANERROR("couldn't fill first part of file with junk");
    182 		anyfail();	/* LTP Port */
    183 	}
    184 #ifdef LARGE_FILE
    185 	if (lseek64(rwfd, holesize, SEEK_CUR) == -1) {
    186 #else /* LARGE_FILE */
    187 	if (lseek(rwfd, holesize, SEEK_CUR) == -1) {
    188 #endif /* LARGE_FILE */
    189 		CLEANERROR("couldn't create hole in file");
    190 		anyfail();	/* LTP Port */
    191 	}
    192 	/* create fragment */
    193 	i = 0;
    194 	while (i < (pagesize >> 1) && write(rwfd, "b", 1) == 1)
    195 		i++;
    196 	if (i != (pagesize >> 1)) {
    197 		CLEANERROR("couldn't fill second part of file with junk");
    198 		anyfail();	/* LTP Port */
    199 	}
    200 	/* At this point fd contains 1 page of a's, holesize bytes skipped,
    201 	 * 1/2 page of b's.
    202 	 */
    203 
    204 #ifdef LARGE_FILE
    205 	if ((mapaddr = mmap64((caddr_t) 0, pagesize * 2 + holesize, PROT_READ,
    206 			      MAP_SHARED | MAP_FILE, rofd,
    207 			      sparseoff)) == (caddr_t) - 1) {
    208 #else /* LARGE_FILE */
    209 	if ((mapaddr = mmap((caddr_t) 0, pagesize * 2 + holesize, PROT_READ,
    210 			    MAP_SHARED | MAP_FILE, rofd,
    211 			    sparseoff)) == (caddr_t) - 1) {
    212 #endif /* LARGE_FILE */
    213 		CLEANERROR("mmap tmp file failed");
    214 		anyfail();	/* LTP Port */
    215 	}
    216 	/* fill out remainder of page + one more page to extend mmapped flag */
    217 	while (i < 2 * pagesize && write(rwfd, "c", 1) == 1)
    218 		i++;
    219 	if (i != 2 * pagesize) {
    220 		CLEANERROR("couldn't fill second part of file with junk");
    221 		anyfail();	/* LTP Port */
    222 	}
    223 	/* fiddle with mmapped hole */
    224 	if (*(mapaddr + pagesize + (holesize >> 1)) != 0) {
    225 		CLEANERROR("hole not filled with 0's");
    226 		anyfail();	/* LTP Port */
    227 	}
    228 #ifdef LARGE_FILE
    229 	if (lseek64(rwfd, sparseoff + e_pageskip * pagesize, SEEK_SET) == -1) {
    230 #else /* LARGE_FILE */
    231 	if (lseek(rwfd, sparseoff + e_pageskip * pagesize, SEEK_SET) == -1) {
    232 #endif /* LARGE_FILE */
    233 		CLEANERROR("couldn't lseek back to put e's in hole");
    234 		anyfail();	/*LTP Port */
    235 	}
    236 	i = 0;
    237 	while (i < pagesize && write(rwfd, "e", 1) == 1)
    238 		i++;
    239 	if (i != pagesize) {
    240 		CLEANERROR("couldn't part of hole with e's");
    241 		anyfail();	/*LTP Port */
    242 	}
    243 	if (fsync(rwfd) == -1) {
    244 		CLEANERROR("fsync failed");
    245 		anyfail();	/* LTP Port */
    246 	}
    247 #ifdef LARGE_FILE
    248 	if (lseek64(rofd, sparseoff, SEEK_SET) == -1) {
    249 #else /* LARGE_FILE */
    250 	if (lseek(rofd, sparseoff, SEEK_SET) == -1) {
    251 #endif /* LARGE_FILE */
    252 		CLEANERROR("couldn't lseek to begining to verify contents");
    253 		anyfail();	/* LTP Port */
    254 	}
    255 	if (munmap(mapaddr, holesize + 2 * pagesize) == -1) {
    256 		CLEANERROR("munmap of tmp file failed");
    257 		anyfail();	/* LTP Port */
    258 	}
    259 	/* check file's contents */
    260 	if (checkchars(rofd, 'a', pagesize)) {
    261 		CLEANERROR("first page not filled with a's");
    262 		anyfail();	/* LTP Port */
    263 	}
    264 	if (checkchars(rofd, '\0', (e_pageskip - 1) * pagesize)) {
    265 		CLEANERROR("e_skip not filled with 0's");
    266 		anyfail();	/* LTP Port */
    267 	}
    268 	if (checkchars(rofd, 'e', pagesize)) {
    269 		CLEANERROR("part after first 0's not filled with e's");
    270 		anyfail();	/* LTP Port */
    271 	}
    272 	if (checkchars(rofd, '\0', holesize - e_pageskip * pagesize)) {
    273 		CLEANERROR("second hole section not filled with 0's");
    274 		anyfail();	/* LTP Port */
    275 	}
    276 	if (checkchars(rofd, 'b', (pagesize >> 1))) {
    277 		CLEANERROR("next to last half page not filled with b's");
    278 		anyfail();	/* LTP Port */
    279 	}
    280 	if (checkchars(rofd, 'c', pagesize + (pagesize >> 1))) {
    281 		CLEANERROR("extended fragment not filled with c's");
    282 		anyfail();	/* LTP Port */
    283 	}
    284 	if (close(rofd) == -1) {
    285 		CLEANERROR("second close of rofd failed");
    286 		anyfail();	/* LTP Port */
    287 	}
    288 	if (unlink(tmpname) == -1) {
    289 		CLEANERROR("unlink failed");
    290 		anyfail();	/* LTP Port */
    291 	}
    292 	(void)time(&t);
    293 //      (void)printf("%s: Finished %s", argv[0], ctime(&t));
    294 	ok_exit();
    295 	tst_exit();
    296 }
    297 
    298 /* checkchars
    299  * 	verrify that the next n characters of file fd are of value val.
    300  *	0 = success; -1 = failure
    301  */
    302 static int checkchars(int fd, char val, int n)
    303 {
    304 	int i;
    305 	char buf;
    306 
    307 	for (i = 0; i < n && read(fd, &buf, 1) == 1; i++)
    308 		if (buf != val)
    309 			return -1;
    310 	return 0;
    311 }
    312 
    313 /*****	**	LTP Port	**	*****/
    314 int anyfail(void)
    315 {
    316 	tst_brkm(TFAIL, tst_rmdir, "Test failed\n");
    317 }
    318 
    319 void ok_exit(void)
    320 {
    321 	tst_resm(TPASS, "Test passed\n");
    322 	tst_rmdir();
    323 	tst_exit();
    324 }
    325 
    326 /*****	**	******		**	*****/
    327