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