diff options
| -rw-r--r-- | tests/fs-tests/integrity/integck.c | 138 | 
1 files changed, 127 insertions, 11 deletions
| diff --git a/tests/fs-tests/integrity/integck.c b/tests/fs-tests/integrity/integck.c index 9822b3b..f39745f 100644 --- a/tests/fs-tests/integrity/integck.c +++ b/tests/fs-tests/integrity/integck.c @@ -68,6 +68,7 @@  static struct {  	long repeat_cnt;  	int power_cut_mode; +	int verify_ops;  	int verbose;  	const char *mount_point;  } args = { @@ -529,6 +530,13 @@ static int dir_new(struct dir_info *parent, const char *name)  		free(path);  		return -1;  	} + +	if (args.verify_ops) { +		struct stat st; + +		CHECK(lstat(path, &st) == 0); +		CHECK(S_ISDIR(st.st_mode)); +	}  	free(path);  	add_dir_entry(parent, 'd', name, NULL); @@ -569,8 +577,16 @@ static int dir_remove(struct dir_info *dir)  		return -1;  	} +	if (args.verify_ops) { +		struct stat st; + +		CHECK(lstat(path, &st) == -1); +		CHECK(errno == ENOENT); +	} +  	/* Remove entry from parent directory */  	remove_dir_entry(dir->entry, 1); +  	free(path);  	return 0;  } @@ -597,10 +613,17 @@ static int file_new(struct dir_info *parent, const char *name)  		free(path);  		return -1;  	} -	free(path); +	if (args.verify_ops) { +		struct stat st; + +		CHECK(lstat(path, &st) == 0); +		CHECK(S_ISREG(st.st_mode)); +	}  	file = add_dir_entry(parent, 'f', name, NULL);  	add_fd(file, fd); + +	free(path);  	return 0;  } @@ -610,6 +633,7 @@ static int link_new(struct dir_info *parent, const char *name,  	struct dir_entry_info *entry;  	char *path, *target;  	int ret; +	struct stat st1, st2;  	entry = file->links;  	if (!entry) @@ -617,6 +641,10 @@ static int link_new(struct dir_info *parent, const char *name,  	path = dir_path(parent, name);  	target = dir_path(entry->parent, entry->name); + +	if (args.verify_ops) +		CHECK(lstat(target, &st1) == 0); +  	ret = link(target, path);  	if (ret != 0) {  		if (errno == ENOSPC) { @@ -629,9 +657,19 @@ static int link_new(struct dir_info *parent, const char *name,  		free(path);  		return ret;  	} + +	if (args.verify_ops) { +		CHECK(lstat(path, &st2) == 0); +		CHECK(S_ISREG(st2.st_mode)); +		CHECK(st1.st_ino == st2.st_ino); +		CHECK(st2.st_nlink > 1); +		CHECK(st2.st_nlink == st1.st_nlink + 1); +	} + +	add_dir_entry(parent, 'f', name, file); +  	free(target);  	free(path); -	add_dir_entry(parent, 'f', name, file);  	return 0;  } @@ -665,10 +703,18 @@ static int file_unlink(struct dir_entry_info *entry)  		free(path);  		return -1;  	} -	free(path); + +	if (args.verify_ops) { +		struct stat st; + +		CHECK(lstat(path, &st) == -1); +		CHECK(errno == ENOENT); +	}  	/* Remove file entry from parent directory */  	remove_dir_entry(entry, 1); + +	free(path);  	return 0;  } @@ -984,6 +1030,9 @@ static int file_ftruncate(struct file_info *file, int fd, off_t new_length)  		return -1;  	} +	if (args.verify_ops) +		CHECK(lseek(fd, 0, SEEK_END) == new_length); +  	return 0;  } @@ -1724,6 +1773,7 @@ static int rename_entry(struct dir_entry_info *entry)  	struct dir_info *parent;  	char *path, *to, *name;  	int ret, isdir, retry; +	struct stat st1, st2;  	if (!entry->parent)  		return 0; @@ -1757,6 +1807,9 @@ static int rename_entry(struct dir_entry_info *entry)  	if (!path)  		return 0; +	if (args.verify_ops) +		CHECK(lstat(path, &st1) == 0); +  	ret = rename(path, to);  	if (ret != 0) {  		ret = 0; @@ -1772,6 +1825,11 @@ static int rename_entry(struct dir_entry_info *entry)  		return ret;  	} +	if (args.verify_ops) { +		CHECK(lstat(to, &st2) == 0); +		CHECK(st1.st_ino == st2.st_ino); +	} +  	free(path);  	free(to); @@ -1870,6 +1928,18 @@ static char *pick_symlink_target(const char *symlink_path)  	return rel_path;  } +static void verify_symlink(const char *target, const char *path) +{ +	int bytes; +	char buf[PATH_MAX + 1]; + +	bytes = readlink(path, buf, PATH_MAX); +	CHECK(bytes >= 0); +	CHECK(bytes < PATH_MAX); +	buf[bytes] = '\0'; +	CHECK(!strcmp(buf, target)); +} +  static int symlink_new(struct dir_info *dir, const char *nm)  {  	struct symlink_info *s; @@ -1896,10 +1966,14 @@ static int symlink_new(struct dir_info *dir, const char *nm)  		free(path);  		return ret;  	} -	free(path); + +	if (args.verify_ops) +		verify_symlink(target, path);  	s = add_dir_entry(dir, 's', name, NULL);  	s->target_pathname = target; + +	free(path);  	free(name);  	return 0;  } @@ -1915,7 +1989,15 @@ static int symlink_remove(struct symlink_info *symlink)  		return -1;  	} +	if (args.verify_ops) { +		struct stat st; + +		CHECK(lstat(path, &st) == -1); +		CHECK(errno == ENOENT); +	} +  	remove_dir_entry(symlink->entry, 1); +  	free(path);  	return 0;  } @@ -2247,11 +2329,34 @@ static int rm_minus_rf_dir(const char *dir_name)  	CHECK(chdir(buf) == 0);  	CHECK(closedir(dir) == 0); + +	if (args.verify_ops) { +		dir = opendir(dir_name); +		CHECK(dir != NULL); +		do { +			errno = 0; +			dent = readdir(dir); +			if (dent) +				CHECK(!strcmp(dent->d_name, ".") || +				      !strcmp(dent->d_name, "..")); +		} while (dent); +		CHECK(errno == 0); +		CHECK(closedir(dir) == 0); +	} +  	ret = rmdir(dir_name);  	if (ret) {  		pcv("cannot remove directory %s", dir_name);  		return -1;  	} + +	if (args.verify_ops) { +		struct stat st; + +		CHECK(lstat(dir_name, &st) == -1); +		CHECK(errno == ENOENT); +	} +  	return 0;  } @@ -2600,6 +2705,11 @@ static const char doc[] = PROGRAM_NAME " version " PROGRAM_VERSION  "directories, etc) should be there and the contents of the files should be\n"  "correct. This is repeated a number of times (set with -n, default 1).\n"  "\n" +"By default the test does not verify file-system modifications and assumes they\n" +"are done correctly if the file-system returns success. However, the -e flag\n" +"enables additional verifications and the test verifies all the file-system\n" +"operations it performs.\n" +"\n"  "This test is also able to perform power cut testing. The underlying file-system\n"  "or the device driver should be able to emulate power-cuts, by switching to R/O\n"  "mode at random moments. And the file-system should return EROFS (read-only\n" @@ -2612,16 +2722,20 @@ static const char optionsstr[] =  "-n, --repeat=<count> repeat count, default is 1; zero value - repeat forever\n"  "-p, --power-cut      power cut testing mode (-n parameter is ignored and the\n"  "                     test continues forever)\n" +"-e, --verify-ops     verify all operations, e.g., every time a file is written\n" +"                     to, read the data back and verify it, every time a\n" +"                     directory is created, check that it exists, etc\n"  "-v, --verbose        be verbose about failures during power cut testing\n"  "-h, -?, --help       print help message\n"  "-V, --version        print program version\n";  static const struct option long_options[] = { -	{ .name = "repeat",    .has_arg = 1, .flag = NULL, .val = 'n' }, -	{ .name = "power-cut", .has_arg = 0, .flag = NULL, .val = 'p' }, -	{ .name = "verbose",   .has_arg = 0, .flag = NULL, .val = 'v' }, -	{ .name = "help",      .has_arg = 0, .flag = NULL, .val = 'h' }, -	{ .name = "version",   .has_arg = 0, .flag = NULL, .val = 'V' }, +	{ .name = "repeat",     .has_arg = 1, .flag = NULL, .val = 'n' }, +	{ .name = "power-cut",  .has_arg = 0, .flag = NULL, .val = 'p' }, +	{ .name = "verify-ops", .has_arg = 0, .flag = NULL, .val = 'e' }, +	{ .name = "verbose",    .has_arg = 0, .flag = NULL, .val = 'v' }, +	{ .name = "help",       .has_arg = 0, .flag = NULL, .val = 'h' }, +	{ .name = "version",    .has_arg = 0, .flag = NULL, .val = 'V' },  	{ NULL, 0, NULL, 0},  }; @@ -2636,7 +2750,7 @@ static int parse_opts(int argc, char * const argv[])  	while (1) {  		int key, error = 0; -		key = getopt_long(argc, argv, "n:pvVh?", long_options, NULL); +		key = getopt_long(argc, argv, "n:pevVh?", long_options, NULL);  		if (key == -1)  			break; @@ -2649,6 +2763,9 @@ static int parse_opts(int argc, char * const argv[])  		case 'p':  			args.power_cut_mode = 1;  			break; +		case 'e': +			args.verify_ops = 1; +			break;  		case 'v':  			args.verbose = 1;  			break; @@ -2867,7 +2984,6 @@ int main(int argc, char *argv[])  		} while (ret);  	} -  	free_test_data();  out_free: | 
