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