xref: /freebsd/tools/regression/ufs/uprintf/ufs_uprintf.c (revision 4039f071d0f25f9b04887dc7411e0e8983be0017)
15334bbbaSRobert Watson /*-
25334bbbaSRobert Watson  * Copyright (c) 2005 Robert N. M. Watson
35334bbbaSRobert Watson  * All rights reserved.
45334bbbaSRobert Watson  *
55334bbbaSRobert Watson  * Redistribution and use in source and binary forms, with or without
65334bbbaSRobert Watson  * modification, are permitted provided that the following conditions
75334bbbaSRobert Watson  * are met:
85334bbbaSRobert Watson  * 1. Redistributions of source code must retain the above copyright
95334bbbaSRobert Watson  *    notice, this list of conditions and the following disclaimer.
105334bbbaSRobert Watson  * 2. Redistributions in binary form must reproduce the above copyright
115334bbbaSRobert Watson  *    notice, this list of conditions and the following disclaimer in the
125334bbbaSRobert Watson  *    documentation and/or other materials provided with the distribution.
135334bbbaSRobert Watson  *
145334bbbaSRobert Watson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
155334bbbaSRobert Watson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
165334bbbaSRobert Watson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
175334bbbaSRobert Watson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
185334bbbaSRobert Watson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
195334bbbaSRobert Watson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
205334bbbaSRobert Watson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
215334bbbaSRobert Watson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
225334bbbaSRobert Watson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
235334bbbaSRobert Watson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
245334bbbaSRobert Watson  * SUCH DAMAGE.
255334bbbaSRobert Watson  *
265334bbbaSRobert Watson  * $FreeBSD$
275334bbbaSRobert Watson  */
285334bbbaSRobert Watson 
295334bbbaSRobert Watson #include <err.h>
305334bbbaSRobert Watson #include <errno.h>
315334bbbaSRobert Watson #include <fcntl.h>
325334bbbaSRobert Watson #include <limits.h>
335334bbbaSRobert Watson #include <stdio.h>
345334bbbaSRobert Watson #include <stdlib.h>
355334bbbaSRobert Watson #include <string.h>
365334bbbaSRobert Watson #include <unistd.h>
375334bbbaSRobert Watson 
385334bbbaSRobert Watson /*
395334bbbaSRobert Watson  * This regression test attempts to exercise two instances of uprintf(9) in
405334bbbaSRobert Watson  * UFS: (1) when blocks are exhausted, and (2) when inodes are exhausted, in
415334bbbaSRobert Watson  * order to attempt to trigger races in the uprintf(9) code.  The test
425334bbbaSRobert Watson  * accepts a pointer to a path -- ideally, a very small UFS partition -- and
435334bbbaSRobert Watson  * then proceeds to fill it in various ways.
445334bbbaSRobert Watson  *
455334bbbaSRobert Watson  * This tool assumes that it is alright to create, and delete, entries in the
465334bbbaSRobert Watson  * directory with names of integer values.  Don't run this tool against a
475334bbbaSRobert Watson  * directory that has files with names along those lines if you want to keep
485334bbbaSRobert Watson  * the files.
495334bbbaSRobert Watson  *
505334bbbaSRobert Watson  * Suggested usage is:
515334bbbaSRobert Watson  *
525334bbbaSRobert Watson  * mdconfig -a -t malloc -s 512
535334bbbaSRobert Watson  * newfs /dev/mdX
545334bbbaSRobert Watson  * mount /dev/mdX /mnt
555334bbbaSRobert Watson  * ufs_uprintf /mnt
565334bbbaSRobert Watson  * umount /mnt
575334bbbaSRobert Watson  * mdconfig -d -u X
585334bbbaSRobert Watson  */
595334bbbaSRobert Watson 
605334bbbaSRobert Watson #define	NUMTRIES	200
615334bbbaSRobert Watson 
625334bbbaSRobert Watson /*
635334bbbaSRobert Watson  * Fill up the disk, then generate NUMTRIES additional ENOSPC errors.
645334bbbaSRobert Watson  */
655334bbbaSRobert Watson #define	BLOCKSIZE	1024
665334bbbaSRobert Watson #define	BLOCKS_FILENAME	"0"
675334bbbaSRobert Watson static void
685334bbbaSRobert Watson fill_blocks(void)
695334bbbaSRobert Watson {
705334bbbaSRobert Watson 	char block[BLOCKSIZE];
715334bbbaSRobert Watson 	ssize_t len;
725334bbbaSRobert Watson 	int fd, i;
735334bbbaSRobert Watson 
745334bbbaSRobert Watson 	fd = open(BLOCKS_FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0600);
755334bbbaSRobert Watson 	if (fd < 0)
765334bbbaSRobert Watson 		err(-1, "fill_blocks: open(%s)", BLOCKS_FILENAME);
775334bbbaSRobert Watson 
785334bbbaSRobert Watson 	/*
795334bbbaSRobert Watson 	 * First step: fill the disk device.  Keep extending the file until
805334bbbaSRobert Watson 	 * we hit our first error, and hope it is ENOSPC.
815334bbbaSRobert Watson 	 */
825334bbbaSRobert Watson 	bzero(block, BLOCKSIZE);
835334bbbaSRobert Watson 	errno = 0;
845334bbbaSRobert Watson 	while (1) {
855334bbbaSRobert Watson 		len = write(fd, block, BLOCKSIZE);
865334bbbaSRobert Watson 		if (len < 0)
875334bbbaSRobert Watson 			break;
885334bbbaSRobert Watson 		if (len != BLOCKSIZE) {
89*4039f071SEd Maste 			warnx("fill_blocks: write(%d) returned %zd",
905334bbbaSRobert Watson 			    BLOCKSIZE, len);
915334bbbaSRobert Watson 			close(fd);
925334bbbaSRobert Watson 			(void)unlink(BLOCKS_FILENAME);
935334bbbaSRobert Watson 			exit(-1);
945334bbbaSRobert Watson 		}
955334bbbaSRobert Watson 
965334bbbaSRobert Watson 	}
975334bbbaSRobert Watson 	if (errno != ENOSPC) {
985334bbbaSRobert Watson 		warn("fill_blocks: write");
995334bbbaSRobert Watson 		close(fd);
1005334bbbaSRobert Watson 		(void)unlink(BLOCKS_FILENAME);
1015334bbbaSRobert Watson 		exit(-1);
1025334bbbaSRobert Watson 	}
1035334bbbaSRobert Watson 
1045334bbbaSRobert Watson 	/*
1055334bbbaSRobert Watson 	 * Second step: generate NUMTRIES instances of the error by retrying
1065334bbbaSRobert Watson 	 * the write.
1075334bbbaSRobert Watson 	 */
1085334bbbaSRobert Watson 	for (i = 0; i < NUMTRIES; i++) {
1095334bbbaSRobert Watson 		len = write(fd, block, BLOCKSIZE);
1105334bbbaSRobert Watson 		if (len < 0 && errno != ENOSPC) {
1115334bbbaSRobert Watson 			warn("fill_blocks: write after ENOSPC");
1125334bbbaSRobert Watson 			close(fd);
1135334bbbaSRobert Watson 			(void)unlink(BLOCKS_FILENAME);
1145334bbbaSRobert Watson 			exit(-1);
1155334bbbaSRobert Watson 		}
1165334bbbaSRobert Watson 	}
1175334bbbaSRobert Watson 
1185334bbbaSRobert Watson 	close(fd);
1195334bbbaSRobert Watson 	(void)unlink(BLOCKS_FILENAME);
1205334bbbaSRobert Watson }
1215334bbbaSRobert Watson 
1225334bbbaSRobert Watson /*
1235334bbbaSRobert Watson  * Create as many entries in the directory as we can, then once we start
1245334bbbaSRobert Watson  * hitting ENOSPC, try NUMTRIES additional times.  Note that we don't be able
1255334bbbaSRobert Watson  * to tell the difference between running out of inodes and running out of
1265334bbbaSRobert Watson  * room to extend the directory, so this is just a best effort.
1275334bbbaSRobert Watson  */
1285334bbbaSRobert Watson static void
1295334bbbaSRobert Watson fill_inodes(void)
1305334bbbaSRobert Watson {
1315334bbbaSRobert Watson 	char path[PATH_MAX];
1325334bbbaSRobert Watson 	int fd, i, max;
1335334bbbaSRobert Watson 
1345334bbbaSRobert Watson 	/*
1355334bbbaSRobert Watson 	 * First step, fill the directory.
1365334bbbaSRobert Watson 	 */
1375334bbbaSRobert Watson 	i = 0;
1385334bbbaSRobert Watson 	while (1) {
1395334bbbaSRobert Watson 		snprintf(path, PATH_MAX, "%d", i);
1405334bbbaSRobert Watson 		fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
1415334bbbaSRobert Watson 		if (fd < 0)
1425334bbbaSRobert Watson 			break;
1435334bbbaSRobert Watson 		close(fd);
1445334bbbaSRobert Watson 		i++;
1455334bbbaSRobert Watson 	}
1465334bbbaSRobert Watson 	max = i;
1475334bbbaSRobert Watson 	if (errno != ENOSPC) {
1485334bbbaSRobert Watson 		warn("fill_inodes: open(%s)", path);
1495334bbbaSRobert Watson 		goto teardown;
1505334bbbaSRobert Watson 	}
1515334bbbaSRobert Watson 
1525334bbbaSRobert Watson 	for (i = 0; i < NUMTRIES; i++) {
1535334bbbaSRobert Watson 		fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
1545334bbbaSRobert Watson 		if (fd < 0 && errno != ENOSPC) {
1555334bbbaSRobert Watson 			warn("fill_inodes: open(%s) after ENOSPC", path);
1565334bbbaSRobert Watson 			goto teardown;
1575334bbbaSRobert Watson 		}
1585334bbbaSRobert Watson 		if (fd >= 0) {
1595334bbbaSRobert Watson 			warnx("fill_inodes: open(%s) after ENOSPC returned "
1605334bbbaSRobert Watson 			    " %d", path, fd);
1615334bbbaSRobert Watson 			close(fd);
1625334bbbaSRobert Watson 			goto teardown;
1635334bbbaSRobert Watson 		}
1645334bbbaSRobert Watson 	}
1655334bbbaSRobert Watson 
1665334bbbaSRobert Watson teardown:
1675334bbbaSRobert Watson 	for (i = 0; i < max; i++) {
1685334bbbaSRobert Watson 		snprintf(path, PATH_MAX, "%d", i);
1695334bbbaSRobert Watson 		(void)unlink(path);
1705334bbbaSRobert Watson 	}
1715334bbbaSRobert Watson }
1725334bbbaSRobert Watson 
1735334bbbaSRobert Watson int
1745334bbbaSRobert Watson main(int argc, char *argv[])
1755334bbbaSRobert Watson {
1765334bbbaSRobert Watson 
1775334bbbaSRobert Watson 	if (argc != 2)
1785334bbbaSRobert Watson 		err(-1, "usage: ufs_uprintf /non_optional_path");
1795334bbbaSRobert Watson 
1805334bbbaSRobert Watson 	if (chdir(argv[1]) < 0)
1815334bbbaSRobert Watson 		err(-1, "chdir(%s)", argv[1]);
1825334bbbaSRobert Watson 
1835334bbbaSRobert Watson 	fill_blocks();
1845334bbbaSRobert Watson 
1855334bbbaSRobert Watson 	fill_inodes();
1865334bbbaSRobert Watson 
1875334bbbaSRobert Watson 	return (0);
1885334bbbaSRobert Watson }
189