52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy/*
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * This file and its contents are supplied under the terms of the
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * Common Development and Distribution License ("CDDL"), version 1.0.
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * You may only use this file in accordance with the terms of version
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * 1.0 of the CDDL.
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy *
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * A full copy of the text of the CDDL should have accompanied this
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * source. A copy of the CDDL is also available via the Internet at
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * http://www.illumos.org/license/CDDL.
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy */
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy/*
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * Copyright (c) 2014 by Delphix. All rights reserved.
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy */
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <stdio.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <fcntl.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <unistd.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <stdlib.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <umem.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <stddef.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <string.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <sys/types.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <sys/errno.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy#include <sys/list.h>
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedyextern int errno;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedytypedef enum {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy SEG_HOLE,
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy SEG_DATA,
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy SEG_TYPES
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy} seg_type_t;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedytypedef struct segment {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy list_node_t seg_node;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg_type_t seg_type;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_t seg_offset;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_t seg_len;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy} seg_t;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedystatic int
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedyno_memory(void) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) fprintf(stderr, "malloc failed\n");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy return (UMEM_CALLBACK_EXIT(255));
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy}
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedystatic void
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedyusage(char *msg, int exit_value)
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy{
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) fprintf(stderr, "mkholes [-d|h offset:length] ... filename\n");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) fprintf(stderr, "%s\n", msg);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(exit_value);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy}
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedystatic char *
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedyget_random_buffer(size_t len)
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy{
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy int rand_fd;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy char *buf;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy buf = umem_alloc(len, UMEM_NOFAIL);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy /*
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * Fill the buffer from /dev/urandom to counteract the
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy * effects of compression.
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy */
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if ((rand_fd = open("/dev/urandom", O_RDONLY)) < 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("open /dev/urandom failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (read(rand_fd, buf, len) < 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("read /dev/urandom failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) close(rand_fd);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy return (buf);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy}
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedystatic void
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedypush_segment(list_t *seg_list, seg_type_t seg_type, char *optarg)
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy{
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy char *off_str, *len_str;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy static off_t file_size = 0;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_t off, len;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg_t *seg;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_str = strtok(optarg, ":");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy len_str = strtok(NULL, ":");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (off_str == NULL || len_str == NULL)
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy usage("Bad offset or length", 1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off = strtoull(off_str, NULL, 0);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy len = strtoull(len_str, NULL, 0);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (file_size >= off + len)
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy usage("Ranges must ascend and may not overlap.", 1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy file_size = off + len;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg = umem_alloc(sizeof (seg_t), UMEM_NOFAIL);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg->seg_type = seg_type;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg->seg_offset = off;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg->seg_len = len;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy list_insert_tail(seg_list, seg);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy}
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedyint
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedymain(int argc, char *argv[])
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy{
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy int c, fd;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy char *fname;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy list_t seg_list;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy seg_t *seg;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_nofail_callback(no_memory);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy list_create(&seg_list, sizeof (seg_t), offsetof(seg_t, seg_node));
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy while ((c = getopt(argc, argv, "d:h:")) != -1) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy switch (c) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy case 'd':
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy push_segment(&seg_list, SEG_DATA, optarg);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy break;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy case 'h':
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy push_segment(&seg_list, SEG_HOLE, optarg);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy break;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy argc -= optind;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy argv += optind;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if ((fname = argv[0]) == NULL)
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy usage("No filename specified", 1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy fname = argv[0];
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if ((fd = open(fname, O_LARGEFILE | O_RDWR | O_CREAT | O_SYNC,
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy 00666)) < 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("open failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy while ((seg = list_remove_head(&seg_list)) != NULL) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy char *buf, *vbuf;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_t off = seg->seg_offset;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_t len = seg->seg_len;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (seg->seg_type == SEG_HOLE) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy struct flock fl;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off_t bytes_read = 0;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy ssize_t readlen = 1024 * 1024 * 16;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy fl.l_whence = SEEK_SET;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy fl.l_start = off;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy fl.l_len = len;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (fcntl(fd, F_FREESP, &fl) != 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("freesp failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy buf = (char *)umem_alloc(readlen, UMEM_NOFAIL);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy vbuf = (char *)umem_zalloc(readlen, UMEM_NOFAIL);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy while (bytes_read < len) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy ssize_t bytes = pread(fd, buf, readlen, off);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (bytes < 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("pread hole failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (memcmp(buf, vbuf, bytes) != 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) fprintf(stderr, "Read back hole "
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy "didn't match.\n");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy bytes_read += bytes;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy off += bytes;
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_free(buf, readlen);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_free(vbuf, readlen);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_free(seg, sizeof (seg_t));
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy } else if (seg->seg_type == SEG_DATA) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy buf = get_random_buffer(len);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy vbuf = (char *)umem_alloc(len, UMEM_NOFAIL);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if ((pwrite(fd, buf, len, off)) < 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("pwrite failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if ((pread(fd, vbuf, len, off)) != len) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy perror("pread failed");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy if (memcmp(buf, vbuf, len) != 0) {
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) fprintf(stderr, "Read back buf didn't "
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy "match.\n");
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy exit(1);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_free(buf, len);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_free(vbuf, len);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy umem_free(seg, sizeof (seg_t));
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy }
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy (void) close(fd);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy return (0);
52244c0958bdf281ca42932b449f644b4decfdc2John Wren Kennedy}