2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright (c) 2014 by Delphix. All rights reserved.
23 #include <sys/types.h>
24 #include <sys/errno.h>
35 typedef struct segment
{
44 (void) fprintf(stderr
, "malloc failed\n");
45 return (UMEM_CALLBACK_EXIT(255));
49 usage(char *msg
, int exit_value
)
51 (void) fprintf(stderr
, "mkholes [-d|h offset:length] ... filename\n");
52 (void) fprintf(stderr
, "%s\n", msg
);
57 get_random_buffer(size_t len
)
62 buf
= umem_alloc(len
, UMEM_NOFAIL
);
65 * Fill the buffer from /dev/urandom to counteract the
66 * effects of compression.
68 if ((rand_fd
= open("/dev/urandom", O_RDONLY
)) < 0) {
69 perror("open /dev/urandom failed");
73 if (read(rand_fd
, buf
, len
) < 0) {
74 perror("read /dev/urandom failed");
78 (void) close(rand_fd
);
84 push_segment(list_t
*seg_list
, seg_type_t seg_type
, char *optarg
)
86 char *off_str
, *len_str
;
87 static off_t file_size
= 0;
91 off_str
= strtok(optarg
, ":");
92 len_str
= strtok(NULL
, ":");
94 if (off_str
== NULL
|| len_str
== NULL
)
95 usage("Bad offset or length", 1);
97 off
= strtoull(off_str
, NULL
, 0);
98 len
= strtoull(len_str
, NULL
, 0);
100 if (file_size
>= off
+ len
)
101 usage("Ranges must ascend and may not overlap.", 1);
102 file_size
= off
+ len
;
104 seg
= umem_alloc(sizeof (seg_t
), UMEM_NOFAIL
);
105 seg
->seg_type
= seg_type
;
106 seg
->seg_offset
= off
;
109 list_insert_tail(seg_list
, seg
);
113 main(int argc
, char *argv
[])
120 umem_nofail_callback(no_memory
);
121 list_create(&seg_list
, sizeof (seg_t
), offsetof(seg_t
, seg_node
));
123 while ((c
= getopt(argc
, argv
, "d:h:")) != -1) {
126 push_segment(&seg_list
, SEG_DATA
, optarg
);
129 push_segment(&seg_list
, SEG_HOLE
, optarg
);
136 if ((fname
= argv
[0]) == NULL
)
137 usage("No filename specified", 1);
140 if ((fd
= open(fname
, O_LARGEFILE
| O_RDWR
| O_CREAT
| O_SYNC
,
142 perror("open failed");
146 while ((seg
= list_remove_head(&seg_list
)) != NULL
) {
148 off_t off
= seg
->seg_offset
;
149 off_t len
= seg
->seg_len
;
151 if (seg
->seg_type
== SEG_HOLE
) {
153 off_t bytes_read
= 0;
154 ssize_t readlen
= 1024 * 1024 * 16;
156 fl
.l_whence
= SEEK_SET
;
159 if (fcntl(fd
, F_FREESP
, &fl
) != 0) {
160 perror("freesp failed");
164 buf
= (char *)umem_alloc(readlen
, UMEM_NOFAIL
);
165 vbuf
= (char *)umem_zalloc(readlen
, UMEM_NOFAIL
);
166 while (bytes_read
< len
) {
167 ssize_t bytes
= pread(fd
, buf
, readlen
, off
);
169 perror("pread hole failed");
173 if (memcmp(buf
, vbuf
, bytes
) != 0) {
174 (void) fprintf(stderr
, "Read back hole "
182 umem_free(buf
, readlen
);
183 umem_free(vbuf
, readlen
);
184 umem_free(seg
, sizeof (seg_t
));
185 } else if (seg
->seg_type
== SEG_DATA
) {
186 buf
= get_random_buffer(len
);
187 vbuf
= (char *)umem_alloc(len
, UMEM_NOFAIL
);
188 if ((pwrite(fd
, buf
, len
, off
)) < 0) {
189 perror("pwrite failed");
193 if ((pread(fd
, vbuf
, len
, off
)) != len
) {
194 perror("pread failed");
198 if (memcmp(buf
, vbuf
, len
) != 0) {
199 (void) fprintf(stderr
, "Read back buf didn't "
205 umem_free(vbuf
, len
);
206 umem_free(seg
, sizeof (seg_t
));