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 + -
显示快捷键?