root/kern/test/fstest.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_threadsem
  2. rotate
  3. fstest_makename
  4. fstest_remove
  5. fstest_write
  6. fstest_read
  7. dofstest
  8. readstress_thread
  9. doreadstress
  10. writestress_thread
  11. dowritestress
  12. writestress2_thread
  13. dowritestress2
  14. createstress_thread
  15. docreatestress
  16. checkfilesystem
  17. 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 }

/* [<][>][^][v][top][bottom][index][help] */