xref: /freebsd/tools/regression/ufs/uprintf/ufs_uprintf.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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 
275334bbbaSRobert Watson #include <err.h>
285334bbbaSRobert Watson #include <errno.h>
295334bbbaSRobert Watson #include <fcntl.h>
305334bbbaSRobert Watson #include <limits.h>
315334bbbaSRobert Watson #include <stdio.h>
325334bbbaSRobert Watson #include <stdlib.h>
335334bbbaSRobert Watson #include <string.h>
345334bbbaSRobert Watson #include <unistd.h>
355334bbbaSRobert Watson 
365334bbbaSRobert Watson /*
375334bbbaSRobert Watson  * This regression test attempts to exercise two instances of uprintf(9) in
385334bbbaSRobert Watson  * UFS: (1) when blocks are exhausted, and (2) when inodes are exhausted, in
395334bbbaSRobert Watson  * order to attempt to trigger races in the uprintf(9) code.  The test
405334bbbaSRobert Watson  * accepts a pointer to a path -- ideally, a very small UFS partition -- and
415334bbbaSRobert Watson  * then proceeds to fill it in various ways.
425334bbbaSRobert Watson  *
435334bbbaSRobert Watson  * This tool assumes that it is alright to create, and delete, entries in the
445334bbbaSRobert Watson  * directory with names of integer values.  Don't run this tool against a
455334bbbaSRobert Watson  * directory that has files with names along those lines if you want to keep
465334bbbaSRobert Watson  * the files.
475334bbbaSRobert Watson  *
485334bbbaSRobert Watson  * Suggested usage is:
495334bbbaSRobert Watson  *
505334bbbaSRobert Watson  * mdconfig -a -t malloc -s 512
515334bbbaSRobert Watson  * newfs /dev/mdX
525334bbbaSRobert Watson  * mount /dev/mdX /mnt
535334bbbaSRobert Watson  * ufs_uprintf /mnt
545334bbbaSRobert Watson  * umount /mnt
555334bbbaSRobert Watson  * mdconfig -d -u X
565334bbbaSRobert Watson  */
575334bbbaSRobert Watson 
585334bbbaSRobert Watson #define	NUMTRIES	200
595334bbbaSRobert Watson 
605334bbbaSRobert Watson /*
615334bbbaSRobert Watson  * Fill up the disk, then generate NUMTRIES additional ENOSPC errors.
625334bbbaSRobert Watson  */
635334bbbaSRobert Watson #define	BLOCKSIZE	1024
645334bbbaSRobert Watson #define	BLOCKS_FILENAME	"0"
655334bbbaSRobert Watson static void
fill_blocks(void)665334bbbaSRobert Watson fill_blocks(void)
675334bbbaSRobert Watson {
685334bbbaSRobert Watson 	char block[BLOCKSIZE];
695334bbbaSRobert Watson 	ssize_t len;
705334bbbaSRobert Watson 	int fd, i;
715334bbbaSRobert Watson 
725334bbbaSRobert Watson 	fd = open(BLOCKS_FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0600);
735334bbbaSRobert Watson 	if (fd < 0)
745334bbbaSRobert Watson 		err(-1, "fill_blocks: open(%s)", BLOCKS_FILENAME);
755334bbbaSRobert Watson 
765334bbbaSRobert Watson 	/*
775334bbbaSRobert Watson 	 * First step: fill the disk device.  Keep extending the file until
785334bbbaSRobert Watson 	 * we hit our first error, and hope it is ENOSPC.
795334bbbaSRobert Watson 	 */
805334bbbaSRobert Watson 	bzero(block, BLOCKSIZE);
815334bbbaSRobert Watson 	errno = 0;
825334bbbaSRobert Watson 	while (1) {
835334bbbaSRobert Watson 		len = write(fd, block, BLOCKSIZE);
845334bbbaSRobert Watson 		if (len < 0)
855334bbbaSRobert Watson 			break;
865334bbbaSRobert Watson 		if (len != BLOCKSIZE) {
87*4039f071SEd Maste 			warnx("fill_blocks: write(%d) returned %zd",
885334bbbaSRobert Watson 			    BLOCKSIZE, len);
895334bbbaSRobert Watson 			close(fd);
905334bbbaSRobert Watson 			(void)unlink(BLOCKS_FILENAME);
915334bbbaSRobert Watson 			exit(-1);
925334bbbaSRobert Watson 		}
935334bbbaSRobert Watson 
945334bbbaSRobert Watson 	}
955334bbbaSRobert Watson 	if (errno != ENOSPC) {
965334bbbaSRobert Watson 		warn("fill_blocks: write");
975334bbbaSRobert Watson 		close(fd);
985334bbbaSRobert Watson 		(void)unlink(BLOCKS_FILENAME);
995334bbbaSRobert Watson 		exit(-1);
1005334bbbaSRobert Watson 	}
1015334bbbaSRobert Watson 
1025334bbbaSRobert Watson 	/*
1035334bbbaSRobert Watson 	 * Second step: generate NUMTRIES instances of the error by retrying
1045334bbbaSRobert Watson 	 * the write.
1055334bbbaSRobert Watson 	 */
1065334bbbaSRobert Watson 	for (i = 0; i < NUMTRIES; i++) {
1075334bbbaSRobert Watson 		len = write(fd, block, BLOCKSIZE);
1085334bbbaSRobert Watson 		if (len < 0 && errno != ENOSPC) {
1095334bbbaSRobert Watson 			warn("fill_blocks: write after ENOSPC");
1105334bbbaSRobert Watson 			close(fd);
1115334bbbaSRobert Watson 			(void)unlink(BLOCKS_FILENAME);
1125334bbbaSRobert Watson 			exit(-1);
1135334bbbaSRobert Watson 		}
1145334bbbaSRobert Watson 	}
1155334bbbaSRobert Watson 
1165334bbbaSRobert Watson 	close(fd);
1175334bbbaSRobert Watson 	(void)unlink(BLOCKS_FILENAME);
1185334bbbaSRobert Watson }
1195334bbbaSRobert Watson 
1205334bbbaSRobert Watson /*
1215334bbbaSRobert Watson  * Create as many entries in the directory as we can, then once we start
1225334bbbaSRobert Watson  * hitting ENOSPC, try NUMTRIES additional times.  Note that we don't be able
1235334bbbaSRobert Watson  * to tell the difference between running out of inodes and running out of
1245334bbbaSRobert Watson  * room to extend the directory, so this is just a best effort.
1255334bbbaSRobert Watson  */
1265334bbbaSRobert Watson static void
fill_inodes(void)1275334bbbaSRobert Watson fill_inodes(void)
1285334bbbaSRobert Watson {
1295334bbbaSRobert Watson 	char path[PATH_MAX];
1305334bbbaSRobert Watson 	int fd, i, max;
1315334bbbaSRobert Watson 
1325334bbbaSRobert Watson 	/*
1335334bbbaSRobert Watson 	 * First step, fill the directory.
1345334bbbaSRobert Watson 	 */
1355334bbbaSRobert Watson 	i = 0;
1365334bbbaSRobert Watson 	while (1) {
1375334bbbaSRobert Watson 		snprintf(path, PATH_MAX, "%d", i);
1385334bbbaSRobert Watson 		fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
1395334bbbaSRobert Watson 		if (fd < 0)
1405334bbbaSRobert Watson 			break;
1415334bbbaSRobert Watson 		close(fd);
1425334bbbaSRobert Watson 		i++;
1435334bbbaSRobert Watson 	}
1445334bbbaSRobert Watson 	max = i;
1455334bbbaSRobert Watson 	if (errno != ENOSPC) {
1465334bbbaSRobert Watson 		warn("fill_inodes: open(%s)", path);
1475334bbbaSRobert Watson 		goto teardown;
1485334bbbaSRobert Watson 	}
1495334bbbaSRobert Watson 
1505334bbbaSRobert Watson 	for (i = 0; i < NUMTRIES; i++) {
1515334bbbaSRobert Watson 		fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
1525334bbbaSRobert Watson 		if (fd < 0 && errno != ENOSPC) {
1535334bbbaSRobert Watson 			warn("fill_inodes: open(%s) after ENOSPC", path);
1545334bbbaSRobert Watson 			goto teardown;
1555334bbbaSRobert Watson 		}
1565334bbbaSRobert Watson 		if (fd >= 0) {
1575334bbbaSRobert Watson 			warnx("fill_inodes: open(%s) after ENOSPC returned "
1585334bbbaSRobert Watson 			    " %d", path, fd);
1595334bbbaSRobert Watson 			close(fd);
1605334bbbaSRobert Watson 			goto teardown;
1615334bbbaSRobert Watson 		}
1625334bbbaSRobert Watson 	}
1635334bbbaSRobert Watson 
1645334bbbaSRobert Watson teardown:
1655334bbbaSRobert Watson 	for (i = 0; i < max; i++) {
1665334bbbaSRobert Watson 		snprintf(path, PATH_MAX, "%d", i);
1675334bbbaSRobert Watson 		(void)unlink(path);
1685334bbbaSRobert Watson 	}
1695334bbbaSRobert Watson }
1705334bbbaSRobert Watson 
1715334bbbaSRobert Watson int
main(int argc,char * argv[])1725334bbbaSRobert Watson main(int argc, char *argv[])
1735334bbbaSRobert Watson {
1745334bbbaSRobert Watson 
1755334bbbaSRobert Watson 	if (argc != 2)
1765334bbbaSRobert Watson 		err(-1, "usage: ufs_uprintf /non_optional_path");
1775334bbbaSRobert Watson 
1785334bbbaSRobert Watson 	if (chdir(argv[1]) < 0)
1795334bbbaSRobert Watson 		err(-1, "chdir(%s)", argv[1]);
1805334bbbaSRobert Watson 
1815334bbbaSRobert Watson 	fill_blocks();
1825334bbbaSRobert Watson 
1835334bbbaSRobert Watson 	fill_inodes();
1845334bbbaSRobert Watson 
1855334bbbaSRobert Watson 	return (0);
1865334bbbaSRobert Watson }
187