Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
script3r
GitHub Repository: script3r/os161
Path: blob/master/kern/test/fstest.c
2091 views
1
/*
2
* Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
3
* The President and Fellows of Harvard College.
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
* 3. Neither the name of the University nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*/
29
30
/*
31
* fstest - filesystem test code
32
*
33
* Writes a file (in small chunks) and then reads it back again
34
* (also in small chunks) and complains if what it reads back is
35
* not the same.
36
*
37
* The length of SLOGAN is intentionally a prime number and
38
* specifically *not* a power of two.
39
*/
40
41
#include <types.h>
42
#include <kern/errno.h>
43
#include <kern/fcntl.h>
44
#include <lib.h>
45
#include <uio.h>
46
#include <thread.h>
47
#include <synch.h>
48
#include <vfs.h>
49
#include <fs.h>
50
#include <vnode.h>
51
#include <test.h>
52
53
#define SLOGAN "HODIE MIHI - CRAS TIBI\n"
54
#define FILENAME "fstest.tmp"
55
#define NCHUNKS 720
56
#define NTHREADS 12
57
#define NCREATES 32
58
59
static struct semaphore *threadsem = NULL;
60
61
static
62
void
63
init_threadsem(void)
64
{
65
if (threadsem==NULL) {
66
threadsem = sem_create("fstestsem", 0);
67
if (threadsem == NULL) {
68
panic("fstest: sem_create failed\n");
69
}
70
}
71
}
72
73
/*
74
* Vary each line of the test file in a way that's predictable but
75
* unlikely to mask bugs in the filesystem.
76
*/
77
static
78
void
79
rotate(char *str, int amt)
80
{
81
int i, ch;
82
83
amt = (amt+2600)%26;
84
KASSERT(amt>=0);
85
86
for (i=0; str[i]; i++) {
87
ch = str[i];
88
if (ch>='A' && ch<='Z') {
89
ch = ch - 'A';
90
ch += amt;
91
ch %= 26;
92
ch = ch + 'A';
93
KASSERT(ch>='A' && ch<='Z');
94
}
95
str[i] = ch;
96
}
97
}
98
99
////////////////////////////////////////////////////////////
100
101
static
102
void
103
fstest_makename(char *buf, size_t buflen,
104
const char *fs, const char *namesuffix)
105
{
106
snprintf(buf, buflen, "%s:%s%s", fs, FILENAME, namesuffix);
107
KASSERT(strlen(buf) < buflen);
108
}
109
110
#define MAKENAME() fstest_makename(name, sizeof(name), fs, namesuffix)
111
112
static
113
int
114
fstest_remove(const char *fs, const char *namesuffix)
115
{
116
char name[32];
117
char buf[32];
118
int err;
119
120
MAKENAME();
121
122
strcpy(buf, name);
123
err = vfs_remove(buf);
124
if (err) {
125
kprintf("Could not remove %s: %s\n", name, strerror(err));
126
return -1;
127
}
128
129
return 0;
130
}
131
132
static
133
int
134
fstest_write(const char *fs, const char *namesuffix,
135
int stridesize, int stridepos)
136
{
137
struct vnode *vn;
138
int err;
139
int i;
140
size_t shouldbytes=0;
141
size_t bytes=0;
142
off_t pos=0;
143
char name[32];
144
char buf[32];
145
struct iovec iov;
146
struct uio ku;
147
int flags;
148
149
KASSERT(sizeof(buf) > strlen(SLOGAN));
150
151
MAKENAME();
152
153
flags = O_WRONLY|O_CREAT;
154
if (stridesize == 1) {
155
flags |= O_TRUNC;
156
}
157
158
/* vfs_open destroys the string it's passed */
159
strcpy(buf, name);
160
err = vfs_open(buf, flags, 0664, &vn);
161
if (err) {
162
kprintf("Could not open %s for write: %s\n",
163
name, strerror(err));
164
return -1;
165
}
166
167
for (i=0; i<NCHUNKS; i++) {
168
if (i % stridesize != stridepos) {
169
pos += strlen(SLOGAN);
170
continue;
171
}
172
strcpy(buf, SLOGAN);
173
rotate(buf, i);
174
uio_kinit(&iov, &ku, buf, strlen(SLOGAN), pos, UIO_WRITE);
175
err = VOP_WRITE(vn, &ku);
176
if (err) {
177
kprintf("%s: Write error: %s\n", name, strerror(err));
178
vfs_close(vn);
179
vfs_remove(name);
180
return -1;
181
}
182
183
if (ku.uio_resid > 0) {
184
kprintf("%s: Short write: %lu bytes left over\n",
185
name, (unsigned long) ku.uio_resid);
186
vfs_close(vn);
187
vfs_remove(name);
188
return -1;
189
}
190
191
bytes += (ku.uio_offset - pos);
192
shouldbytes += strlen(SLOGAN);
193
pos = ku.uio_offset;
194
}
195
196
vfs_close(vn);
197
198
if (bytes != shouldbytes) {
199
kprintf("%s: %lu bytes written, should have been %lu!\n",
200
name, (unsigned long) bytes,
201
(unsigned long) (NCHUNKS*strlen(SLOGAN)));
202
vfs_remove(name);
203
return -1;
204
}
205
kprintf("%s: %lu bytes written\n", name, (unsigned long) bytes);
206
207
return 0;
208
}
209
210
static
211
int
212
fstest_read(const char *fs, const char *namesuffix)
213
{
214
struct vnode *vn;
215
int err;
216
int i;
217
size_t bytes=0;
218
char name[32];
219
char buf[32];
220
struct iovec iov;
221
struct uio ku;
222
223
MAKENAME();
224
225
/* vfs_open destroys the string it's passed */
226
strcpy(buf, name);
227
err = vfs_open(buf, O_RDONLY, 0664, &vn);
228
if (err) {
229
kprintf("Could not open test file for read: %s\n",
230
strerror(err));
231
return -1;
232
}
233
234
for (i=0; i<NCHUNKS; i++) {
235
uio_kinit(&iov, &ku, buf, strlen(SLOGAN), bytes, UIO_READ);
236
err = VOP_READ(vn, &ku);
237
if (err) {
238
kprintf("%s: Read error: %s\n", name, strerror(err));
239
vfs_close(vn);
240
return -1;
241
}
242
243
if (ku.uio_resid > 0) {
244
kprintf("%s: Short read: %lu bytes left over\n", name,
245
(unsigned long) ku.uio_resid);
246
vfs_close(vn);
247
return -1;
248
}
249
buf[strlen(SLOGAN)] = 0;
250
rotate(buf, -i);
251
if (strcmp(buf, SLOGAN)) {
252
kprintf("%s: Test failed: line %d mismatched: %s\n",
253
name, i+1, buf);
254
vfs_close(vn);
255
return -1;
256
}
257
258
bytes = ku.uio_offset;
259
}
260
261
vfs_close(vn);
262
263
if (bytes != NCHUNKS*strlen(SLOGAN)) {
264
kprintf("%s: %lu bytes read, should have been %lu!\n",
265
name, (unsigned long) bytes,
266
(unsigned long) (NCHUNKS*strlen(SLOGAN)));
267
return -1;
268
}
269
kprintf("%s: %lu bytes read\n", name, (unsigned long) bytes);
270
return 0;
271
}
272
273
////////////////////////////////////////////////////////////
274
275
static
276
void
277
dofstest(const char *filesys)
278
{
279
kprintf("*** Starting filesystem test on %s:\n", filesys);
280
281
if (fstest_write(filesys, "", 1, 0)) {
282
kprintf("*** Test failed\n");
283
return;
284
}
285
286
if (fstest_read(filesys, "")) {
287
kprintf("*** Test failed\n");
288
return;
289
}
290
291
if (fstest_remove(filesys, "")) {
292
kprintf("*** Test failed\n");
293
return;
294
}
295
296
kprintf("*** Filesystem test done\n");
297
}
298
299
////////////////////////////////////////////////////////////
300
301
static
302
void
303
readstress_thread(void *fs, unsigned long num)
304
{
305
const char *filesys = fs;
306
if (fstest_read(filesys, "")) {
307
kprintf("*** Thread %lu: failed\n", num);
308
}
309
V(threadsem);
310
}
311
312
static
313
void
314
doreadstress(const char *filesys)
315
{
316
int i, err;
317
318
init_threadsem();
319
320
kprintf("*** Starting fs read stress test on %s:\n", filesys);
321
322
if (fstest_write(filesys, "", 1, 0)) {
323
kprintf("*** Test failed\n");
324
return;
325
}
326
327
for (i=0; i<NTHREADS; i++) {
328
err = thread_fork("readstress",
329
readstress_thread, (char *)filesys, i,
330
NULL);
331
if (err) {
332
panic("readstress: thread_fork failed: %s\n",
333
strerror(err));
334
}
335
}
336
337
for (i=0; i<NTHREADS; i++) {
338
P(threadsem);
339
}
340
341
if (fstest_remove(filesys, "")) {
342
kprintf("*** Test failed\n");
343
return;
344
}
345
346
kprintf("*** fs read stress test done\n");
347
}
348
349
////////////////////////////////////////////////////////////
350
351
static
352
void
353
writestress_thread(void *fs, unsigned long num)
354
{
355
const char *filesys = fs;
356
char numstr[8];
357
snprintf(numstr, sizeof(numstr), "%lu", num);
358
359
if (fstest_write(filesys, numstr, 1, 0)) {
360
kprintf("*** Thread %lu: failed\n", num);
361
V(threadsem);
362
return;
363
}
364
365
if (fstest_read(filesys, numstr)) {
366
kprintf("*** Thread %lu: failed\n", num);
367
V(threadsem);
368
return;
369
}
370
371
if (fstest_remove(filesys, numstr)) {
372
kprintf("*** Thread %lu: failed\n", num);
373
}
374
375
kprintf("*** Thread %lu: done\n", num);
376
377
V(threadsem);
378
}
379
380
static
381
void
382
dowritestress(const char *filesys)
383
{
384
int i, err;
385
386
init_threadsem();
387
388
kprintf("*** Starting fs write stress test on %s:\n", filesys);
389
390
for (i=0; i<NTHREADS; i++) {
391
err = thread_fork("writestress",
392
writestress_thread, (char *)filesys, i,
393
NULL);
394
if (err) {
395
panic("thread_fork failed %s\n", strerror(err));
396
}
397
}
398
399
for (i=0; i<NTHREADS; i++) {
400
P(threadsem);
401
}
402
403
kprintf("*** fs write stress test done\n");
404
}
405
406
////////////////////////////////////////////////////////////
407
408
static
409
void
410
writestress2_thread(void *fs, unsigned long num)
411
{
412
const char *filesys = fs;
413
414
if (fstest_write(filesys, "", NTHREADS, num)) {
415
kprintf("*** Thread %lu: failed\n", num);
416
V(threadsem);
417
return;
418
}
419
420
V(threadsem);
421
}
422
423
static
424
void
425
dowritestress2(const char *filesys)
426
{
427
int i, err;
428
char name[32];
429
struct vnode *vn;
430
431
init_threadsem();
432
433
kprintf("*** Starting fs write stress test 2 on %s:\n", filesys);
434
435
/* Create and truncate test file */
436
fstest_makename(name, sizeof(name), filesys, "");
437
err = vfs_open(name, O_WRONLY|O_CREAT|O_TRUNC, 0664, &vn);
438
if (err) {
439
kprintf("Could not create test file: %s\n", strerror(err));
440
kprintf("*** Test failed\n");
441
return;
442
}
443
vfs_close(vn);
444
445
for (i=0; i<NTHREADS; i++) {
446
err = thread_fork("writestress2",
447
writestress2_thread, (char *)filesys, i,
448
NULL);
449
if (err) {
450
panic("writestress2: thread_fork failed: %s\n",
451
strerror(err));
452
}
453
}
454
455
for (i=0; i<NTHREADS; i++) {
456
P(threadsem);
457
}
458
459
if (fstest_read(filesys, "")) {
460
kprintf("*** Test failed\n");
461
return;
462
}
463
464
if (fstest_remove(filesys, "")) {
465
kprintf("*** Test failed\n");
466
}
467
468
469
kprintf("*** fs write stress test 2 done\n");
470
}
471
472
////////////////////////////////////////////////////////////
473
474
static
475
void
476
createstress_thread(void *fs, unsigned long num)
477
{
478
const char *filesys = fs;
479
int i;
480
char numstr[16];
481
482
for (i=0; i<NCREATES; i++) {
483
484
snprintf(numstr, sizeof(numstr), "%lu-%d", num, i);
485
486
if (fstest_write(filesys, numstr, 1, 0)) {
487
kprintf("*** Thread %lu: file %d: failed\n", num, i);
488
V(threadsem);
489
return;
490
}
491
492
if (fstest_read(filesys, numstr)) {
493
kprintf("*** Thread %lu: file %d: failed\n", num, i);
494
V(threadsem);
495
return;
496
}
497
498
if (fstest_remove(filesys, numstr)) {
499
kprintf("*** Thread %lu: file %d: failed\n", num, i);
500
V(threadsem);
501
return;
502
}
503
504
}
505
506
V(threadsem);
507
}
508
509
static
510
void
511
docreatestress(const char *filesys)
512
{
513
int i, err;
514
515
init_threadsem();
516
517
kprintf("*** Starting fs create stress test on %s:\n", filesys);
518
519
for (i=0; i<NTHREADS; i++) {
520
err = thread_fork("createstress",
521
createstress_thread, (char *)filesys, i,
522
NULL);
523
if (err) {
524
panic("createstress: thread_fork failed %s\n",
525
strerror(err));
526
}
527
}
528
529
for (i=0; i<NTHREADS; i++) {
530
P(threadsem);
531
}
532
533
kprintf("*** fs create stress test done\n");
534
}
535
536
////////////////////////////////////////////////////////////
537
538
static
539
int
540
checkfilesystem(int nargs, char **args)
541
{
542
char *device;
543
544
if (nargs != 2) {
545
kprintf("Usage: fs[12345] filesystem:\n");
546
return EINVAL;
547
}
548
549
device = args[1];
550
551
/* Allow (but do not require) colon after device name */
552
if (device[strlen(device)-1]==':') {
553
device[strlen(device)-1] = 0;
554
}
555
556
return 0;
557
}
558
559
#define DEFTEST(testname) \
560
int \
561
testname(int nargs, char **args) \
562
{ \
563
int result; \
564
result = checkfilesystem(nargs, args); \
565
if (result) { \
566
return result; \
567
} \
568
do##testname(args[1]); \
569
return 0; \
570
}
571
572
DEFTEST(fstest);
573
DEFTEST(readstress);
574
DEFTEST(writestress);
575
DEFTEST(writestress2);
576
DEFTEST(createstress);
577
578
////////////////////////////////////////////////////////////
579
580
int
581
printfile(int nargs, char **args)
582
{
583
struct vnode *rv, *wv;
584
struct iovec iov;
585
struct uio ku;
586
off_t rpos=0, wpos=0;
587
char buf[128];
588
char outfile[16];
589
int result;
590
int done=0;
591
592
if (nargs != 2) {
593
kprintf("Usage: pf filename\n");
594
return EINVAL;
595
}
596
597
/* vfs_open destroys the string it's passed; make a copy */
598
strcpy(outfile, "con:");
599
600
result = vfs_open(args[1], O_RDONLY, 0664, &rv);
601
if (result) {
602
kprintf("printfile: %s\n", strerror(result));
603
return result;
604
}
605
606
result = vfs_open(outfile, O_WRONLY, 0664, &wv);
607
if (result) {
608
kprintf("printfile: output: %s\n", strerror(result));
609
vfs_close(rv);
610
return result;
611
}
612
613
while (!done) {
614
uio_kinit(&iov, &ku, buf, sizeof(buf), rpos, UIO_READ);
615
result = VOP_READ(rv, &ku);
616
if (result) {
617
kprintf("Read error: %s\n", strerror(result));
618
break;
619
}
620
rpos = ku.uio_offset;
621
622
if (ku.uio_resid > 0) {
623
done = 1;
624
}
625
626
uio_kinit(&iov, &ku, buf, sizeof(buf)-ku.uio_resid, wpos,
627
UIO_WRITE);
628
result = VOP_WRITE(wv, &ku);
629
if (result) {
630
kprintf("Write error: %s\n", strerror(result));
631
break;
632
}
633
wpos = ku.uio_offset;
634
635
if (ku.uio_resid > 0) {
636
kprintf("Warning: short write\n");
637
}
638
}
639
640
vfs_close(wv);
641
vfs_close(rv);
642
643
return 0;
644
}
645
646