1150332Srwatson/*- 2150332Srwatson * Copyright (c) 2005 Robert N. M. Watson 3150332Srwatson * All rights reserved. 4150332Srwatson * 5150332Srwatson * Redistribution and use in source and binary forms, with or without 6150332Srwatson * modification, are permitted provided that the following conditions 7150332Srwatson * are met: 8150332Srwatson * 1. Redistributions of source code must retain the above copyright 9150332Srwatson * notice, this list of conditions and the following disclaimer. 10150332Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11150332Srwatson * notice, this list of conditions and the following disclaimer in the 12150332Srwatson * documentation and/or other materials provided with the distribution. 13150332Srwatson * 14150332Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15150332Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16150332Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17150332Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18150332Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19150332Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20150332Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21150332Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22150332Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23150332Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24150332Srwatson * SUCH DAMAGE. 25150332Srwatson * 26150332Srwatson * $FreeBSD: releng/11.0/tools/regression/ufs/uprintf/ufs_uprintf.c 243316 2012-11-19 23:07:38Z emaste $ 27150332Srwatson */ 28150332Srwatson 29150332Srwatson#include <err.h> 30150332Srwatson#include <errno.h> 31150332Srwatson#include <fcntl.h> 32150332Srwatson#include <limits.h> 33150332Srwatson#include <stdio.h> 34150332Srwatson#include <stdlib.h> 35150332Srwatson#include <string.h> 36150332Srwatson#include <unistd.h> 37150332Srwatson 38150332Srwatson/* 39150332Srwatson * This regression test attempts to exercise two instances of uprintf(9) in 40150332Srwatson * UFS: (1) when blocks are exhausted, and (2) when inodes are exhausted, in 41150332Srwatson * order to attempt to trigger races in the uprintf(9) code. The test 42150332Srwatson * accepts a pointer to a path -- ideally, a very small UFS partition -- and 43150332Srwatson * then proceeds to fill it in various ways. 44150332Srwatson * 45150332Srwatson * This tool assumes that it is alright to create, and delete, entries in the 46150332Srwatson * directory with names of integer values. Don't run this tool against a 47150332Srwatson * directory that has files with names along those lines if you want to keep 48150332Srwatson * the files. 49150332Srwatson * 50150332Srwatson * Suggested usage is: 51150332Srwatson * 52150332Srwatson * mdconfig -a -t malloc -s 512 53150332Srwatson * newfs /dev/mdX 54150332Srwatson * mount /dev/mdX /mnt 55150332Srwatson * ufs_uprintf /mnt 56150332Srwatson * umount /mnt 57150332Srwatson * mdconfig -d -u X 58150332Srwatson */ 59150332Srwatson 60150332Srwatson#define NUMTRIES 200 61150332Srwatson 62150332Srwatson/* 63150332Srwatson * Fill up the disk, then generate NUMTRIES additional ENOSPC errors. 64150332Srwatson */ 65150332Srwatson#define BLOCKSIZE 1024 66150332Srwatson#define BLOCKS_FILENAME "0" 67150332Srwatsonstatic void 68150332Srwatsonfill_blocks(void) 69150332Srwatson{ 70150332Srwatson char block[BLOCKSIZE]; 71150332Srwatson ssize_t len; 72150332Srwatson int fd, i; 73150332Srwatson 74150332Srwatson fd = open(BLOCKS_FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0600); 75150332Srwatson if (fd < 0) 76150332Srwatson err(-1, "fill_blocks: open(%s)", BLOCKS_FILENAME); 77150332Srwatson 78150332Srwatson /* 79150332Srwatson * First step: fill the disk device. Keep extending the file until 80150332Srwatson * we hit our first error, and hope it is ENOSPC. 81150332Srwatson */ 82150332Srwatson bzero(block, BLOCKSIZE); 83150332Srwatson errno = 0; 84150332Srwatson while (1) { 85150332Srwatson len = write(fd, block, BLOCKSIZE); 86150332Srwatson if (len < 0) 87150332Srwatson break; 88150332Srwatson if (len != BLOCKSIZE) { 89243316Semaste warnx("fill_blocks: write(%d) returned %zd", 90150332Srwatson BLOCKSIZE, len); 91150332Srwatson close(fd); 92150332Srwatson (void)unlink(BLOCKS_FILENAME); 93150332Srwatson exit(-1); 94150332Srwatson } 95150332Srwatson 96150332Srwatson } 97150332Srwatson if (errno != ENOSPC) { 98150332Srwatson warn("fill_blocks: write"); 99150332Srwatson close(fd); 100150332Srwatson (void)unlink(BLOCKS_FILENAME); 101150332Srwatson exit(-1); 102150332Srwatson } 103150332Srwatson 104150332Srwatson /* 105150332Srwatson * Second step: generate NUMTRIES instances of the error by retrying 106150332Srwatson * the write. 107150332Srwatson */ 108150332Srwatson for (i = 0; i < NUMTRIES; i++) { 109150332Srwatson len = write(fd, block, BLOCKSIZE); 110150332Srwatson if (len < 0 && errno != ENOSPC) { 111150332Srwatson warn("fill_blocks: write after ENOSPC"); 112150332Srwatson close(fd); 113150332Srwatson (void)unlink(BLOCKS_FILENAME); 114150332Srwatson exit(-1); 115150332Srwatson } 116150332Srwatson } 117150332Srwatson 118150332Srwatson close(fd); 119150332Srwatson (void)unlink(BLOCKS_FILENAME); 120150332Srwatson} 121150332Srwatson 122150332Srwatson/* 123150332Srwatson * Create as many entries in the directory as we can, then once we start 124150332Srwatson * hitting ENOSPC, try NUMTRIES additional times. Note that we don't be able 125150332Srwatson * to tell the difference between running out of inodes and running out of 126150332Srwatson * room to extend the directory, so this is just a best effort. 127150332Srwatson */ 128150332Srwatsonstatic void 129150332Srwatsonfill_inodes(void) 130150332Srwatson{ 131150332Srwatson char path[PATH_MAX]; 132150332Srwatson int fd, i, max; 133150332Srwatson 134150332Srwatson /* 135150332Srwatson * First step, fill the directory. 136150332Srwatson */ 137150332Srwatson i = 0; 138150332Srwatson while (1) { 139150332Srwatson snprintf(path, PATH_MAX, "%d", i); 140150332Srwatson fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600); 141150332Srwatson if (fd < 0) 142150332Srwatson break; 143150332Srwatson close(fd); 144150332Srwatson i++; 145150332Srwatson } 146150332Srwatson max = i; 147150332Srwatson if (errno != ENOSPC) { 148150332Srwatson warn("fill_inodes: open(%s)", path); 149150332Srwatson goto teardown; 150150332Srwatson } 151150332Srwatson 152150332Srwatson for (i = 0; i < NUMTRIES; i++) { 153150332Srwatson fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600); 154150332Srwatson if (fd < 0 && errno != ENOSPC) { 155150332Srwatson warn("fill_inodes: open(%s) after ENOSPC", path); 156150332Srwatson goto teardown; 157150332Srwatson } 158150332Srwatson if (fd >= 0) { 159150332Srwatson warnx("fill_inodes: open(%s) after ENOSPC returned " 160150332Srwatson " %d", path, fd); 161150332Srwatson close(fd); 162150332Srwatson goto teardown; 163150332Srwatson } 164150332Srwatson } 165150332Srwatson 166150332Srwatsonteardown: 167150332Srwatson for (i = 0; i < max; i++) { 168150332Srwatson snprintf(path, PATH_MAX, "%d", i); 169150332Srwatson (void)unlink(path); 170150332Srwatson } 171150332Srwatson} 172150332Srwatson 173150332Srwatsonint 174150332Srwatsonmain(int argc, char *argv[]) 175150332Srwatson{ 176150332Srwatson 177150332Srwatson if (argc != 2) 178150332Srwatson err(-1, "usage: ufs_uprintf /non_optional_path"); 179150332Srwatson 180150332Srwatson if (chdir(argv[1]) < 0) 181150332Srwatson err(-1, "chdir(%s)", argv[1]); 182150332Srwatson 183150332Srwatson fill_blocks(); 184150332Srwatson 185150332Srwatson fill_inodes(); 186150332Srwatson 187150332Srwatson return (0); 188150332Srwatson} 189