/* * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009 * The President and Fellows of Harvard College. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * fstest - filesystem test code * * Writes a file (in small chunks) and then reads it back again * (also in small chunks) and complains if what it reads back is * not the same. * * The length of SLOGAN is intentionally a prime number and * specifically *not* a power of two. */ #include #include #include #include #include #include #include #include #include #include #include #define SLOGAN "HODIE MIHI - CRAS TIBI\n" #define FILENAME "fstest.tmp" #define NCHUNKS 720 #define NTHREADS 12 #define NLONG 32 #define NCREATE 24 static struct semaphore *threadsem = NULL; static void init_threadsem(void) { if (threadsem==NULL) { threadsem = sem_create("fstestsem", 0); if (threadsem == NULL) { panic("fstest: sem_create failed\n"); } } } /* * Vary each line of the test file in a way that's predictable but * unlikely to mask bugs in the filesystem. */ static void rotate(char *str, int amt) { int i, ch; amt = (amt+2600)%26; KASSERT(amt>=0); for (i=0; str[i]; i++) { ch = str[i]; if (ch>='A' && ch<='Z') { ch = ch - 'A'; ch += amt; ch %= 26; ch = ch + 'A'; KASSERT(ch>='A' && ch<='Z'); } str[i] = ch; } } //////////////////////////////////////////////////////////// static void fstest_makename(char *buf, size_t buflen, const char *fs, const char *namesuffix) { snprintf(buf, buflen, "%s:%s%s", fs, FILENAME, namesuffix); KASSERT(strlen(buf) < buflen); } #define MAKENAME() fstest_makename(name, sizeof(name), fs, namesuffix) static int fstest_remove(const char *fs, const char *namesuffix) { char name[32]; char buf[32]; int err; MAKENAME(); strcpy(buf, name); err = vfs_remove(buf); if (err) { kprintf("Could not remove %s: %s\n", name, strerror(err)); return -1; } return 0; } static int fstest_write(const char *fs, const char *namesuffix, int stridesize, int stridepos) { struct vnode *vn; int err; int i; size_t shouldbytes=0; size_t bytes=0; off_t pos=0; char name[32]; char buf[32]; struct iovec iov; struct uio ku; int flags; KASSERT(sizeof(buf) > strlen(SLOGAN)); MAKENAME(); flags = O_WRONLY|O_CREAT; if (stridesize == 1) { flags |= O_TRUNC; } /* vfs_open destroys the string it's passed */ strcpy(buf, name); err = vfs_open(buf, flags, 0664, &vn); if (err) { kprintf("Could not open %s for write: %s\n", name, strerror(err)); return -1; } for (i=0; i 0) { kprintf("%s: Short write: %lu bytes left over\n", name, (unsigned long) ku.uio_resid); vfs_close(vn); vfs_remove(name); return -1; } bytes += (ku.uio_offset - pos); shouldbytes += strlen(SLOGAN); pos = ku.uio_offset; } vfs_close(vn); if (bytes != shouldbytes) { kprintf("%s: %lu bytes written, should have been %lu!\n", name, (unsigned long) bytes, (unsigned long) (NCHUNKS*strlen(SLOGAN))); vfs_remove(name); return -1; } kprintf("%s: %lu bytes written\n", name, (unsigned long) bytes); return 0; } static int fstest_read(const char *fs, const char *namesuffix) { struct vnode *vn; int err; int i; size_t bytes=0; char name[32]; char buf[32]; struct iovec iov; struct uio ku; MAKENAME(); /* vfs_open destroys the string it's passed */ strcpy(buf, name); err = vfs_open(buf, O_RDONLY, 0664, &vn); if (err) { kprintf("Could not open test file for read: %s\n", strerror(err)); return -1; } for (i=0; i 0) { kprintf("%s: Short read: %lu bytes left over\n", name, (unsigned long) ku.uio_resid); vfs_close(vn); return -1; } buf[strlen(SLOGAN)] = 0; rotate(buf, -i); if (strcmp(buf, SLOGAN)) { kprintf("%s: Test failed: line %d mismatched: %s\n", name, i+1, buf); vfs_close(vn); return -1; } bytes = ku.uio_offset; } vfs_close(vn); if (bytes != NCHUNKS*strlen(SLOGAN)) { kprintf("%s: %lu bytes read, should have been %lu!\n", name, (unsigned long) bytes, (unsigned long) (NCHUNKS*strlen(SLOGAN))); return -1; } kprintf("%s: %lu bytes read\n", name, (unsigned long) bytes); return 0; } //////////////////////////////////////////////////////////// static void dofstest(const char *filesys) { kprintf("*** Starting filesystem test on %s:\n", filesys); if (fstest_write(filesys, "", 1, 0)) { kprintf("*** Test failed\n"); return; } if (fstest_read(filesys, "")) { kprintf("*** Test failed\n"); return; } if (fstest_remove(filesys, "")) { kprintf("*** Test failed\n"); return; } kprintf("*** Filesystem test done\n"); } //////////////////////////////////////////////////////////// static void readstress_thread(void *fs, unsigned long num) { const char *filesys = fs; if (fstest_read(filesys, "")) { kprintf("*** Thread %lu: failed\n", num); } V(threadsem); } static void doreadstress(const char *filesys) { int i, err; init_threadsem(); kprintf("*** Starting fs read stress test on %s:\n", filesys); if (fstest_write(filesys, "", 1, 0)) { kprintf("*** Test failed\n"); return; } for (i=0; i 0) { kprintf("%s: Short write: %lu bytes left over\n", name, (unsigned long) ku.uio_resid); continue; } bytes = ku.uio_offset; if (bytes != strlen(SLOGAN)) { kprintf("%s: %lu bytes written, expected %lu!\n", name, (unsigned long) bytes, (unsigned long) strlen(SLOGAN)); continue; } numwritten++; } kprintf("Thread %lu: %u files written\n", num, numwritten); for (i=0; i 0) { kprintf("%s: Short read: %lu bytes left over\n", name, (unsigned long) ku.uio_resid); continue; } buf[strlen(SLOGAN)] = 0; rotate(buf, -i); if (strcmp(buf, SLOGAN)) { kprintf("%s: Test failed: file mismatched: %s\n", name, buf); continue; } bytes = ku.uio_offset; if (bytes != strlen(SLOGAN)) { kprintf("%s: %lu bytes read, expected %lu!\n", name, (unsigned long) bytes, (unsigned long) strlen(SLOGAN)); continue; } numread++; } kprintf("Thread %lu: %u files read\n", num, numread); for (i=0; i 0) { done = 1; } uio_kinit(&iov, &ku, buf, sizeof(buf)-ku.uio_resid, wpos, UIO_WRITE); result = VOP_WRITE(wv, &ku); if (result) { kprintf("Write error: %s\n", strerror(result)); break; } wpos = ku.uio_offset; if (ku.uio_resid > 0) { kprintf("Warning: short write\n"); } } vfs_close(wv); vfs_close(rv); return 0; }