@@ -37,6 +37,7 @@
#include <sys/vfs.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
+#include <linux/fs.h>
#define PROGRAM_VERSION "1.1"
#define PROGRAM_NAME "integck"
@@ -61,6 +62,9 @@
/* Maximum buffer size for a single read/write operation */
#define IO_BUFFER_SIZE 32768
+/* To avoid trouble with error 16 (Device or resource busy) */
+#define MOUNT_DELAY 10000
+
/*
* Check if a condition is true and die if not.
*/
@@ -95,6 +99,7 @@
static struct {
long repeat_cnt;
int power_cut_mode;
+ const char * pc_reenable;
int verify_ops;
int reattach;
int mtdn;
@@ -2580,6 +2585,25 @@ static int rm_minus_rf_dir(const char *dir_name)
}
/**
+ * Re-enable the power cut emulation mode on the tested file system
+ */
+static int reenable_power_cut(void)
+{
+ int fd;
+
+ fd = open(args.pc_reenable, O_WRONLY);
+ if (fd == -1) {
+ errmsg("failed to reenable power-cut: %d", errno);
+ return -1;
+ }
+
+ CHECK(write(fd, "1\n", 2) == 2);
+ CHECK(close(fd) == 0);
+
+ return 0;
+}
+
+/**
* Re-mount the test file-system. This function randomly select how to
* re-mount.
*/
@@ -2604,6 +2628,7 @@ static int remount_tested_fs(void)
if (rorw1) {
flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT;
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype,
flags, fsinfo.mount_opts);
if (ret) {
@@ -2614,6 +2639,7 @@ static int remount_tested_fs(void)
flags = fsinfo.mount_flags | MS_REMOUNT;
flags &= ~((unsigned long)MS_RDONLY);
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype,
flags, fsinfo.mount_opts);
if (ret) {
@@ -2626,6 +2652,7 @@ static int remount_tested_fs(void)
if (um) {
if (um_ro) {
flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT;
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, flags, fsinfo.mount_opts);
if (ret) {
@@ -2635,6 +2662,7 @@ static int remount_tested_fs(void)
}
}
+ usleep(MOUNT_DELAY);
ret = umount(fsinfo.mount_point);
if (ret) {
pcv("cannot unmount %s", fsinfo.mount_point);
@@ -2642,6 +2670,7 @@ static int remount_tested_fs(void)
}
if (!um_rorw) {
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, fsinfo.mount_flags,
fsinfo.mount_opts);
@@ -2651,6 +2680,7 @@ static int remount_tested_fs(void)
return -1;
}
} else {
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, fsinfo.mount_flags | MS_RDONLY,
fsinfo.mount_opts);
@@ -2662,6 +2692,7 @@ static int remount_tested_fs(void)
flags = fsinfo.mount_flags | MS_REMOUNT;
flags &= ~((unsigned long)MS_RDONLY);
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, flags, fsinfo.mount_opts);
if (ret) {
@@ -2674,6 +2705,7 @@ static int remount_tested_fs(void)
if (rorw2) {
flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT;
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype,
flags, fsinfo.mount_opts);
if (ret) {
@@ -2683,6 +2715,7 @@ static int remount_tested_fs(void)
flags = fsinfo.mount_flags | MS_REMOUNT;
flags &= ~((unsigned long)MS_RDONLY);
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype,
flags, fsinfo.mount_opts);
if (ret) {
@@ -2693,6 +2726,13 @@ static int remount_tested_fs(void)
}
CHECK(chdir(fsinfo.mount_point) == 0);
+
+ if (args.pc_reenable) {
+ ret = reenable_power_cut();
+ if (ret)
+ return -1;
+ }
+
return 0;
}
@@ -3015,12 +3055,16 @@ static const char doc[] = PROGRAM_NAME " version " PROGRAM_VERSION
"file-system error) for all operations which modify it. In this case this test\n"
"program re-mounts the file-system and checks that all files and directories\n"
"which have been successfully synchronized before the power cut. And the test\n"
-"continues forever.\n";
+"continues forever.\n"
+"Whereas -p requires power cut emulation to be enabled globally, the -P option\n"
+"enables the use of power cut emulation on the tested fs instance only.\n";
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"
+"-P, --pc-reenable=<sysfile> Like -p but power-cut mode is re-enabled by writing\n"
+" '1' to the specified sysfs file after every re-mount.\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"
@@ -3031,13 +3075,14 @@ static const char optionsstr[] =
"-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 = "verify-ops", .has_arg = 0, .flag = NULL, .val = 'e' },
- { .name = "reattach", .has_arg = 1, .flag = NULL, .val = 'm' },
- { .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 = "pc-reenable", .has_arg = 1, .flag = NULL, .val = 'P' },
+ { .name = "verify-ops", .has_arg = 0, .flag = NULL, .val = 'e' },
+ { .name = "reattach", .has_arg = 1, .flag = NULL, .val = 'm' },
+ { .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},
};
@@ -3052,7 +3097,7 @@ static int parse_opts(int argc, char * const argv[])
while (1) {
int key, error = 0;
- key = getopt_long(argc, argv, "n:pm:evVh?", long_options, NULL);
+ key = getopt_long(argc, argv, "n:pP:m:evVh?", long_options, NULL);
if (key == -1)
break;
@@ -3065,6 +3110,12 @@ static int parse_opts(int argc, char * const argv[])
case 'p':
args.power_cut_mode = 1;
break;
+ case 'P':
+ args.pc_reenable = optarg;
+ if (args.pc_reenable[0] == '-')
+ return errmsg("bad power-cut enable file: \"%s\"", optarg);
+ args.power_cut_mode = 1;
+ break;
case 'm':
args.mtdn = simple_strtoul(optarg, &error);
if (error || args.mtdn < 0)
@@ -3205,13 +3256,16 @@ static int recover_tested_fs(void)
* while mounting in 'remount_tested_fs()'.
*/
mntent = get_tested_fs_mntent();
- if (mntent)
+ if (mntent) {
+ usleep(MOUNT_DELAY);
CHECK(umount(fsinfo.mount_point) != -1);
+ }
if (args.reattach)
CHECK(reattach() == 0);
if (!um_rorw) {
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, fsinfo.mount_flags,
fsinfo.mount_opts);
@@ -3221,6 +3275,7 @@ static int recover_tested_fs(void)
return -1;
}
} else {
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, fsinfo.mount_flags | MS_RDONLY,
fsinfo.mount_opts);
@@ -3232,6 +3287,7 @@ static int recover_tested_fs(void)
flags = fsinfo.mount_flags | MS_REMOUNT;
flags &= ~((unsigned long)MS_RDONLY);
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point,
fsinfo.fstype, flags, fsinfo.mount_opts);
if (ret) {
@@ -3243,6 +3299,7 @@ static int recover_tested_fs(void)
if (rorw2) {
flags = fsinfo.mount_flags | MS_RDONLY | MS_REMOUNT;
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype,
flags, fsinfo.mount_opts);
if (ret) {
@@ -3252,6 +3309,7 @@ static int recover_tested_fs(void)
flags = fsinfo.mount_flags | MS_REMOUNT;
flags &= ~((unsigned long)MS_RDONLY);
+ usleep(MOUNT_DELAY);
ret = mount(fsinfo.fsdev, fsinfo.mount_point, fsinfo.fstype,
flags, fsinfo.mount_opts);
if (ret) {
@@ -3261,6 +3319,12 @@ static int recover_tested_fs(void)
}
}
+ if (args.pc_reenable) {
+ ret = reenable_power_cut();
+ if (ret)
+ return -1;
+ }
+
return 0;
}