[PATCH v2] mtd-utils: integck: add support for volume specific power-cut test

Mats Kärrman Mats.Karrman at tritech.se
Thu May 15 01:21:55 PDT 2014


>From a3c9a9be5fe136d1a8e1c029a9f8cc3de634afd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mats=20K=C3=A4rrman?= <mats.karrman at tritech.se>
Date: Thu, 15 May 2014 10:03:56 +0200
Subject: [PATCH v2] mtd-utils: integck: add support for volume specific power-cut
 test
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem:
The current power-cut test requires power-cut emulation to be enabled globally
(e.g. for all UBIFS volumes) since the power-cut mode is otherwise lost when
the file-system is re-mounted. However this may lead to some practical
problems when the root fs of the tested machine is also of the same type.

Solution:
Modify the -p option so that it automatically enables power-cut testing
selectively for the tested filesystem and then re-enables it after every
re-mount. Enabling is done 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.

Signed-off-by: Mats Kärrman <mats.karrman at tritech.se>
---
 tests/fs-tests/integrity/integck.c | 151 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 149 insertions(+), 2 deletions(-)

v2:
- Meged the function into the existing '-p' option instead of creating a new
  overlapping option.
- Consistently use CHECK() for error handling when dealing with not-to-be-
  expected errors.
- Bumped program version to 1.2 since it's no longer backwards compatible.

diff --git a/tests/fs-tests/integrity/integck.c b/tests/fs-tests/integrity/integck.c
index 8badd1f..3f6b8ad 100644
--- a/tests/fs-tests/integrity/integck.c
+++ b/tests/fs-tests/integrity/integck.c
@@ -38,7 +38,7 @@
 #include <sys/mount.h>
 #include <sys/statvfs.h>
 
-#define PROGRAM_VERSION "1.1"
+#define PROGRAM_VERSION "1.2"
 #define PROGRAM_NAME "integck"
 #include "common.h"
 #include "libubi.h"
@@ -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.
  */
@@ -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_enable_path: path to the debugfs control knob file used to 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_enable_path;
 } fsinfo = {
 	.nospc_size_ok = 1,
 	.can_mmap = 1,
@@ -2580,6 +2586,24 @@ static int rm_minus_rf_dir(const char *dir_name)
 }
 
 /**
+ * Enable the power cut emulation mode on the tested file system
+ */
+static void enable_power_cut(void)
+{
+	int fd;
+
+	fd = open(fsinfo.pc_enable_path, O_WRONLY);
+	if (fd == -1) {
+		errmsg("failed to enable power-cut: %d", errno);
+		CHECK(0);
+	}
+
+	v("enabling power-cut for %s", fsinfo.fsdev);
+	CHECK(write(fd, "1\n", 2) == 2);
+	CHECK(close(fd) == 0);
+}
+
+/**
  * Re-mount the test file-system. This function randomly select how to
  * re-mount.
  */
@@ -2693,6 +2717,10 @@ static int remount_tested_fs(void)
 	}
 
 	CHECK(chdir(fsinfo.mount_point) == 0);
+
+	if (args.power_cut_mode)
+		enable_power_cut();
+
 	return 0;
 }
 
@@ -2850,6 +2878,115 @@ static int integck(void)
 }
 
 /*
+ * This is a helper function for 'make_ubifs_power_cut_enable_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_enable_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_enable_path(void)
+{
+	char * path;
+	struct stat st;
+
+	if (!strcmp("ubifs", fsinfo.fstype)) {
+		path = make_ubifs_power_cut_enable_path();
+	} else {
+		errmsg("power-cut enable not supported for %s",
+		       fsinfo.fstype);
+		CHECK(0);
+	}
+
+	if (stat(path, &st) == -1) {
+		sys_errmsg("failed to stat power-cut enable knob '%s': %d",
+			   path, errno);
+		CHECK(0);
+	}
+
+	fsinfo.pc_enable_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,7 +3152,8 @@ 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"
+"Currently power cut testing is implemented for UBIFS only.\n";
 
 static const char optionsstr[] =
 "-n, --repeat=<count> repeat count, default is 1; zero value - repeat forever\n"
@@ -3261,6 +3399,9 @@ static int recover_tested_fs(void)
 		}
 	}
 
+	if (args.power_cut_mode)
+		enable_power_cut();
+
 	return 0;
 }
 
@@ -3285,6 +3426,10 @@ int main(int argc, char *argv[])
 		return EXIT_FAILURE;
 
 	get_tested_fs_info();
+	if (args.power_cut_mode) {
+		set_power_cut_enable_path();
+		enable_power_cut();
+	}
 
 	/* Seed the random generator with out PID */
 	random_seed = getpid();
@@ -3380,5 +3525,7 @@ out_free:
 	free(fsinfo.fstype);
 	free(fsinfo.fsdev);
 	free(fsinfo.test_dir);
+	if (fsinfo.pc_enable_path)
+		free(fsinfo.pc_enable_path);
 	return ret ? EXIT_FAILURE : EXIT_SUCCESS;
 }
-- 
1.8.5.1



More information about the linux-mtd mailing list