123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646 |
- /*
- * 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 <types.h>
- #include <kern/errno.h>
- #include <kern/fcntl.h>
- #include <lib.h>
- #include <uio.h>
- #include <thread.h>
- #include <synch.h>
- #include <vfs.h>
- #include <fs.h>
- #include <vnode.h>
- #include <test.h>
- #define SLOGAN "HODIE MIHI - CRAS TIBI\n"
- #define FILENAME "fstest.tmp"
- #define NCHUNKS 720
- #define NTHREADS 12
- #define NCREATES 32
- 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<NCHUNKS; i++) {
- if (i % stridesize != stridepos) {
- pos += strlen(SLOGAN);
- continue;
- }
- strcpy(buf, SLOGAN);
- rotate(buf, i);
- uio_kinit(&iov, &ku, buf, strlen(SLOGAN), pos, UIO_WRITE);
- err = VOP_WRITE(vn, &ku);
- if (err) {
- kprintf("%s: Write error: %s\n", name, strerror(err));
- vfs_close(vn);
- vfs_remove(name);
- return -1;
- }
- if (ku.uio_resid > 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<NCHUNKS; i++) {
- uio_kinit(&iov, &ku, buf, strlen(SLOGAN), bytes, UIO_READ);
- err = VOP_READ(vn, &ku);
- if (err) {
- kprintf("%s: Read error: %s\n", name, strerror(err));
- vfs_close(vn);
- return -1;
- }
- if (ku.uio_resid > 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<NTHREADS; i++) {
- err = thread_fork("readstress", NULL,
- readstress_thread, (char *)filesys, i);
- if (err) {
- panic("readstress: thread_fork failed: %s\n",
- strerror(err));
- }
- }
- for (i=0; i<NTHREADS; i++) {
- P(threadsem);
- }
- if (fstest_remove(filesys, "")) {
- kprintf("*** Test failed\n");
- return;
- }
-
- kprintf("*** fs read stress test done\n");
- }
- ////////////////////////////////////////////////////////////
- static
- void
- writestress_thread(void *fs, unsigned long num)
- {
- const char *filesys = fs;
- char numstr[8];
- snprintf(numstr, sizeof(numstr), "%lu", num);
- if (fstest_write(filesys, numstr, 1, 0)) {
- kprintf("*** Thread %lu: failed\n", num);
- V(threadsem);
- return;
- }
- if (fstest_read(filesys, numstr)) {
- kprintf("*** Thread %lu: failed\n", num);
- V(threadsem);
- return;
- }
- if (fstest_remove(filesys, numstr)) {
- kprintf("*** Thread %lu: failed\n", num);
- }
- kprintf("*** Thread %lu: done\n", num);
- V(threadsem);
- }
- static
- void
- dowritestress(const char *filesys)
- {
- int i, err;
- init_threadsem();
- kprintf("*** Starting fs write stress test on %s:\n", filesys);
- for (i=0; i<NTHREADS; i++) {
- err = thread_fork("writestress", NULL,
- writestress_thread, (char *)filesys, i);
- if (err) {
- panic("thread_fork failed %s\n", strerror(err));
- }
- }
- for (i=0; i<NTHREADS; i++) {
- P(threadsem);
- }
- kprintf("*** fs write stress test done\n");
- }
- ////////////////////////////////////////////////////////////
- static
- void
- writestress2_thread(void *fs, unsigned long num)
- {
- const char *filesys = fs;
- if (fstest_write(filesys, "", NTHREADS, num)) {
- kprintf("*** Thread %lu: failed\n", num);
- V(threadsem);
- return;
- }
- V(threadsem);
- }
- static
- void
- dowritestress2(const char *filesys)
- {
- int i, err;
- char name[32];
- struct vnode *vn;
- init_threadsem();
- kprintf("*** Starting fs write stress test 2 on %s:\n", filesys);
- /* Create and truncate test file */
- fstest_makename(name, sizeof(name), filesys, "");
- err = vfs_open(name, O_WRONLY|O_CREAT|O_TRUNC, 0664, &vn);
- if (err) {
- kprintf("Could not create test file: %s\n", strerror(err));
- kprintf("*** Test failed\n");
- return;
- }
- vfs_close(vn);
- for (i=0; i<NTHREADS; i++) {
- err = thread_fork("writestress2", NULL,
- writestress2_thread, (char *)filesys, i);
- if (err) {
- panic("writestress2: thread_fork failed: %s\n",
- strerror(err));
- }
- }
- for (i=0; i<NTHREADS; i++) {
- P(threadsem);
- }
- if (fstest_read(filesys, "")) {
- kprintf("*** Test failed\n");
- return;
- }
- if (fstest_remove(filesys, "")) {
- kprintf("*** Test failed\n");
- }
- kprintf("*** fs write stress test 2 done\n");
- }
- ////////////////////////////////////////////////////////////
- static
- void
- createstress_thread(void *fs, unsigned long num)
- {
- const char *filesys = fs;
- int i;
- char numstr[16];
- for (i=0; i<NCREATES; i++) {
- snprintf(numstr, sizeof(numstr), "%lu-%d", num, i);
- if (fstest_write(filesys, numstr, 1, 0)) {
- kprintf("*** Thread %lu: file %d: failed\n", num, i);
- V(threadsem);
- return;
- }
-
- if (fstest_read(filesys, numstr)) {
- kprintf("*** Thread %lu: file %d: failed\n", num, i);
- V(threadsem);
- return;
- }
- if (fstest_remove(filesys, numstr)) {
- kprintf("*** Thread %lu: file %d: failed\n", num, i);
- V(threadsem);
- return;
- }
- }
- V(threadsem);
- }
- static
- void
- docreatestress(const char *filesys)
- {
- int i, err;
- init_threadsem();
- kprintf("*** Starting fs create stress test on %s:\n", filesys);
- for (i=0; i<NTHREADS; i++) {
- #ifdef UW
- err = thread_fork("createstress", NULL,
- createstress_thread, (char *)filesys, i);
- #else
- err = thread_fork("createstress",
- createstress_thread, (char *)filesys, i,
- NULL);
- #endif
- if (err) {
- panic("createstress: thread_fork failed %s\n",
- strerror(err));
- }
- }
- for (i=0; i<NTHREADS; i++) {
- P(threadsem);
- }
- kprintf("*** fs create stress test done\n");
- }
- ////////////////////////////////////////////////////////////
- static
- int
- checkfilesystem(int nargs, char **args)
- {
- char *device;
- if (nargs != 2) {
- kprintf("Usage: fs[12345] filesystem:\n");
- return EINVAL;
- }
- device = args[1];
- /* Allow (but do not require) colon after device name */
- if (device[strlen(device)-1]==':') {
- device[strlen(device)-1] = 0;
- }
- return 0;
- }
- #define DEFTEST(testname) \
- int \
- testname(int nargs, char **args) \
- { \
- int result; \
- result = checkfilesystem(nargs, args); \
- if (result) { \
- return result; \
- } \
- do##testname(args[1]); \
- return 0; \
- }
- DEFTEST(fstest);
- DEFTEST(readstress);
- DEFTEST(writestress);
- DEFTEST(writestress2);
- DEFTEST(createstress);
- ////////////////////////////////////////////////////////////
- int
- printfile(int nargs, char **args)
- {
- struct vnode *rv, *wv;
- struct iovec iov;
- struct uio ku;
- off_t rpos=0, wpos=0;
- char buf[128];
- char outfile[16];
- int result;
- int done=0;
- if (nargs != 2) {
- kprintf("Usage: pf filename\n");
- return EINVAL;
- }
- /* vfs_open destroys the string it's passed; make a copy */
- strcpy(outfile, "con:");
- result = vfs_open(args[1], O_RDONLY, 0664, &rv);
- if (result) {
- kprintf("printfile: %s\n", strerror(result));
- return result;
- }
- result = vfs_open(outfile, O_WRONLY, 0664, &wv);
- if (result) {
- kprintf("printfile: output: %s\n", strerror(result));
- vfs_close(rv);
- return result;
- }
- while (!done) {
- uio_kinit(&iov, &ku, buf, sizeof(buf), rpos, UIO_READ);
- result = VOP_READ(rv, &ku);
- if (result) {
- kprintf("Read error: %s\n", strerror(result));
- break;
- }
- rpos = ku.uio_offset;
- if (ku.uio_resid > 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;
- }
|