os161-1.99
 All Data Structures
fstest.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * fstest - filesystem test code
00032  *
00033  * Writes a file (in small chunks) and then reads it back again
00034  * (also in small chunks) and complains if what it reads back is
00035  * not the same.
00036  *
00037  * The length of SLOGAN is intentionally a prime number and 
00038  * specifically *not* a power of two.
00039  */
00040 
00041 #include <types.h>
00042 #include <kern/errno.h>
00043 #include <kern/fcntl.h>
00044 #include <lib.h>
00045 #include <uio.h>
00046 #include <thread.h>
00047 #include <synch.h>
00048 #include <vfs.h>
00049 #include <fs.h>
00050 #include <vnode.h>
00051 #include <test.h>
00052 
00053 #define SLOGAN   "HODIE MIHI - CRAS TIBI\n"
00054 #define FILENAME "fstest.tmp"
00055 #define NCHUNKS  720
00056 #define NTHREADS 12
00057 #define NCREATES 32
00058 
00059 static struct semaphore *threadsem = NULL;
00060 
00061 static
00062 void
00063 init_threadsem(void)
00064 {
00065         if (threadsem==NULL) {
00066                 threadsem = sem_create("fstestsem", 0);
00067                 if (threadsem == NULL) {
00068                         panic("fstest: sem_create failed\n");
00069                 }
00070         }
00071 }
00072 
00073 /*
00074  * Vary each line of the test file in a way that's predictable but
00075  * unlikely to mask bugs in the filesystem.
00076  */
00077 static
00078 void
00079 rotate(char *str, int amt)
00080 {
00081         int i, ch;
00082 
00083         amt = (amt+2600)%26;
00084         KASSERT(amt>=0);
00085 
00086         for (i=0; str[i]; i++) {
00087                 ch = str[i];
00088                 if (ch>='A' && ch<='Z') {
00089                         ch = ch - 'A';
00090                         ch += amt;
00091                         ch %= 26;
00092                         ch = ch + 'A';
00093                         KASSERT(ch>='A' && ch<='Z');
00094                 }
00095                 str[i] = ch;
00096         }
00097 }
00098 
00099 ////////////////////////////////////////////////////////////
00100 
00101 static
00102 void
00103 fstest_makename(char *buf, size_t buflen, 
00104                 const char *fs, const char *namesuffix)
00105 {
00106         snprintf(buf, buflen, "%s:%s%s", fs, FILENAME, namesuffix);
00107         KASSERT(strlen(buf) < buflen);
00108 }
00109 
00110 #define MAKENAME() fstest_makename(name, sizeof(name), fs, namesuffix)
00111 
00112 static
00113 int
00114 fstest_remove(const char *fs, const char *namesuffix)
00115 {
00116         char name[32];
00117         char buf[32];
00118         int err;
00119 
00120         MAKENAME();
00121 
00122         strcpy(buf, name);
00123         err = vfs_remove(buf);
00124         if (err) {
00125                 kprintf("Could not remove %s: %s\n", name, strerror(err));
00126                 return -1;
00127         }
00128         
00129         return 0;
00130 }
00131 
00132 static
00133 int
00134 fstest_write(const char *fs, const char *namesuffix,
00135              int stridesize, int stridepos)
00136 {
00137         struct vnode *vn;
00138         int err;
00139         int i;
00140         size_t shouldbytes=0;
00141         size_t bytes=0;
00142         off_t pos=0;
00143         char name[32];
00144         char buf[32];
00145         struct iovec iov;
00146         struct uio ku;
00147         int flags;
00148 
00149         KASSERT(sizeof(buf) > strlen(SLOGAN));
00150 
00151         MAKENAME();
00152 
00153         flags = O_WRONLY|O_CREAT;
00154         if (stridesize == 1) {
00155                 flags |= O_TRUNC;
00156         }
00157 
00158         /* vfs_open destroys the string it's passed */
00159         strcpy(buf, name);
00160         err = vfs_open(buf, flags, 0664, &vn);
00161         if (err) {
00162                 kprintf("Could not open %s for write: %s\n", 
00163                         name, strerror(err));
00164                 return -1;
00165         }
00166 
00167         for (i=0; i<NCHUNKS; i++) {
00168                 if (i % stridesize != stridepos) {
00169                         pos += strlen(SLOGAN);
00170                         continue;
00171                 }
00172                 strcpy(buf, SLOGAN);
00173                 rotate(buf, i);
00174                 uio_kinit(&iov, &ku, buf, strlen(SLOGAN), pos, UIO_WRITE);
00175                 err = VOP_WRITE(vn, &ku);
00176                 if (err) {
00177                         kprintf("%s: Write error: %s\n", name, strerror(err));
00178                         vfs_close(vn);
00179                         vfs_remove(name);
00180                         return -1;
00181                 }
00182 
00183                 if (ku.uio_resid > 0) {
00184                         kprintf("%s: Short write: %lu bytes left over\n",
00185                                 name, (unsigned long) ku.uio_resid);
00186                         vfs_close(vn);
00187                         vfs_remove(name);
00188                         return -1;
00189                 }
00190 
00191                 bytes += (ku.uio_offset - pos);
00192                 shouldbytes += strlen(SLOGAN);
00193                 pos = ku.uio_offset;
00194         }
00195 
00196         vfs_close(vn);
00197 
00198         if (bytes != shouldbytes) {
00199                 kprintf("%s: %lu bytes written, should have been %lu!\n",
00200                         name, (unsigned long) bytes, 
00201                         (unsigned long) (NCHUNKS*strlen(SLOGAN)));
00202                 vfs_remove(name);
00203                 return -1;
00204         }
00205         kprintf("%s: %lu bytes written\n", name, (unsigned long) bytes);
00206 
00207         return 0;
00208 }
00209 
00210 static
00211 int
00212 fstest_read(const char *fs, const char *namesuffix)
00213 {
00214         struct vnode *vn;
00215         int err;
00216         int i;
00217         size_t bytes=0;
00218         char name[32];
00219         char buf[32];
00220         struct iovec iov;
00221         struct uio ku;
00222 
00223         MAKENAME();
00224 
00225         /* vfs_open destroys the string it's passed */
00226         strcpy(buf, name);
00227         err = vfs_open(buf, O_RDONLY, 0664, &vn);
00228         if (err) {
00229                 kprintf("Could not open test file for read: %s\n",
00230                         strerror(err));
00231                 return -1;
00232         }
00233 
00234         for (i=0; i<NCHUNKS; i++) {
00235                 uio_kinit(&iov, &ku, buf, strlen(SLOGAN), bytes, UIO_READ);
00236                 err = VOP_READ(vn, &ku);
00237                 if (err) {
00238                         kprintf("%s: Read error: %s\n", name, strerror(err));
00239                         vfs_close(vn);
00240                         return -1;
00241                 }
00242 
00243                 if (ku.uio_resid > 0) {
00244                         kprintf("%s: Short read: %lu bytes left over\n", name,
00245                                 (unsigned long) ku.uio_resid);
00246                         vfs_close(vn);
00247                         return -1;
00248                 }
00249                 buf[strlen(SLOGAN)] = 0;
00250                 rotate(buf, -i);
00251                 if (strcmp(buf, SLOGAN)) {
00252                         kprintf("%s: Test failed: line %d mismatched: %s\n",
00253                                 name, i+1, buf);
00254                         vfs_close(vn);
00255                         return -1;
00256                 }
00257 
00258                 bytes = ku.uio_offset;
00259         }
00260 
00261         vfs_close(vn);
00262 
00263         if (bytes != NCHUNKS*strlen(SLOGAN)) {
00264                 kprintf("%s: %lu bytes read, should have been %lu!\n",
00265                         name, (unsigned long) bytes, 
00266                         (unsigned long) (NCHUNKS*strlen(SLOGAN)));
00267                 return -1;
00268         }
00269         kprintf("%s: %lu bytes read\n", name, (unsigned long) bytes);
00270         return 0;
00271 }
00272 
00273 ////////////////////////////////////////////////////////////
00274 
00275 static
00276 void
00277 dofstest(const char *filesys)
00278 {
00279         kprintf("*** Starting filesystem test on %s:\n", filesys);
00280 
00281         if (fstest_write(filesys, "", 1, 0)) {
00282                 kprintf("*** Test failed\n");
00283                 return;
00284         }
00285         
00286         if (fstest_read(filesys, "")) {
00287                 kprintf("*** Test failed\n");
00288                 return;
00289         }
00290 
00291         if (fstest_remove(filesys, "")) {
00292                 kprintf("*** Test failed\n");
00293                 return;
00294         }
00295 
00296         kprintf("*** Filesystem test done\n");
00297 }
00298 
00299 ////////////////////////////////////////////////////////////
00300 
00301 static
00302 void
00303 readstress_thread(void *fs, unsigned long num)
00304 {
00305         const char *filesys = fs;
00306         if (fstest_read(filesys, "")) {
00307                 kprintf("*** Thread %lu: failed\n", num);
00308         }
00309         V(threadsem);
00310 }
00311 
00312 static
00313 void
00314 doreadstress(const char *filesys)
00315 {
00316         int i, err;
00317 
00318         init_threadsem();
00319 
00320         kprintf("*** Starting fs read stress test on %s:\n", filesys);
00321 
00322         if (fstest_write(filesys, "", 1, 0)) {
00323                 kprintf("*** Test failed\n");
00324                 return;
00325         }
00326 
00327         for (i=0; i<NTHREADS; i++) {
00328                 err = thread_fork("readstress", NULL,
00329                                   readstress_thread, (char *)filesys, i);
00330                 if (err) {
00331                         panic("readstress: thread_fork failed: %s\n",
00332                               strerror(err));
00333                 }
00334         }
00335 
00336         for (i=0; i<NTHREADS; i++) {
00337                 P(threadsem);
00338         }
00339 
00340         if (fstest_remove(filesys, "")) {
00341                 kprintf("*** Test failed\n");
00342                 return;
00343         }
00344         
00345         kprintf("*** fs read stress test done\n");
00346 }
00347 
00348 ////////////////////////////////////////////////////////////
00349 
00350 static
00351 void
00352 writestress_thread(void *fs, unsigned long num)
00353 {
00354         const char *filesys = fs;
00355         char numstr[8];
00356         snprintf(numstr, sizeof(numstr), "%lu", num);
00357 
00358         if (fstest_write(filesys, numstr, 1, 0)) {
00359                 kprintf("*** Thread %lu: failed\n", num);
00360                 V(threadsem);
00361                 return;
00362         }
00363 
00364         if (fstest_read(filesys, numstr)) {
00365                 kprintf("*** Thread %lu: failed\n", num);
00366                 V(threadsem);
00367                 return;
00368         }
00369 
00370         if (fstest_remove(filesys, numstr)) {
00371                 kprintf("*** Thread %lu: failed\n", num);
00372         }
00373 
00374         kprintf("*** Thread %lu: done\n", num);
00375 
00376         V(threadsem);
00377 }
00378 
00379 static
00380 void
00381 dowritestress(const char *filesys)
00382 {
00383         int i, err;
00384 
00385         init_threadsem();
00386 
00387         kprintf("*** Starting fs write stress test on %s:\n", filesys);
00388 
00389         for (i=0; i<NTHREADS; i++) {
00390                 err = thread_fork("writestress", NULL,
00391                                   writestress_thread, (char *)filesys, i);
00392                 if (err) {
00393                         panic("thread_fork failed %s\n", strerror(err));
00394                 }
00395         }
00396 
00397         for (i=0; i<NTHREADS; i++) {
00398                 P(threadsem);
00399         }
00400 
00401         kprintf("*** fs write stress test done\n");
00402 }
00403 
00404 ////////////////////////////////////////////////////////////
00405 
00406 static
00407 void
00408 writestress2_thread(void *fs, unsigned long num)
00409 {
00410         const char *filesys = fs;
00411 
00412         if (fstest_write(filesys, "", NTHREADS, num)) {
00413                 kprintf("*** Thread %lu: failed\n", num);
00414                 V(threadsem);
00415                 return;
00416         }
00417 
00418         V(threadsem);
00419 }
00420 
00421 static
00422 void
00423 dowritestress2(const char *filesys)
00424 {
00425         int i, err;
00426         char name[32];
00427         struct vnode *vn;
00428 
00429         init_threadsem();
00430 
00431         kprintf("*** Starting fs write stress test 2 on %s:\n", filesys);
00432 
00433         /* Create and truncate test file */
00434         fstest_makename(name, sizeof(name), filesys, "");
00435         err = vfs_open(name, O_WRONLY|O_CREAT|O_TRUNC, 0664, &vn);
00436         if (err) {
00437                 kprintf("Could not create test file: %s\n", strerror(err));
00438                 kprintf("*** Test failed\n");
00439                 return;
00440         }
00441         vfs_close(vn);
00442 
00443         for (i=0; i<NTHREADS; i++) {
00444                 err = thread_fork("writestress2", NULL,
00445                                   writestress2_thread, (char *)filesys, i);
00446                 if (err) {
00447                         panic("writestress2: thread_fork failed: %s\n",
00448                               strerror(err));
00449                 }
00450         }
00451 
00452         for (i=0; i<NTHREADS; i++) {
00453                 P(threadsem);
00454         }
00455 
00456         if (fstest_read(filesys, "")) {
00457                 kprintf("*** Test failed\n");
00458                 return;
00459         }
00460 
00461         if (fstest_remove(filesys, "")) {
00462                 kprintf("*** Test failed\n");
00463         }
00464 
00465 
00466         kprintf("*** fs write stress test 2 done\n");
00467 }
00468 
00469 ////////////////////////////////////////////////////////////
00470 
00471 static
00472 void
00473 createstress_thread(void *fs, unsigned long num)
00474 {
00475         const char *filesys = fs;
00476         int i;
00477         char numstr[16];
00478 
00479         for (i=0; i<NCREATES; i++) {
00480 
00481                 snprintf(numstr, sizeof(numstr), "%lu-%d", num, i);
00482 
00483                 if (fstest_write(filesys, numstr, 1, 0)) {
00484                         kprintf("*** Thread %lu: file %d: failed\n", num, i);
00485                         V(threadsem);
00486                         return;
00487                 }
00488                 
00489                 if (fstest_read(filesys, numstr)) {
00490                         kprintf("*** Thread %lu: file %d: failed\n", num, i);
00491                         V(threadsem);
00492                         return;
00493                 }
00494 
00495                 if (fstest_remove(filesys, numstr)) {
00496                         kprintf("*** Thread %lu: file %d: failed\n", num, i);
00497                         V(threadsem);
00498                         return;
00499                 }
00500 
00501         }
00502 
00503         V(threadsem);
00504 }
00505 
00506 static
00507 void
00508 docreatestress(const char *filesys)
00509 {
00510         int i, err;
00511 
00512         init_threadsem();
00513 
00514         kprintf("*** Starting fs create stress test on %s:\n", filesys);
00515 
00516         for (i=0; i<NTHREADS; i++) {
00517 #ifdef UW
00518                 err = thread_fork("createstress", NULL,
00519                                   createstress_thread, (char *)filesys, i);
00520 #else
00521                 err = thread_fork("createstress",
00522                                   createstress_thread, (char *)filesys, i,
00523                                   NULL);
00524 #endif
00525                 if (err) {
00526                         panic("createstress: thread_fork failed %s\n",
00527                               strerror(err));
00528                 }
00529         }
00530 
00531         for (i=0; i<NTHREADS; i++) {
00532                 P(threadsem);
00533         }
00534 
00535         kprintf("*** fs create stress test done\n");
00536 }
00537 
00538 ////////////////////////////////////////////////////////////
00539 
00540 static
00541 int
00542 checkfilesystem(int nargs, char **args)
00543 {
00544         char *device;
00545 
00546         if (nargs != 2) {
00547                 kprintf("Usage: fs[12345] filesystem:\n");
00548                 return EINVAL;
00549         }
00550 
00551         device = args[1];
00552 
00553         /* Allow (but do not require) colon after device name */
00554         if (device[strlen(device)-1]==':') {
00555                 device[strlen(device)-1] = 0;
00556         }
00557 
00558         return 0;
00559 }
00560 
00561 #define DEFTEST(testname)                         \
00562   int                                             \
00563   testname(int nargs, char **args)                \
00564   {                                               \
00565         int result;                               \
00566         result = checkfilesystem(nargs, args);    \
00567         if (result) {                             \
00568                 return result;                    \
00569         }                                         \
00570         do##testname(args[1]);                    \
00571         return 0;                                 \
00572   }
00573 
00574 DEFTEST(fstest);
00575 DEFTEST(readstress);
00576 DEFTEST(writestress);
00577 DEFTEST(writestress2);
00578 DEFTEST(createstress);
00579 
00580 ////////////////////////////////////////////////////////////
00581 
00582 int
00583 printfile(int nargs, char **args)
00584 {
00585         struct vnode *rv, *wv;
00586         struct iovec iov;
00587         struct uio ku;
00588         off_t rpos=0, wpos=0;
00589         char buf[128];
00590         char outfile[16];
00591         int result;
00592         int done=0;
00593 
00594         if (nargs != 2) {
00595                 kprintf("Usage: pf filename\n");
00596                 return EINVAL;
00597         }
00598 
00599         /* vfs_open destroys the string it's passed; make a copy */
00600         strcpy(outfile, "con:");
00601 
00602         result = vfs_open(args[1], O_RDONLY, 0664, &rv);
00603         if (result) {
00604                 kprintf("printfile: %s\n", strerror(result));
00605                 return result;
00606         }
00607 
00608         result = vfs_open(outfile, O_WRONLY, 0664, &wv);
00609         if (result) {
00610                 kprintf("printfile: output: %s\n", strerror(result));
00611                 vfs_close(rv);
00612                 return result;
00613         }
00614 
00615         while (!done) {
00616                 uio_kinit(&iov, &ku, buf, sizeof(buf), rpos, UIO_READ);
00617                 result = VOP_READ(rv, &ku);
00618                 if (result) {
00619                         kprintf("Read error: %s\n", strerror(result));
00620                         break;
00621                 }
00622                 rpos = ku.uio_offset;
00623 
00624                 if (ku.uio_resid > 0) {
00625                         done = 1;
00626                 }
00627 
00628                 uio_kinit(&iov, &ku, buf, sizeof(buf)-ku.uio_resid, wpos,
00629                           UIO_WRITE);
00630                 result = VOP_WRITE(wv, &ku);
00631                 if (result) {
00632                         kprintf("Write error: %s\n", strerror(result));
00633                         break;
00634                 }
00635                 wpos = ku.uio_offset;
00636 
00637                 if (ku.uio_resid > 0) {
00638                         kprintf("Warning: short write\n");
00639                 }
00640         }
00641 
00642         vfs_close(wv);
00643         vfs_close(rv);
00644 
00645         return 0;
00646 }
 All Data Structures