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 <fcntl.h> 30 #include <stdio.h> 31 #include <unistd.h> 32 #include <memory.h> 33 #include <sys/mman.h> 34 #include <sys/wait.h> 35 #include <limits.h> 36 #include <getopt.h> 37 38 #include "test.h" 39 #include "safe_macros.h" 40 41 #define NUM_CHILDREN 1000 42 43 static void setup(void); 44 static void cleanup(void); 45 static void usage(void); 46 static int debug = 0; 47 48 char *TCID = "dio_sparse"; 49 int TST_TOTAL = 1; 50 51 #include "common_sparse.h" 52 53 /* 54 * Write zeroes using O_DIRECT into sparse file. 55 */ 56 int dio_sparse(char *filename, int align, int writesize, int filesize) 57 { 58 int fd; 59 void *bufptr; 60 int i, w; 61 62 fd = open(filename, O_DIRECT | O_WRONLY | O_CREAT | O_EXCL, 0600); 63 64 if (fd < 0) { 65 tst_resm(TBROK | TERRNO, "open()"); 66 return 1; 67 } 68 69 SAFE_FTRUNCATE(cleanup, fd, filesize); 70 71 if (posix_memalign(&bufptr, align, writesize)) { 72 close(fd); 73 tst_resm(TBROK | TERRNO, "posix_memalign()"); 74 return 1; 75 } 76 77 memset(bufptr, 0, writesize); 78 for (i = 0; i < filesize;) { 79 if ((w = write(fd, bufptr, writesize)) != writesize) { 80 tst_resm(TBROK | TERRNO, "write() returned %d", w); 81 close(fd); 82 return 1; 83 } 84 85 i += w; 86 } 87 88 close(fd); 89 unlink(filename); 90 91 return 0; 92 } 93 94 void usage(void) 95 { 96 fprintf(stderr, "usage: dio_sparse [-d] [-n children] [-s filesize]" 97 " [-w writesize]\n"); 98 exit(1); 99 } 100 101 int main(int argc, char **argv) 102 { 103 char *filename = "dio_sparse"; 104 int pid[NUM_CHILDREN]; 105 int num_children = 1; 106 int i; 107 long alignment = 512; 108 int writesize = 65536; 109 int filesize = 100 * 1024 * 1024; 110 int c; 111 int children_errors = 0; 112 int ret; 113 114 while ((c = getopt(argc, argv, "dw:n:a:s:")) != -1) { 115 char *endp; 116 switch (c) { 117 case 'd': 118 debug++; 119 break; 120 case 'a': 121 alignment = strtol(optarg, &endp, 0); 122 alignment = scale_by_kmg(alignment, *endp); 123 break; 124 case 'w': 125 writesize = strtol(optarg, &endp, 0); 126 writesize = scale_by_kmg(writesize, *endp); 127 break; 128 case 's': 129 filesize = strtol(optarg, &endp, 0); 130 filesize = scale_by_kmg(filesize, *endp); 131 break; 132 case 'n': 133 num_children = atoi(optarg); 134 if (num_children > NUM_CHILDREN) { 135 fprintf(stderr, 136 "number of children limited to %d\n", 137 NUM_CHILDREN); 138 num_children = NUM_CHILDREN; 139 } 140 break; 141 case '?': 142 usage(); 143 break; 144 } 145 } 146 147 setup(); 148 tst_resm(TINFO, "Dirtying free blocks"); 149 dirty_freeblocks(filesize); 150 151 tst_resm(TINFO, "Starting I/O tests"); 152 signal(SIGTERM, SIG_DFL); 153 for (i = 0; i < num_children; i++) { 154 switch (pid[i] = fork()) { 155 case 0: 156 read_sparse(filename, filesize); 157 break; 158 case -1: 159 while (i-- > 0) 160 kill(pid[i], SIGTERM); 161 162 tst_brkm(TBROK | TERRNO, cleanup, "fork()"); 163 default: 164 continue; 165 } 166 } 167 tst_sig(FORK, DEF_HANDLER, cleanup); 168 169 ret = dio_sparse(filename, alignment, writesize, filesize); 170 171 tst_resm(TINFO, "Killing childrens(s)"); 172 173 for (i = 0; i < num_children; i++) 174 kill(pid[i], SIGTERM); 175 176 for (i = 0; i < num_children; i++) { 177 int status; 178 pid_t p; 179 180 p = waitpid(pid[i], &status, 0); 181 if (p < 0) { 182 tst_resm(TBROK | TERRNO, "waitpid()"); 183 } else { 184 if (WIFEXITED(status) && WEXITSTATUS(status) == 10) 185 children_errors++; 186 } 187 } 188 189 if (children_errors) 190 tst_resm(TFAIL, "%i children(s) exited abnormally", 191 children_errors); 192 193 if (!children_errors && !ret) 194 tst_resm(TPASS, "Test passed"); 195 196 cleanup(); 197 tst_exit(); 198 } 199 200 static void setup(void) 201 { 202 tst_sig(FORK, DEF_HANDLER, cleanup); 203 tst_tmpdir(); 204 } 205 206 static void cleanup(void) 207 { 208 tst_rmdir(); 209 } 210