1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
|
/*
* @(#)bigfile.c 1.2 98/12/19 Connectathon Testsuite
*/
/*
* Write and reread a large file. This potentially covers a few problems
* that have appeared in the past:
* - inability of server to commit a large file range with one RPC
* - client's dirtying memory faster than it can clean it
* - server's returning bogus file attributes, confusing the client
* - client and server not propagating "filesystem full" errors back to the
* application
*/
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#ifdef MMAP
#include <sys/mman.h>
#endif
#include "../tests.h"
static char usage[] = "usage: bigfile [-s size_in_MB] filename";
static off_t file_size = 30 * 1024 * 1024;
static char *filename; /* name of test file */
static int buffer_size = 8192; /* size of read/write buffer */
#ifdef MMAP
static long pagesize;
#endif
static void dump_buf ARGS_((char *, int));
static void io_error ARGS_((int, char *));
static unsigned char testval ARGS_((off_t));
static int verify ARGS_((char *, long, int));
static void write_read ARGS_((int));
#ifdef MMAP
static void write_read_mmap ARGS_((int));
#endif
int
main(argc, argv)
int argc;
char **argv;
{
int c;
off_t size;
int fd;
extern int optind;
extern char *optarg;
#ifdef MMAP
pagesize = sysconf(_SC_PAGESIZE);
if (pagesize < 0) {
fprintf(stderr, "can't get page size\n");
exit(1);
}
#endif
while ((c = getopt(argc, argv, "s:")) != EOF)
switch (c) {
case 's':
size = atol(optarg) * 1024 * 1024;
if (size > 0)
file_size = size;
break;
case '?':
fprintf(stderr, "%s\n", usage);
exit(1);
break;
}
if (optind != argc - 1) {
fprintf(stderr, "%s\n", usage);
exit(1);
}
filename = argv[optind];
fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0666);
if (fd < 0) {
fprintf(stderr, "can't create %s: %s\n",
filename, strerror(errno));
exit(1);
}
write_read(fd);
#ifdef MMAP
write_read_mmap(fd);
#endif
if (unlink(filename) < 0) {
fprintf(stderr, "can't unlink %s: %s\n",
filename, strerror(errno));
exit(1);
}
exit(0);
}
/*
* Write and then reread the file, using regular read/write calls. If the
* filesystem fills up, exit with a warning message. For any other error,
* exit with an error message.
*/
static void
write_read(fd)
int fd;
{
long numbufs = file_size / buffer_size;
char *buf;
int i;
buf = malloc(buffer_size);
if (buf == 0) {
fprintf(stderr, "can't allocate read/write buffer\n");
exit(1);
}
/*
* Fill the file with unsigned chars. Change the value for each
* buffer written.
*/
for (i = 0; i < numbufs; i++) {
unsigned char val = testval(i);
int bytes_written;
memset(buf, val, buffer_size);
bytes_written = write(fd, buf, buffer_size);
if (bytes_written < 0) {
int error = errno;
char errmsg[1024];
sprintf(errmsg, "write to %s failed: %s",
filename, strerror(errno));
io_error(error, errmsg);
} else if (bytes_written < buffer_size) {
fprintf(stderr, "short write (%d) to %s\n",
bytes_written, filename);
exit(1);
}
}
if (fsync(fd) < 0) {
char errmsg[1024];
int error = errno;
sprintf(errmsg, "can't sync %s: %s", filename,
strerror(error));
io_error(error, errmsg);
}
/*
* Close and reopen the file, in case that prompts the client to
* throw anything away.
*/
if (close(fd) < 0) {
char errmsg[1024];
int error = errno;
sprintf(errmsg, "can't close %s: %s", filename,
strerror(error));
io_error(error, errmsg);
}
fd = open(filename, O_RDWR, 0666);
if (fd < 0) {
fprintf(stderr, "can't reopen %s: %s\n",
filename, strerror(errno));
exit(1);
}
/*
* Reread the file and make sure it has correct bits.
*/
for (i = 0; i < numbufs; i++) {
unsigned char val = testval(i);
int bytes_read;
if (lseek(fd, i * buffer_size, SEEK_SET) < 0) {
fprintf(stderr, "seek to %ld failed: %s\n",
(long)i * buffer_size,
strerror(errno));
exit(1);
}
bytes_read = read(fd, buf, buffer_size);
if (bytes_read < 0) {
int error = errno;
char errmsg[1024];
sprintf(errmsg, "read from %s failed: %s",
filename, strerror(errno));
io_error(error, errmsg);
} else if (bytes_read < buffer_size) {
fprintf(stderr, "short read (%d) to %s\n",
bytes_read, filename);
exit(1);
}
if (!verify(buf, buffer_size, val)) {
fprintf(stderr, "verify failed, offset %ld; ",
(long)i * buffer_size);
fprintf(stderr, "expected %x, got \n",
val);
dump_buf(buf, buffer_size);
exit(1);
}
}
}
/*
* Return non-zero if the given buffer is full of the given value.
* Otherwise, return zero.
*/
static int
verify(buf, bufsize, val)
char *buf;
long bufsize;
unsigned char val;
{
int i;
for (i = 0; i < bufsize; i++) {
if ((unsigned char)(buf[i]) != val)
return (0);
}
return (1);
}
/*
* Print the contents of the buffer in hex to stderr.
*/
static void
dump_buf(buf, bufsize)
char *buf;
int bufsize;
{
int i;
for (i = 0; i < bufsize; i++) {
fprintf(stderr, "%x ", buf[i]);
if ((i + 1) % 10 == 0)
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
/*
* Write out the given error message and exit. If the error is because
* there is no more space, flag it as a warning, and delete the file.
* Otherwise, flag it as an error and leave the file alone.
*/
static void
io_error(error, errmsg)
int error; /* errno value */
char *errmsg;
{
if (error == EDQUOT || error == ENOSPC)
fprintf(stderr, "Warning: can't complete test: ");
else
fprintf(stderr, "Error: ");
fprintf(stderr, "%s\n", errmsg);
if (error == EDQUOT || error == ENOSPC)
unlink(filename);
exit(1);
}
/*
* Return the test value for the given offset.
*/
static unsigned char
testval(offset)
off_t offset;
{
return 'a' + (offset % 26);
}
#ifdef MMAP
/*
* Write and then randomly reread the file, by mapping it. Same error
* handling as write_read().
*/
static void
write_read_mmap(fd)
int fd;
{
long numpages = file_size / pagesize;
char *buf;
int i;
/*
* Truncate the file and then map it in (the entire file). Then
* fill it with unsigned chars, the same as write_read().
*/
if (ftruncate(fd, 0) < 0) {
fprintf(stderr, "can't truncate %s: %s\n",
filename, strerror(errno));
exit(1);
}
if (ftruncate(fd, file_size) < 0) {
int error = errno;
char errmsg[1024];
sprintf(errmsg, "write to %s failed: %s",
filename, strerror(errno));
io_error(error, errmsg);
}
buf = mmap(0, file_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if (buf == (char *)MAP_FAILED) {
fprintf(stderr, "can't map %s for writing: %s\n",
filename, strerror(errno));
exit(1);
}
for (i = 0; i < numpages; i++) {
unsigned char val = testval(i);
memset(buf + i * pagesize, val, pagesize);
}
if (msync(buf, file_size, MS_SYNC | MS_INVALIDATE) < 0) {
char errmsg[1024];
int error = errno;
sprintf(errmsg, "can't msync %s: %s", filename,
strerror(error));
io_error(error, errmsg);
}
if (munmap(buf, file_size) < 0) {
char errmsg[1024];
int error = errno;
sprintf(errmsg, "can't munmap %s: %s", filename,
strerror(error));
io_error(error, errmsg);
}
/*
* Reread the file, a page at a time, and make sure it has correct
* bits.
*/
for (i = 0; i < numpages; i++) {
unsigned char val = testval(i);
buf = mmap(0, pagesize, PROT_READ, MAP_SHARED, fd,
i * pagesize);
if (buf == (char *)MAP_FAILED) {
fprintf(stderr, "can't map %s for reading: %s\n",
filename, strerror(errno));
exit(1);
}
if (!verify(buf, pagesize, val)) {
fprintf(stderr,
"verify of mapped file failed, offset %ld; ",
(long)i * pagesize);
fprintf(stderr, "expected %x, got \n",
val);
dump_buf(buf, pagesize);
exit(1);
}
if (munmap(buf, pagesize) < 0) {
fprintf(stderr,
"can't unmap file after verifying: %s\n",
strerror(errno));
exit(1);
}
}
}
#endif /* MMAP */
|