]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/regression/ufs/uprintf/ufs_uprintf.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / regression / ufs / uprintf / ufs_uprintf.c
1 /*-
2  * Copyright (c) 2005 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28
29 #include <err.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <limits.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 /*
39  * This regression test attempts to exercise two instances of uprintf(9) in
40  * UFS: (1) when blocks are exhausted, and (2) when inodes are exhausted, in
41  * order to attempt to trigger races in the uprintf(9) code.  The test
42  * accepts a pointer to a path -- ideally, a very small UFS partition -- and
43  * then proceeds to fill it in various ways.
44  *
45  * This tool assumes that it is alright to create, and delete, entries in the
46  * directory with names of integer values.  Don't run this tool against a
47  * directory that has files with names along those lines if you want to keep
48  * the files.
49  *
50  * Suggested usage is:
51  *
52  * mdconfig -a -t malloc -s 512
53  * newfs /dev/mdX
54  * mount /dev/mdX /mnt
55  * ufs_uprintf /mnt
56  * umount /mnt
57  * mdconfig -d -u X
58  */
59
60 #define NUMTRIES        200
61
62 /*
63  * Fill up the disk, then generate NUMTRIES additional ENOSPC errors.
64  */
65 #define BLOCKSIZE       1024
66 #define BLOCKS_FILENAME "0"
67 static void
68 fill_blocks(void)
69 {
70         char block[BLOCKSIZE];
71         ssize_t len;
72         int fd, i;
73
74         fd = open(BLOCKS_FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0600);
75         if (fd < 0)
76                 err(-1, "fill_blocks: open(%s)", BLOCKS_FILENAME);
77
78         /*
79          * First step: fill the disk device.  Keep extending the file until
80          * we hit our first error, and hope it is ENOSPC.
81          */
82         bzero(block, BLOCKSIZE);
83         errno = 0;
84         while (1) {
85                 len = write(fd, block, BLOCKSIZE);
86                 if (len < 0)
87                         break;
88                 if (len != BLOCKSIZE) {
89                         warnx("fill_blocks: write(%d) returned %zd",
90                             BLOCKSIZE, len);
91                         close(fd);
92                         (void)unlink(BLOCKS_FILENAME);
93                         exit(-1);
94                 }
95
96         }
97         if (errno != ENOSPC) {
98                 warn("fill_blocks: write");
99                 close(fd);
100                 (void)unlink(BLOCKS_FILENAME);
101                 exit(-1);
102         }
103
104         /*
105          * Second step: generate NUMTRIES instances of the error by retrying
106          * the write.
107          */
108         for (i = 0; i < NUMTRIES; i++) {
109                 len = write(fd, block, BLOCKSIZE);
110                 if (len < 0 && errno != ENOSPC) {
111                         warn("fill_blocks: write after ENOSPC");
112                         close(fd);
113                         (void)unlink(BLOCKS_FILENAME);
114                         exit(-1);
115                 }
116         }
117
118         close(fd);
119         (void)unlink(BLOCKS_FILENAME);
120 }
121
122 /*
123  * Create as many entries in the directory as we can, then once we start
124  * hitting ENOSPC, try NUMTRIES additional times.  Note that we don't be able
125  * to tell the difference between running out of inodes and running out of
126  * room to extend the directory, so this is just a best effort.
127  */
128 static void
129 fill_inodes(void)
130 {
131         char path[PATH_MAX];
132         int fd, i, max;
133
134         /*
135          * First step, fill the directory.
136          */
137         i = 0;
138         while (1) {
139                 snprintf(path, PATH_MAX, "%d", i);
140                 fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
141                 if (fd < 0)
142                         break;
143                 close(fd);
144                 i++;
145         }
146         max = i;
147         if (errno != ENOSPC) {
148                 warn("fill_inodes: open(%s)", path);
149                 goto teardown;
150         }
151
152         for (i = 0; i < NUMTRIES; i++) {
153                 fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
154                 if (fd < 0 && errno != ENOSPC) {
155                         warn("fill_inodes: open(%s) after ENOSPC", path);
156                         goto teardown;
157                 }
158                 if (fd >= 0) {
159                         warnx("fill_inodes: open(%s) after ENOSPC returned "
160                             " %d", path, fd);
161                         close(fd);
162                         goto teardown;
163                 }
164         }
165
166 teardown:
167         for (i = 0; i < max; i++) {
168                 snprintf(path, PATH_MAX, "%d", i);
169                 (void)unlink(path);
170         }
171 }
172
173 int
174 main(int argc, char *argv[])
175 {
176
177         if (argc != 2)
178                 err(-1, "usage: ufs_uprintf /non_optional_path");
179
180         if (chdir(argv[1]) < 0)
181                 err(-1, "chdir(%s)", argv[1]);
182
183         fill_blocks();
184
185         fill_inodes();
186
187         return (0);
188 }