Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tools/regression/ufs/uprintf/ufs_uprintf.c
48261 views
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
27
#include <err.h>
28
#include <errno.h>
29
#include <fcntl.h>
30
#include <limits.h>
31
#include <stdio.h>
32
#include <stdlib.h>
33
#include <string.h>
34
#include <unistd.h>
35
36
/*
37
* This regression test attempts to exercise two instances of uprintf(9) in
38
* UFS: (1) when blocks are exhausted, and (2) when inodes are exhausted, in
39
* order to attempt to trigger races in the uprintf(9) code. The test
40
* accepts a pointer to a path -- ideally, a very small UFS partition -- and
41
* then proceeds to fill it in various ways.
42
*
43
* This tool assumes that it is alright to create, and delete, entries in the
44
* directory with names of integer values. Don't run this tool against a
45
* directory that has files with names along those lines if you want to keep
46
* the files.
47
*
48
* Suggested usage is:
49
*
50
* mdconfig -a -t malloc -s 512
51
* newfs /dev/mdX
52
* mount /dev/mdX /mnt
53
* ufs_uprintf /mnt
54
* umount /mnt
55
* mdconfig -d -u X
56
*/
57
58
#define NUMTRIES 200
59
60
/*
61
* Fill up the disk, then generate NUMTRIES additional ENOSPC errors.
62
*/
63
#define BLOCKSIZE 1024
64
#define BLOCKS_FILENAME "0"
65
static void
66
fill_blocks(void)
67
{
68
char block[BLOCKSIZE];
69
ssize_t len;
70
int fd, i;
71
72
fd = open(BLOCKS_FILENAME, O_CREAT | O_TRUNC | O_RDWR, 0600);
73
if (fd < 0)
74
err(-1, "fill_blocks: open(%s)", BLOCKS_FILENAME);
75
76
/*
77
* First step: fill the disk device. Keep extending the file until
78
* we hit our first error, and hope it is ENOSPC.
79
*/
80
bzero(block, BLOCKSIZE);
81
errno = 0;
82
while (1) {
83
len = write(fd, block, BLOCKSIZE);
84
if (len < 0)
85
break;
86
if (len != BLOCKSIZE) {
87
warnx("fill_blocks: write(%d) returned %zd",
88
BLOCKSIZE, len);
89
close(fd);
90
(void)unlink(BLOCKS_FILENAME);
91
exit(-1);
92
}
93
94
}
95
if (errno != ENOSPC) {
96
warn("fill_blocks: write");
97
close(fd);
98
(void)unlink(BLOCKS_FILENAME);
99
exit(-1);
100
}
101
102
/*
103
* Second step: generate NUMTRIES instances of the error by retrying
104
* the write.
105
*/
106
for (i = 0; i < NUMTRIES; i++) {
107
len = write(fd, block, BLOCKSIZE);
108
if (len < 0 && errno != ENOSPC) {
109
warn("fill_blocks: write after ENOSPC");
110
close(fd);
111
(void)unlink(BLOCKS_FILENAME);
112
exit(-1);
113
}
114
}
115
116
close(fd);
117
(void)unlink(BLOCKS_FILENAME);
118
}
119
120
/*
121
* Create as many entries in the directory as we can, then once we start
122
* hitting ENOSPC, try NUMTRIES additional times. Note that we don't be able
123
* to tell the difference between running out of inodes and running out of
124
* room to extend the directory, so this is just a best effort.
125
*/
126
static void
127
fill_inodes(void)
128
{
129
char path[PATH_MAX];
130
int fd, i, max;
131
132
/*
133
* First step, fill the directory.
134
*/
135
i = 0;
136
while (1) {
137
snprintf(path, PATH_MAX, "%d", i);
138
fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
139
if (fd < 0)
140
break;
141
close(fd);
142
i++;
143
}
144
max = i;
145
if (errno != ENOSPC) {
146
warn("fill_inodes: open(%s)", path);
147
goto teardown;
148
}
149
150
for (i = 0; i < NUMTRIES; i++) {
151
fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0600);
152
if (fd < 0 && errno != ENOSPC) {
153
warn("fill_inodes: open(%s) after ENOSPC", path);
154
goto teardown;
155
}
156
if (fd >= 0) {
157
warnx("fill_inodes: open(%s) after ENOSPC returned "
158
" %d", path, fd);
159
close(fd);
160
goto teardown;
161
}
162
}
163
164
teardown:
165
for (i = 0; i < max; i++) {
166
snprintf(path, PATH_MAX, "%d", i);
167
(void)unlink(path);
168
}
169
}
170
171
int
172
main(int argc, char *argv[])
173
{
174
175
if (argc != 2)
176
err(-1, "usage: ufs_uprintf /non_optional_path");
177
178
if (chdir(argv[1]) < 0)
179
err(-1, "chdir(%s)", argv[1]);
180
181
fill_blocks();
182
183
fill_inodes();
184
185
return (0);
186
}
187
188