Home | History | Annotate | Download | only in ltp-aiodio
      1 /*
      2  *   Copyright (c) 2004 Daniel McNeil <daniel (at) osdl.org>
      3  *                 2004 Open Source Development Lab
      4  *
      5  *   Copyright (c) 2004 Marty Ridgeway <mridge (at) us.ibm.com>
      6  *
      7  *   Copyright (c) 2011 Cyril Hrubis <chrubis (at) suse.cz>
      8  *
      9  *   This program is free software;  you can redistribute it and/or modify
     10  *   it under the terms of the GNU General Public License as published by
     11  *   the Free Software Foundation; either version 2 of the License, or
     12  *   (at your option) any later version.
     13  *
     14  *   This program is distributed in the hope that it will be useful,
     15  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
     16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
     17  *   the GNU General Public License for more details.
     18  *
     19  *   You should have received a copy of the GNU General Public License
     20  *   along with this program;  if not, write to the Free Software
     21  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
     22  */
     23 
     24 #define _GNU_SOURCE
     25 
     26 #include <stdlib.h>
     27 #include <sys/types.h>
     28 #include <signal.h>
     29 #include <errno.h>
     30 #include <fcntl.h>
     31 #include <stdio.h>
     32 #include <unistd.h>
     33 #include <memory.h>
     34 #include <sys/mman.h>
     35 #include <sys/wait.h>
     36 #include <limits.h>
     37 #include <getopt.h>
     38 
     39 #include "test.h"
     40 #include "safe_macros.h"
     41 
     42 #define NUM_CHILDREN 1000
     43 
     44 static void setup(void);
     45 static void cleanup(void);
     46 static void usage(void);
     47 static int debug = 0;
     48 static int fd;
     49 
     50 char *TCID = "dio_sparse";
     51 int TST_TOTAL = 1;
     52 
     53 #include "common_sparse.h"
     54 
     55 /*
     56  * Write zeroes using O_DIRECT into sparse file.
     57  */
     58 int dio_sparse(int fd, int align, int writesize, int filesize, int offset)
     59 {
     60 	void *bufptr;
     61 	int i, w;
     62 
     63 	TEST(posix_memalign(&bufptr, align, writesize));
     64 	if (TEST_RETURN) {
     65 		tst_resm(TBROK | TRERRNO, "cannot allocate aligned memory");
     66 		return 1;
     67 	}
     68 
     69 	memset(bufptr, 0, writesize);
     70 	lseek(fd, offset, SEEK_SET);
     71 	for (i = offset; i < filesize;) {
     72 		if ((w = write(fd, bufptr, writesize)) != writesize) {
     73 			tst_resm(TBROK | TERRNO, "write() returned %d", w);
     74 			return 1;
     75 		}
     76 
     77 		i += w;
     78 	}
     79 
     80 	return 0;
     81 }
     82 
     83 void usage(void)
     84 {
     85 	fprintf(stderr, "usage: dio_sparse [-d] [-n children] [-s filesize]"
     86 		" [-w writesize] [-o offset]]\n");
     87 	exit(1);
     88 }
     89 
     90 int main(int argc, char **argv)
     91 {
     92 	char *filename = "dio_sparse";
     93 	int pid[NUM_CHILDREN];
     94 	int num_children = 1;
     95 	int i;
     96 	long alignment = 512;
     97 	int writesize = 65536;
     98 	int filesize = 100 * 1024 * 1024;
     99 	int offset = 0;
    100 	int c;
    101 	int children_errors = 0;
    102 	int ret;
    103 
    104 	while ((c = getopt(argc, argv, "dw:n:a:s:o:")) != -1) {
    105 		char *endp;
    106 		switch (c) {
    107 		case 'd':
    108 			debug++;
    109 			break;
    110 		case 'a':
    111 			alignment = strtol(optarg, &endp, 0);
    112 			alignment = scale_by_kmg(alignment, *endp);
    113 			break;
    114 		case 'w':
    115 			writesize = strtol(optarg, &endp, 0);
    116 			writesize = scale_by_kmg(writesize, *endp);
    117 			break;
    118 		case 's':
    119 			filesize = strtol(optarg, &endp, 0);
    120 			filesize = scale_by_kmg(filesize, *endp);
    121 			break;
    122 		case 'o':
    123 			offset = strtol(optarg, &endp, 0);
    124 			offset = scale_by_kmg(offset, *endp);
    125 			break;
    126 		case 'n':
    127 			num_children = atoi(optarg);
    128 			if (num_children > NUM_CHILDREN) {
    129 				fprintf(stderr,
    130 					"number of children limited to %d\n",
    131 					NUM_CHILDREN);
    132 				num_children = NUM_CHILDREN;
    133 			}
    134 			break;
    135 		case '?':
    136 			usage();
    137 			break;
    138 		}
    139 	}
    140 
    141 	setup();
    142 	tst_resm(TINFO, "Dirtying free blocks");
    143 	dirty_freeblocks(filesize);
    144 
    145 	fd = SAFE_OPEN(cleanup, filename,
    146 		O_DIRECT | O_WRONLY | O_CREAT | O_EXCL, 0600);
    147 	SAFE_FTRUNCATE(cleanup, fd, filesize);
    148 
    149 	tst_resm(TINFO, "Starting I/O tests");
    150 	signal(SIGTERM, SIG_DFL);
    151 	for (i = 0; i < num_children; i++) {
    152 		switch (pid[i] = fork()) {
    153 		case 0:
    154 			SAFE_CLOSE(NULL, fd);
    155 			read_sparse(filename, filesize);
    156 			break;
    157 		case -1:
    158 			while (i-- > 0)
    159 				kill(pid[i], SIGTERM);
    160 
    161 			tst_brkm(TBROK | TERRNO, cleanup, "fork()");
    162 		default:
    163 			continue;
    164 		}
    165 	}
    166 	tst_sig(FORK, DEF_HANDLER, cleanup);
    167 
    168 	ret = dio_sparse(fd, alignment, writesize, filesize, offset);
    169 
    170 	tst_resm(TINFO, "Killing childrens(s)");
    171 
    172 	for (i = 0; i < num_children; i++)
    173 		kill(pid[i], SIGTERM);
    174 
    175 	for (i = 0; i < num_children; i++) {
    176 		int status;
    177 		pid_t p;
    178 
    179 		p = waitpid(pid[i], &status, 0);
    180 		if (p < 0) {
    181 			tst_resm(TBROK | TERRNO, "waitpid()");
    182 		} else {
    183 			if (WIFEXITED(status) && WEXITSTATUS(status) == 10)
    184 				children_errors++;
    185 		}
    186 	}
    187 
    188 	if (children_errors)
    189 		tst_resm(TFAIL, "%i children(s) exited abnormally",
    190 			 children_errors);
    191 
    192 	if (!children_errors && !ret)
    193 		tst_resm(TPASS, "Test passed");
    194 
    195 	cleanup();
    196 	tst_exit();
    197 }
    198 
    199 static void setup(void)
    200 {
    201 	tst_sig(FORK, DEF_HANDLER, cleanup);
    202 	tst_tmpdir();
    203 }
    204 
    205 static void cleanup(void)
    206 {
    207 	if (fd > 0 && close(fd))
    208 		tst_resm(TWARN | TERRNO, "Failed to close file");
    209 
    210 	tst_rmdir();
    211 }
    212