1*52244c09SJohn Wren Kennedy /* 2*52244c09SJohn Wren Kennedy * This file and its contents are supplied under the terms of the 3*52244c09SJohn Wren Kennedy * Common Development and Distribution License ("CDDL"), version 1.0. 4*52244c09SJohn Wren Kennedy * You may only use this file in accordance with the terms of version 5*52244c09SJohn Wren Kennedy * 1.0 of the CDDL. 6*52244c09SJohn Wren Kennedy * 7*52244c09SJohn Wren Kennedy * A full copy of the text of the CDDL should have accompanied this 8*52244c09SJohn Wren Kennedy * source. A copy of the CDDL is also available via the Internet at 9*52244c09SJohn Wren Kennedy * http://www.illumos.org/license/CDDL. 10*52244c09SJohn Wren Kennedy */ 11*52244c09SJohn Wren Kennedy 12*52244c09SJohn Wren Kennedy /* 13*52244c09SJohn Wren Kennedy * Copyright (c) 2014 by Delphix. All rights reserved. 14*52244c09SJohn Wren Kennedy */ 15*52244c09SJohn Wren Kennedy 16*52244c09SJohn Wren Kennedy #include <stdio.h> 17*52244c09SJohn Wren Kennedy #include <fcntl.h> 18*52244c09SJohn Wren Kennedy #include <unistd.h> 19*52244c09SJohn Wren Kennedy #include <stdlib.h> 20*52244c09SJohn Wren Kennedy #include <umem.h> 21*52244c09SJohn Wren Kennedy #include <stddef.h> 22*52244c09SJohn Wren Kennedy #include <string.h> 23*52244c09SJohn Wren Kennedy #include <sys/types.h> 24*52244c09SJohn Wren Kennedy #include <sys/errno.h> 25*52244c09SJohn Wren Kennedy #include <sys/list.h> 26*52244c09SJohn Wren Kennedy 27*52244c09SJohn Wren Kennedy extern int errno; 28*52244c09SJohn Wren Kennedy 29*52244c09SJohn Wren Kennedy typedef enum { 30*52244c09SJohn Wren Kennedy SEG_HOLE, 31*52244c09SJohn Wren Kennedy SEG_DATA, 32*52244c09SJohn Wren Kennedy SEG_TYPES 33*52244c09SJohn Wren Kennedy } seg_type_t; 34*52244c09SJohn Wren Kennedy 35*52244c09SJohn Wren Kennedy typedef struct segment { 36*52244c09SJohn Wren Kennedy list_node_t seg_node; 37*52244c09SJohn Wren Kennedy seg_type_t seg_type; 38*52244c09SJohn Wren Kennedy off_t seg_offset; 39*52244c09SJohn Wren Kennedy off_t seg_len; 40*52244c09SJohn Wren Kennedy } seg_t; 41*52244c09SJohn Wren Kennedy 42*52244c09SJohn Wren Kennedy static int 43*52244c09SJohn Wren Kennedy no_memory(void) { 44*52244c09SJohn Wren Kennedy (void) fprintf(stderr, "malloc failed\n"); 45*52244c09SJohn Wren Kennedy return (UMEM_CALLBACK_EXIT(255)); 46*52244c09SJohn Wren Kennedy } 47*52244c09SJohn Wren Kennedy 48*52244c09SJohn Wren Kennedy static void 49*52244c09SJohn Wren Kennedy usage(char *msg, int exit_value) 50*52244c09SJohn Wren Kennedy { 51*52244c09SJohn Wren Kennedy (void) fprintf(stderr, "mkholes [-d|h offset:length] ... filename\n"); 52*52244c09SJohn Wren Kennedy (void) fprintf(stderr, "%s\n", msg); 53*52244c09SJohn Wren Kennedy exit(exit_value); 54*52244c09SJohn Wren Kennedy } 55*52244c09SJohn Wren Kennedy 56*52244c09SJohn Wren Kennedy static char * 57*52244c09SJohn Wren Kennedy get_random_buffer(size_t len) 58*52244c09SJohn Wren Kennedy { 59*52244c09SJohn Wren Kennedy int rand_fd; 60*52244c09SJohn Wren Kennedy char *buf; 61*52244c09SJohn Wren Kennedy 62*52244c09SJohn Wren Kennedy buf = umem_alloc(len, UMEM_NOFAIL); 63*52244c09SJohn Wren Kennedy 64*52244c09SJohn Wren Kennedy /* 65*52244c09SJohn Wren Kennedy * Fill the buffer from /dev/urandom to counteract the 66*52244c09SJohn Wren Kennedy * effects of compression. 67*52244c09SJohn Wren Kennedy */ 68*52244c09SJohn Wren Kennedy if ((rand_fd = open("/dev/urandom", O_RDONLY)) < 0) { 69*52244c09SJohn Wren Kennedy perror("open /dev/urandom failed"); 70*52244c09SJohn Wren Kennedy exit(1); 71*52244c09SJohn Wren Kennedy } 72*52244c09SJohn Wren Kennedy 73*52244c09SJohn Wren Kennedy if (read(rand_fd, buf, len) < 0) { 74*52244c09SJohn Wren Kennedy perror("read /dev/urandom failed"); 75*52244c09SJohn Wren Kennedy exit(1); 76*52244c09SJohn Wren Kennedy } 77*52244c09SJohn Wren Kennedy 78*52244c09SJohn Wren Kennedy (void) close(rand_fd); 79*52244c09SJohn Wren Kennedy 80*52244c09SJohn Wren Kennedy return (buf); 81*52244c09SJohn Wren Kennedy } 82*52244c09SJohn Wren Kennedy 83*52244c09SJohn Wren Kennedy static void 84*52244c09SJohn Wren Kennedy push_segment(list_t *seg_list, seg_type_t seg_type, char *optarg) 85*52244c09SJohn Wren Kennedy { 86*52244c09SJohn Wren Kennedy char *off_str, *len_str; 87*52244c09SJohn Wren Kennedy static off_t file_size = 0; 88*52244c09SJohn Wren Kennedy off_t off, len; 89*52244c09SJohn Wren Kennedy seg_t *seg; 90*52244c09SJohn Wren Kennedy 91*52244c09SJohn Wren Kennedy off_str = strtok(optarg, ":"); 92*52244c09SJohn Wren Kennedy len_str = strtok(NULL, ":"); 93*52244c09SJohn Wren Kennedy 94*52244c09SJohn Wren Kennedy if (off_str == NULL || len_str == NULL) 95*52244c09SJohn Wren Kennedy usage("Bad offset or length", 1); 96*52244c09SJohn Wren Kennedy 97*52244c09SJohn Wren Kennedy off = strtoull(off_str, NULL, 0); 98*52244c09SJohn Wren Kennedy len = strtoull(len_str, NULL, 0); 99*52244c09SJohn Wren Kennedy 100*52244c09SJohn Wren Kennedy if (file_size >= off + len) 101*52244c09SJohn Wren Kennedy usage("Ranges must ascend and may not overlap.", 1); 102*52244c09SJohn Wren Kennedy file_size = off + len; 103*52244c09SJohn Wren Kennedy 104*52244c09SJohn Wren Kennedy seg = umem_alloc(sizeof (seg_t), UMEM_NOFAIL); 105*52244c09SJohn Wren Kennedy seg->seg_type = seg_type; 106*52244c09SJohn Wren Kennedy seg->seg_offset = off; 107*52244c09SJohn Wren Kennedy seg->seg_len = len; 108*52244c09SJohn Wren Kennedy 109*52244c09SJohn Wren Kennedy list_insert_tail(seg_list, seg); 110*52244c09SJohn Wren Kennedy } 111*52244c09SJohn Wren Kennedy 112*52244c09SJohn Wren Kennedy int 113*52244c09SJohn Wren Kennedy main(int argc, char *argv[]) 114*52244c09SJohn Wren Kennedy { 115*52244c09SJohn Wren Kennedy int c, fd; 116*52244c09SJohn Wren Kennedy char *fname; 117*52244c09SJohn Wren Kennedy list_t seg_list; 118*52244c09SJohn Wren Kennedy seg_t *seg; 119*52244c09SJohn Wren Kennedy 120*52244c09SJohn Wren Kennedy umem_nofail_callback(no_memory); 121*52244c09SJohn Wren Kennedy list_create(&seg_list, sizeof (seg_t), offsetof(seg_t, seg_node)); 122*52244c09SJohn Wren Kennedy 123*52244c09SJohn Wren Kennedy while ((c = getopt(argc, argv, "d:h:")) != -1) { 124*52244c09SJohn Wren Kennedy switch (c) { 125*52244c09SJohn Wren Kennedy case 'd': 126*52244c09SJohn Wren Kennedy push_segment(&seg_list, SEG_DATA, optarg); 127*52244c09SJohn Wren Kennedy break; 128*52244c09SJohn Wren Kennedy case 'h': 129*52244c09SJohn Wren Kennedy push_segment(&seg_list, SEG_HOLE, optarg); 130*52244c09SJohn Wren Kennedy break; 131*52244c09SJohn Wren Kennedy } 132*52244c09SJohn Wren Kennedy } 133*52244c09SJohn Wren Kennedy argc -= optind; 134*52244c09SJohn Wren Kennedy argv += optind; 135*52244c09SJohn Wren Kennedy 136*52244c09SJohn Wren Kennedy if ((fname = argv[0]) == NULL) 137*52244c09SJohn Wren Kennedy usage("No filename specified", 1); 138*52244c09SJohn Wren Kennedy fname = argv[0]; 139*52244c09SJohn Wren Kennedy 140*52244c09SJohn Wren Kennedy if ((fd = open(fname, O_LARGEFILE | O_RDWR | O_CREAT | O_SYNC, 141*52244c09SJohn Wren Kennedy 00666)) < 0) { 142*52244c09SJohn Wren Kennedy perror("open failed"); 143*52244c09SJohn Wren Kennedy exit(1); 144*52244c09SJohn Wren Kennedy } 145*52244c09SJohn Wren Kennedy 146*52244c09SJohn Wren Kennedy while ((seg = list_remove_head(&seg_list)) != NULL) { 147*52244c09SJohn Wren Kennedy char *buf, *vbuf; 148*52244c09SJohn Wren Kennedy off_t off = seg->seg_offset; 149*52244c09SJohn Wren Kennedy off_t len = seg->seg_len; 150*52244c09SJohn Wren Kennedy 151*52244c09SJohn Wren Kennedy if (seg->seg_type == SEG_HOLE) { 152*52244c09SJohn Wren Kennedy struct flock fl; 153*52244c09SJohn Wren Kennedy off_t bytes_read = 0; 154*52244c09SJohn Wren Kennedy ssize_t readlen = 1024 * 1024 * 16; 155*52244c09SJohn Wren Kennedy 156*52244c09SJohn Wren Kennedy fl.l_whence = SEEK_SET; 157*52244c09SJohn Wren Kennedy fl.l_start = off; 158*52244c09SJohn Wren Kennedy fl.l_len = len; 159*52244c09SJohn Wren Kennedy if (fcntl(fd, F_FREESP, &fl) != 0) { 160*52244c09SJohn Wren Kennedy perror("freesp failed"); 161*52244c09SJohn Wren Kennedy exit(1); 162*52244c09SJohn Wren Kennedy } 163*52244c09SJohn Wren Kennedy 164*52244c09SJohn Wren Kennedy buf = (char *)umem_alloc(readlen, UMEM_NOFAIL); 165*52244c09SJohn Wren Kennedy vbuf = (char *)umem_zalloc(readlen, UMEM_NOFAIL); 166*52244c09SJohn Wren Kennedy while (bytes_read < len) { 167*52244c09SJohn Wren Kennedy ssize_t bytes = pread(fd, buf, readlen, off); 168*52244c09SJohn Wren Kennedy if (bytes < 0) { 169*52244c09SJohn Wren Kennedy perror("pread hole failed"); 170*52244c09SJohn Wren Kennedy exit(1); 171*52244c09SJohn Wren Kennedy } 172*52244c09SJohn Wren Kennedy 173*52244c09SJohn Wren Kennedy if (memcmp(buf, vbuf, bytes) != 0) { 174*52244c09SJohn Wren Kennedy (void) fprintf(stderr, "Read back hole " 175*52244c09SJohn Wren Kennedy "didn't match.\n"); 176*52244c09SJohn Wren Kennedy exit(1); 177*52244c09SJohn Wren Kennedy } 178*52244c09SJohn Wren Kennedy bytes_read += bytes; 179*52244c09SJohn Wren Kennedy off += bytes; 180*52244c09SJohn Wren Kennedy } 181*52244c09SJohn Wren Kennedy 182*52244c09SJohn Wren Kennedy umem_free(buf, readlen); 183*52244c09SJohn Wren Kennedy umem_free(vbuf, readlen); 184*52244c09SJohn Wren Kennedy umem_free(seg, sizeof (seg_t)); 185*52244c09SJohn Wren Kennedy } else if (seg->seg_type == SEG_DATA) { 186*52244c09SJohn Wren Kennedy buf = get_random_buffer(len); 187*52244c09SJohn Wren Kennedy vbuf = (char *)umem_alloc(len, UMEM_NOFAIL); 188*52244c09SJohn Wren Kennedy if ((pwrite(fd, buf, len, off)) < 0) { 189*52244c09SJohn Wren Kennedy perror("pwrite failed"); 190*52244c09SJohn Wren Kennedy exit(1); 191*52244c09SJohn Wren Kennedy } 192*52244c09SJohn Wren Kennedy 193*52244c09SJohn Wren Kennedy if ((pread(fd, vbuf, len, off)) != len) { 194*52244c09SJohn Wren Kennedy perror("pread failed"); 195*52244c09SJohn Wren Kennedy exit(1); 196*52244c09SJohn Wren Kennedy } 197*52244c09SJohn Wren Kennedy 198*52244c09SJohn Wren Kennedy if (memcmp(buf, vbuf, len) != 0) { 199*52244c09SJohn Wren Kennedy (void) fprintf(stderr, "Read back buf didn't " 200*52244c09SJohn Wren Kennedy "match.\n"); 201*52244c09SJohn Wren Kennedy exit(1); 202*52244c09SJohn Wren Kennedy } 203*52244c09SJohn Wren Kennedy 204*52244c09SJohn Wren Kennedy umem_free(buf, len); 205*52244c09SJohn Wren Kennedy umem_free(vbuf, len); 206*52244c09SJohn Wren Kennedy umem_free(seg, sizeof (seg_t)); 207*52244c09SJohn Wren Kennedy } 208*52244c09SJohn Wren Kennedy } 209*52244c09SJohn Wren Kennedy 210*52244c09SJohn Wren Kennedy (void) close(fd); 211*52244c09SJohn Wren Kennedy return (0); 212*52244c09SJohn Wren Kennedy } 213