llverfs.c
来自「lustre 1.6.5 source code」· C语言 代码 · 共 651 行 · 第 1/2 页
C
651 行
/* * ext3 Filesystem Verification Tool. * This program tests the correct operation of ext3 filesystem. * This tool have two working modes * 1. full mode * 2. fast mode * The full mode is basic mode in which program creates a subdirectory * in the test fileysytem, writes n(files_in_dir, default=16) large(4GB) files * to the directory with the test pattern at the start of each 4kb block. * The test pattern contains timestamp, relative file offset and per file * unique idenfifier(inode number). this continues until whole filesystem is * full and then this tooll verifies that the data in all of the test files * is correct. * In the fast mode the tool creates a test directories with * EXT3_TOPDIR_FL flag set. the number of directories equals to the number * of block groups in the filesystem(e.g. 65536 directories for 8TB filesystem) * and then writes a single 1MB file in each directory. The tool then verifies * that the data in each file is correct. */#ifndef _GNU_SOURCE#define _GNU_SOURCE#endif#ifndef LUSTRE_UTILS#define LUSTRE_UTILS#endif#ifndef _LARGEFILE64_SOURCE#define _LARGEFILE64_SOURCE#endif#ifndef _FILE_OFFSET_BITS#define _FILE_OFFSET_BITS 64#endif#include <features.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <ctype.h>#include <fcntl.h>#include <unistd.h>#include <limits.h>#include <errno.h>#include <fcntl.h>#include <getopt.h>#include <time.h>#include <dirent.h>#include <mntent.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/vfs.h>#include <gnu/stubs.h>#include <gnu/stubs.h>#ifdef HAVE_EXT2FS_EXT2FS_H# include <e2p/e2p.h># include <ext2fs/ext2fs.h>#endif#define ONE_MB (1024 * 1024)#define ONE_GB ((unsigned long long)(1024 * 1024 * 1024))#define BLOCKSIZE 4096/* Structure for writing test pattern */struct block_data { unsigned long long bd_offset; unsigned long long bd_time; unsigned long long bd_inode;};static char *progname; /* name by which this program was run. */static unsigned verbose = 1; /* prints offset in kB, operation rate */static int readoption; /* run test in read-only (verify) mode */static int writeoption; /* run test in write_only mode */char *testdir; /* name of device to be tested. */static unsigned full = 1; /* flag to full check */static int errno_local; /* local copy of errno */static unsigned long num_files; /* Total number of files for read/write */static loff_t file_size = 4*ONE_GB; /* Size of each file */static unsigned files_in_dir = 32; /* number of files in each directioy */static unsigned num_dirs = 30000; /* total number of directories */const int dirmode = S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;static int fd = -1;static int isatty_flag;static int perms = S_IRWXU | S_IRGRP | S_IROTH;static struct option const longopts[] ={ { "chunksize", required_argument, 0, 'c' }, { "help", no_argument, 0, 'h' }, { "offset", required_argument, 0, 'o' }, { "long", no_argument, 0, 'l' }, { "partial", required_argument, 0, 'p' }, { "quiet", required_argument, 0, 'q' }, { "read", no_argument, 0, 'r' }, { "timestamp", required_argument, 0, 't' }, { "verbose", no_argument, 0, 'v' }, { "write", no_argument, 0, 'w' }, { 0, 0, 0, 0}};/* * Usages: displays help information, whenever user supply --help option in * command or enters incorrect command line. */void usage(int status){ if (status != 0) { printf("\nUsage: %s [OPTION]... <filesystem path> ...\n", progname); printf("ext3 filesystem verification tool.\n" "\t-t {seconds} for --timestamp, set test time" "(default=current time())\n" "\t-o {offset} for --offset, directory starting offset" " from which tests should start\n" "\t-r run test in read (verify) mode\n" "\t-w run test in write (test-pattern) mode (default=r&w)\n" "\t-v for verbose\n" "\t-p for --partial, for partial check (1MB files)\n" "\t-l for --long, full check (4GB file with 4k blocks)\n" "\t-c for --chunksize, IO chunk size (default=1048576)\n" "\t-h display this help and exit\n" "\t--help display this help and exit\n"); } exit(status);}/* * open_file: Opens file in specified mode and returns fd. */static int open_file(const char *file, int flag){ fd = open(file, flag, perms); if (fd < 0) { fprintf(stderr, "\n%s: Open '%s' failed:%s\n", progname, file, strerror(errno)); exit(3); } return (fd);}/* * Verify_chunk: Verifies test pattern in each 4kB (BLOCKSIZE) is correct. * Returns 0 if test offset and timestamp is correct otherwise 1. */int verify_chunk(char *chunk_buf, size_t chunksize,unsigned long long chunk_off, unsigned long long time_st, unsigned long long inode_st, char *file){ struct block_data *bd; char *chunk_end; for (chunk_end = chunk_buf + chunksize - sizeof(*bd); (char *)chunk_buf < chunk_end; chunk_buf += BLOCKSIZE, chunk_off += BLOCKSIZE) { bd = (struct block_data *)chunk_buf; if ((bd->bd_offset == chunk_off) && (bd->bd_time == time_st) && (bd->bd_inode == inode_st)) continue; fprintf(stderr,"\n%s: verify %s failed offset/timestamp/inode " "%llu/%llu/%llu: found %llu/%llu/%llu instead\n", progname, file, chunk_off, time_st, inode_st, bd->bd_offset, bd->bd_time, bd->bd_inode); return 1; } return 0;}/* * fill_chunk: Fills the chunk with current or user specified timestamp * and offset. The test patters is filled at the beginning of * each 4kB(BLOCKSIZE) blocks in chunk_buf. */void fill_chunk(char *chunk_buf, size_t chunksize, loff_t chunk_off, time_t time_st, ino_t inode_st){ struct block_data *bd; char *chunk_end; for (chunk_end = chunk_buf + chunksize - sizeof(*bd); (char *)chunk_buf < chunk_end; chunk_buf += BLOCKSIZE, chunk_off += BLOCKSIZE) { bd = (struct block_data *)chunk_buf; bd->bd_offset = chunk_off; bd->bd_time = time_st; bd->bd_inode = inode_st; }}/* * write_chunk: write the chunk_buf on the device. The number of write * operations are based on the parameters write_end, offset, and chunksize. */int write_chunks(int fd, unsigned long long offset,unsigned long long write_end, char *chunk_buf, size_t chunksize, time_t time_st, ino_t inode_st, const char *file){ unsigned long long stride; stride = full ? chunksize : (ONE_GB - chunksize); for (offset = offset & ~(chunksize - 1); offset < write_end; offset += stride) { if (lseek64(fd, offset, SEEK_SET) == -1) { fprintf(stderr, "\n%s: lseek64(%s+%llu) failed: %s\n", progname, file, offset, strerror(errno)); return 1; } if (offset + chunksize > write_end) chunksize = write_end - offset; if (!full && offset > chunksize) { fill_chunk(chunk_buf, chunksize, offset, time_st, inode_st); if (write(fd, chunk_buf, chunksize) < 0) { if (errno == ENOSPC) { errno_local = errno; return 0; } fprintf(stderr, "\n%s: write %s+%llu failed: %s\n", progname, file, offset,strerror(errno)); return errno; } offset += chunksize; if (offset + chunksize > write_end) chunksize = write_end - offset; } fill_chunk(chunk_buf, chunksize, offset, time_st, inode_st); if (write(fd, (char *) chunk_buf, chunksize) < 0) { if (errno == ENOSPC) { errno_local = errno; return 0; } fprintf(stderr, "\n%s: write %s+%llu failed: %s\n", progname, file, offset, strerror(errno)); return 1; } } return 0;}/* * read_chunk: reads the chunk_buf from the device. The number of read * operations are based on the parameters read_end, offset, and chunksize. */int read_chunks(int fd, unsigned long long offset, unsigned long long read_end, char *chunk_buf, size_t chunksize, time_t time_st, ino_t inode_st, char *file){ unsigned long long stride; stride = full ? chunksize : (ONE_GB - chunksize); for (offset = offset & ~(chunksize - 1); offset < read_end; offset += stride) { if (lseek64(fd, offset, SEEK_SET) == -1) { fprintf(stderr, "\n%s: lseek64(%s+%llu) failed: %s\n", progname, file, offset, strerror(errno)); return 1; } if (offset + chunksize > read_end) chunksize = read_end - offset; if (!full && offset > chunksize) { if (read(fd, chunk_buf, chunksize) < 0) { fprintf(stderr, "\n%s: read %s+%llu failed: %s\n", progname, file, offset,strerror(errno)); return 1; } if (verify_chunk(chunk_buf, chunksize, offset, time_st, inode_st, file) != 0) return 1; offset += chunksize; if (offset + chunksize >= read_end) chunksize = read_end - offset; } if (read(fd, chunk_buf, chunksize) < 0) { fprintf(stderr, "\n%s: read %s+%llu failed: %s\n", progname, file, offset, strerror(errno)); return 1; } if (verify_chunk(chunk_buf, chunksize, offset, time_st, inode_st, file) != 0) return 1; } return 0;}/* * new_file: prepares new filename using file counter and current dir. */char *new_file(char *tempfile, char *cur_dir, int file_num){ sprintf(tempfile, "%s/file%03d", cur_dir, file_num); return tempfile;}/* * new_dir: prepares new dir name using dir counters. */char *new_dir(char *tempdir, int dir_num){ sprintf(tempdir, "%s/dir%05d", testdir, dir_num); return tempdir;}/* * show_filename: Displays name of current file read/write */void show_filename(char *op, char *filename){ static time_t last; time_t now; double diff; now = time(NULL); diff = now - last; if (diff > 4 || verbose > 2) { if (isatty_flag) printf("\r"); printf("%s File name: %s ", op, filename); if (isatty_flag) fflush(stdout); else printf("\n"); last = now; }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?