/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- init_threadsem
- rotate
- fstest_makename
- fstest_remove
- fstest_write
- fstest_read
- dofstest
- readstress_thread
- doreadstress
- writestress_thread
- dowritestress
- writestress2_thread
- dowritestress2
- createstress_thread
- docreatestress
- checkfilesystem
- printfile
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", NULL,
329 readstress_thread, (char *)filesys, i);
330 if (err) {
331 panic("readstress: thread_fork failed: %s\n",
332 strerror(err));
333 }
334 }
335
336 for (i=0; i<NTHREADS; i++) {
337 P(threadsem);
338 }
339
340 if (fstest_remove(filesys, "")) {
341 kprintf("*** Test failed\n");
342 return;
343 }
344
345 kprintf("*** fs read stress test done\n");
346 }
347
348 ////////////////////////////////////////////////////////////
349
350 static
351 void
352 writestress_thread(void *fs, unsigned long num)
353 {
354 const char *filesys = fs;
355 char numstr[8];
356 snprintf(numstr, sizeof(numstr), "%lu", num);
357
358 if (fstest_write(filesys, numstr, 1, 0)) {
359 kprintf("*** Thread %lu: failed\n", num);
360 V(threadsem);
361 return;
362 }
363
364 if (fstest_read(filesys, numstr)) {
365 kprintf("*** Thread %lu: failed\n", num);
366 V(threadsem);
367 return;
368 }
369
370 if (fstest_remove(filesys, numstr)) {
371 kprintf("*** Thread %lu: failed\n", num);
372 }
373
374 kprintf("*** Thread %lu: done\n", num);
375
376 V(threadsem);
377 }
378
379 static
380 void
381 dowritestress(const char *filesys)
382 {
383 int i, err;
384
385 init_threadsem();
386
387 kprintf("*** Starting fs write stress test on %s:\n", filesys);
388
389 for (i=0; i<NTHREADS; i++) {
390 err = thread_fork("writestress", NULL,
391 writestress_thread, (char *)filesys, i);
392 if (err) {
393 panic("thread_fork failed %s\n", strerror(err));
394 }
395 }
396
397 for (i=0; i<NTHREADS; i++) {
398 P(threadsem);
399 }
400
401 kprintf("*** fs write stress test done\n");
402 }
403
404 ////////////////////////////////////////////////////////////
405
406 static
407 void
408 writestress2_thread(void *fs, unsigned long num)
409 {
410 const char *filesys = fs;
411
412 if (fstest_write(filesys, "", NTHREADS, num)) {
413 kprintf("*** Thread %lu: failed\n", num);
414 V(threadsem);
415 return;
416 }
417
418 V(threadsem);
419 }
420
421 static
422 void
423 dowritestress2(const char *filesys)
424 {
425 int i, err;
426 char name[32];
427 struct vnode *vn;
428
429 init_threadsem();
430
431 kprintf("*** Starting fs write stress test 2 on %s:\n", filesys);
432
433 /* Create and truncate test file */
434 fstest_makename(name, sizeof(name), filesys, "");
435 err = vfs_open(name, O_WRONLY|O_CREAT|O_TRUNC, 0664, &vn);
436 if (err) {
437 kprintf("Could not create test file: %s\n", strerror(err));
438 kprintf("*** Test failed\n");
439 return;
440 }
441 vfs_close(vn);
442
443 for (i=0; i<NTHREADS; i++) {
444 err = thread_fork("writestress2", NULL,
445 writestress2_thread, (char *)filesys, i);
446 if (err) {
447 panic("writestress2: thread_fork failed: %s\n",
448 strerror(err));
449 }
450 }
451
452 for (i=0; i<NTHREADS; i++) {
453 P(threadsem);
454 }
455
456 if (fstest_read(filesys, "")) {
457 kprintf("*** Test failed\n");
458 return;
459 }
460
461 if (fstest_remove(filesys, "")) {
462 kprintf("*** Test failed\n");
463 }
464
465
466 kprintf("*** fs write stress test 2 done\n");
467 }
468
469 ////////////////////////////////////////////////////////////
470
471 static
472 void
473 createstress_thread(void *fs, unsigned long num)
474 {
475 const char *filesys = fs;
476 int i;
477 char numstr[16];
478
479 for (i=0; i<NCREATES; i++) {
480
481 snprintf(numstr, sizeof(numstr), "%lu-%d", num, i);
482
483 if (fstest_write(filesys, numstr, 1, 0)) {
484 kprintf("*** Thread %lu: file %d: failed\n", num, i);
485 V(threadsem);
486 return;
487 }
488
489 if (fstest_read(filesys, numstr)) {
490 kprintf("*** Thread %lu: file %d: failed\n", num, i);
491 V(threadsem);
492 return;
493 }
494
495 if (fstest_remove(filesys, numstr)) {
496 kprintf("*** Thread %lu: file %d: failed\n", num, i);
497 V(threadsem);
498 return;
499 }
500
501 }
502
503 V(threadsem);
504 }
505
506 static
507 void
508 docreatestress(const char *filesys)
509 {
510 int i, err;
511
512 init_threadsem();
513
514 kprintf("*** Starting fs create stress test on %s:\n", filesys);
515
516 for (i=0; i<NTHREADS; i++) {
517 #ifdef UW
518 err = thread_fork("createstress", NULL,
519 createstress_thread, (char *)filesys, i);
520 #else
521 err = thread_fork("createstress",
522 createstress_thread, (char *)filesys, i,
523 NULL);
524 #endif
525 if (err) {
526 panic("createstress: thread_fork failed %s\n",
527 strerror(err));
528 }
529 }
530
531 for (i=0; i<NTHREADS; i++) {
532 P(threadsem);
533 }
534
535 kprintf("*** fs create stress test done\n");
536 }
537
538 ////////////////////////////////////////////////////////////
539
540 static
541 int
542 checkfilesystem(int nargs, char **args)
543 {
544 char *device;
545
546 if (nargs != 2) {
547 kprintf("Usage: fs[12345] filesystem:\n");
548 return EINVAL;
549 }
550
551 device = args[1];
552
553 /* Allow (but do not require) colon after device name */
554 if (device[strlen(device)-1]==':') {
555 device[strlen(device)-1] = 0;
556 }
557
558 return 0;
559 }
560
561 #define DEFTEST(testname) \
562 int \
563 testname(int nargs, char **args) \
564 { \
565 int result; \
566 result = checkfilesystem(nargs, args); \
567 if (result) { \
568 return result; \
569 } \
570 do##testname(args[1]); \
571 return 0; \
572 }
573
574 DEFTEST(fstest);
575 DEFTEST(readstress);
576 DEFTEST(writestress);
577 DEFTEST(writestress2);
578 DEFTEST(createstress);
579
580 ////////////////////////////////////////////////////////////
581
582 int
583 printfile(int nargs, char **args)
584 {
585 struct vnode *rv, *wv;
586 struct iovec iov;
587 struct uio ku;
588 off_t rpos=0, wpos=0;
589 char buf[128];
590 char outfile[16];
591 int result;
592 int done=0;
593
594 if (nargs != 2) {
595 kprintf("Usage: pf filename\n");
596 return EINVAL;
597 }
598
599 /* vfs_open destroys the string it's passed; make a copy */
600 strcpy(outfile, "con:");
601
602 result = vfs_open(args[1], O_RDONLY, 0664, &rv);
603 if (result) {
604 kprintf("printfile: %s\n", strerror(result));
605 return result;
606 }
607
608 result = vfs_open(outfile, O_WRONLY, 0664, &wv);
609 if (result) {
610 kprintf("printfile: output: %s\n", strerror(result));
611 vfs_close(rv);
612 return result;
613 }
614
615 while (!done) {
616 uio_kinit(&iov, &ku, buf, sizeof(buf), rpos, UIO_READ);
617 result = VOP_READ(rv, &ku);
618 if (result) {
619 kprintf("Read error: %s\n", strerror(result));
620 break;
621 }
622 rpos = ku.uio_offset;
623
624 if (ku.uio_resid > 0) {
625 done = 1;
626 }
627
628 uio_kinit(&iov, &ku, buf, sizeof(buf)-ku.uio_resid, wpos,
629 UIO_WRITE);
630 result = VOP_WRITE(wv, &ku);
631 if (result) {
632 kprintf("Write error: %s\n", strerror(result));
633 break;
634 }
635 wpos = ku.uio_offset;
636
637 if (ku.uio_resid > 0) {
638 kprintf("Warning: short write\n");
639 }
640 }
641
642 vfs_close(wv);
643 vfs_close(rv);
644
645 return 0;
646 }