[PATCH 2/2] mtd-utils: integck: add support for volume specific power-cut test
Mats Kärrman
Mats.Karrman at tritech.se
Mon Apr 14 04:47:04 PDT 2014
>From 5b334638fcfad3a200748826393d50ec1f79a6cd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mats=20K=C3=A4rrman?= <mats.karrman at tritech.se>
Date: Fri, 11 Apr 2014 10:26:39 +0200
Subject: [PATCH 2/2] mtd-utils: integck: add support for volume specific
power-cut test
Problem:
The current power-cut test requires power-cut emulation to be enabled globally
(i.e. for all UBIFS volumes) since the power-cut mode is otherwise lost when
the file-system is re-mounted but this may lead to some practical problems when
the root fs of the tested machine is also of the same type.
Solution:
Add a new option -P that extends the existing option -p with the ability to
automatically re-enable power-cut emulation after every re-mount by writing
"1" to the associated control file. The file to use is deduced from the mounted
device and the assumption that debugfs is mounted on /sys/kernel/debug.
The old option -p is kept for backwards compatibility and because the result
may be different if the power-cut mode is active also during re-mount.
Signed-off-by: Mats Karrman <mats.karrman at tritech.se>
---
tests/fs-tests/integrity/integck.c | 182 +++++++++++++++++++++++++++++++++---
1 file changed, 171 insertions(+), 11 deletions(-)
diff --git a/tests/fs-tests/integrity/integck.c b/tests/fs-tests/integrity/integck.c
index 8badd1f..90ccbbc 100644
--- a/tests/fs-tests/integrity/integck.c
+++ b/tests/fs-tests/integrity/integck.c
@@ -61,6 +61,9 @@
/* Maximum buffer size for a single read/write operation */
#define IO_BUFFER_SIZE 32768
+/* Kernel debug fs mount point */
+#define DEBUGFS_MOUNT_POINT "/sys/kernel/debug"
+
/*
* Check if a condition is true and die if not.
*/
@@ -94,7 +97,7 @@
/* The variables below are set by command line arguments */
static struct {
long repeat_cnt;
- int power_cut_mode;
+ int power_cut_mode; /* 0=off, 1=on, 2=auto enable */
int verify_ops;
int reattach;
int mtdn;
@@ -123,6 +126,8 @@ static struct {
* options as stored as a set of flags)
* mount_point: tested file-system mount point path
* test_dir: the directory on the tested file-system where we test
+ * pc_reenable_path: path to the debugfs control knob file used to re-enable
+ * power-cut mode for the tested file-system
*/
static struct {
int max_name_len;
@@ -137,6 +142,7 @@ static struct {
unsigned long mount_flags;
char *mount_point;
char *test_dir;
+ char *pc_reenable_path;
} fsinfo = {
.nospc_size_ok = 1,
.can_mmap = 1,
@@ -2580,6 +2586,26 @@ 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(fsinfo.pc_reenable_path, O_WRONLY);
+ if (fd == -1) {
+ errmsg("failed to re-enable power-cut: %d", errno);
+ return -1;
+ }
+
+ v("re-enabling power-cut for %s", fsinfo.fsdev);
+ 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.
*/
@@ -2693,6 +2719,13 @@ static int remount_tested_fs(void)
}
CHECK(chdir(fsinfo.mount_point) == 0);
+
+ if (args.power_cut_mode == 2) {
+ ret = reenable_power_cut();
+ if (ret)
+ return -1;
+ }
+
return 0;
}
@@ -2850,6 +2883,115 @@ static int integck(void)
}
/*
+ * This is a helper function for 'make_ubifs_power_cut_reenable_path()' that
+ * uses libubi to find out the ubifs volume number from a volume name.
+ */
+static int get_ubi_vol_num_from_name(int devnum, const char * name)
+{
+ libubi_t libubi;
+ struct ubi_vol_info vol_info;
+ int err, vol_num;
+
+ libubi = libubi_open();
+ if (!libubi) {
+ if (errno == 0)
+ errmsg("UBI is not present in the system");
+ else
+ sys_errmsg("cannot open libubi");
+ return -1;
+ }
+
+ err = ubi_get_vol_info1_nm(libubi, devnum, name, &vol_info);
+ if (err) {
+ sys_errmsg("cannot find UBI volume \"%s\"", name);
+ vol_num = -1;
+ } else {
+ vol_num = vol_info.vol_id;
+ }
+
+ libubi_close(libubi);
+ return vol_num;
+}
+
+/*
+ * Make a path for an ubifs power-cut enable knob file according to the
+ * device and volume number of the tested file-system.
+ */
+static char * make_ubifs_power_cut_reenable_path(void)
+{
+ int ubidev, ubivol;
+ char *p;
+ char path_tail[32];
+
+ /*
+ * Try to find the ubifs device and volume number using the
+ * fsinfo device string.
+ * Valid formats are (from comments in the 'open_ubi()' function):
+ * o ubiX_Y - mount UBI device number X, volume Y;
+ * o ubiY - mount UBI device number 0, volume Y;
+ * o ubiX:NAME - mount UBI device X, volume with name NAME;
+ * o ubi:NAME - mount UBI device 0, volume with name NAME.
+ * The first format may also be preceeded by the path to the dev node
+ * directory, e.g. "/dev/ubiX_Y".
+ */
+ ubivol = -1;
+ p = strstr(fsinfo.fsdev, "ubi");
+ if (p) {
+ p += 3;
+ if (isdigit(*p)) {
+ if (p[1] == '_' && isdigit(p[2]) && p[3] == '\0') {
+ ubidev = *p - '0';
+ ubivol = p[2] - '0';
+ } else if (p[1] == '\0') {
+ ubidev = 0;
+ ubivol = *p - '0';
+ } else if (p[1] == ':') {
+ ubidev = *p - '0';
+ ubivol = get_ubi_vol_num_from_name(ubidev, p+2);
+ }
+ } else if (*p == ':') {
+ ubidev = 0;
+ ubivol = get_ubi_vol_num_from_name(ubidev, p+1);
+ }
+ }
+
+ if (ubivol == -1) {
+ errmsg("failed to parse ubifs device string '%s'",
+ fsinfo.fsdev);
+ return NULL;
+ }
+
+ sprintf(path_tail, "/ubifs/ubi%d_%d/tst_recovery", ubidev, ubivol);
+ return cat_strings(DEBUGFS_MOUNT_POINT, path_tail);
+}
+
+/*
+ * Set path to the power-cut enable knob file according to the type of
+ * the tested file system.
+ */
+static void set_power_cut_reenable_path(void)
+{
+ char * path;
+ struct stat st;
+
+ if (!strcmp("ubifs", fsinfo.fstype)) {
+ path = make_ubifs_power_cut_reenable_path();
+ } else {
+ errmsg("automatic power-cut re-enable not supported for %s",
+ fsinfo.fstype);
+ CHECK(0);
+ }
+
+ if (stat(path, &st) == -1) {
+ sys_errmsg("failed to stat power-cut re-enable knob '%s': %d",
+ path, errno);
+ CHECK(0);
+ }
+
+ fsinfo.pc_reenable_path = path;
+}
+
+/*
* This is a helper function for 'get_tested_fs_info()'. It parses file-system
* mount options string, extracts standard mount options from there, and saves
* them in the 'fsinfo.mount_flags' variable, and non-standard mount options
@@ -3015,12 +3157,17 @@ 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"
+"automatically enables the use of power cut emulation on the tested fs instance\n"
+"only (currently implemented for UBIFS 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 Like -p but power-cut mode is re-enabled by writing\n"
+" '1' to the associated 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 +3178,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 = 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' },
{ NULL, 0, NULL, 0},
};
@@ -3052,7 +3200,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:pPm:evVh?", long_options, NULL);
if (key == -1)
break;
@@ -3063,7 +3211,11 @@ static int parse_opts(int argc, char * const argv[])
return errmsg("bad repeat count: \"%s\"", optarg);
break;
case 'p':
- args.power_cut_mode = 1;
+ if (!args.power_cut_mode)
+ args.power_cut_mode = 1;
+ break;
+ case 'P':
+ args.power_cut_mode = 2;
break;
case 'm':
args.mtdn = simple_strtoul(optarg, &error);
@@ -3261,6 +3413,12 @@ static int recover_tested_fs(void)
}
}
+ if (args.power_cut_mode == 2) {
+ ret = reenable_power_cut();
+ if (ret)
+ return -1;
+ }
+
return 0;
}
@@ -3285,6 +3443,8 @@ int main(int argc, char *argv[])
return EXIT_FAILURE;
get_tested_fs_info();
+ if (args.power_cut_mode == 2)
+ set_power_cut_reenable_path();
/* Seed the random generator with out PID */
random_seed = getpid();
--
1.7.10.4
More information about the linux-mtd
mailing list