[PATCH] mtd-utils: introduce mtd_raid tool.
Dongsheng Yang
yangds.fnst at cn.fujitsu.com
Tue Dec 1 02:53:50 PST 2015
From: Zeng Linggang <zenglg.jy at cn.fujitsu.com>
Signed-off-by: Zeng Linggang <zenglg.jy at cn.fujitsu.com>
Signed-off-by: Dongsheng Yang <yangds.fnst at cn.fujitsu.com>
---
.gitignore | 1 +
Makefile | 2 +-
include/mtd/mtd-raid-user.h | 33 ++++++
misc-utils/mtd_raid.c | 246 ++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 281 insertions(+), 1 deletion(-)
create mode 100644 include/mtd/mtd-raid-user.h
create mode 100644 misc-utils/mtd_raid.c
diff --git a/.gitignore b/.gitignore
index 04d9251..94ebdce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,6 +31,7 @@
/misc-utils/flashcp
/misc-utils/ftl_check
/misc-utils/ftl_format
+/misc-utils/mtd_raid
/jffsX-utils/jffs2dump
/jffsX-utils/jffs2reader
/jffsX-utils/mkfs.jffs2
diff --git a/Makefile b/Makefile
index 33d3e34..5282be9 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ MISC_BINS = \
ftl_format doc_loadbios ftl_check mtd_debug docfdisk \
serve_image recv_image mtdpart flash_erase flash_lock \
flash_unlock flash_otp_info flash_otp_dump flash_otp_lock \
- flash_otp_write flashcp
+ flash_otp_write flashcp mtd_raid
UBI_BINS = \
ubiupdatevol ubimkvol ubirmvol ubicrc32 ubinfo ubiattach \
ubidetach ubinize ubiformat ubirename mtdinfo ubirsvol ubiblock
diff --git a/include/mtd/mtd-raid-user.h b/include/mtd/mtd-raid-user.h
new file mode 100644
index 0000000..8c735ba
--- /dev/null
+++ b/include/mtd/mtd-raid-user.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2015, see mtd/mtd-raid for licensing and copyright details
+ */
+#ifndef __MTD_RAID_USER_H__
+#define __MTD_RAID_USER_H__
+
+#include <linux/types.h>
+#include <linux/magic.h>
+
+/* ioctl's command */
+#define MTD_RAID_IOC_CREATE _IOW(0xFE, 1, struct mtd_raid_create_req)
+#define MTD_RAID_IOC_DESTROY _IOW(0xFE, 2, struct mtd_raid_destroy_req)
+
+enum mtd_raid_level {
+ MTD_RAID_LEVEL_SINGLE = 0,
+ MTD_RAID_LEVEL_RAID0,
+ MTD_RAID_LEVEL_RAID1,
+ MTD_RAID_LEVEL_MAX
+};
+
+struct mtd_raid_create_req {
+ __u8 raid_level;
+ __u8 reserved[3];
+ __u32 dev_count;
+ __u64 substripe_size;
+ __u32 mtd_nums[0];
+};
+
+struct mtd_raid_destroy_req {
+ __u32 mtd_num;
+};
+
+#endif /* __MTD_RAID_USER_H__ */
diff --git a/misc-utils/mtd_raid.c b/misc-utils/mtd_raid.c
new file mode 100644
index 0000000..203676a
--- /dev/null
+++ b/misc-utils/mtd_raid.c
@@ -0,0 +1,246 @@
+/*
+ * User tool for MTD RAID
+ *
+ * Copyright (C) 2015 Zeng Linggang. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors: Dongsheng Yang <yangds.fnst at cn.fujitsu.com>
+ * Zeng Linggang <zenglg.jy at cn.fujitsu.com>
+ */
+
+#define PROGRAM_NAME "mtd_raid"
+
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <linux/blkpg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <mtd/mtd-raid-user.h>
+
+#include "common.h"
+
+static void display_help(int status)
+{
+ printf(
+ "Usage:\n"
+ " %1$s create [OPTION]... <MTD_DEVICE1> ...\n"
+ " %1$s destroy <MTD_RAID_DEVICE>\n"
+ "\n"
+ "Options:\n"
+ " -l, --level=[single|0|1] RAID level of the device you want to create.\n"
+ " -s, --substripe-size=<SIZE> Size of substripe, it's not necessary for\n"
+ " raid-single. Default value is mtd->writesize.\n"
+ " -h, --help Display this help and exit\n"
+ "\n"
+ "Create or destroy a mtd raid device. With the create subcommand, we can create\n"
+ "a raid device from the devices you requested.\n",
+ PROGRAM_NAME);
+ exit(status);
+}
+
+/* Command arguments */
+
+typedef enum {
+ COMMAND_CREATE,
+ COMMAND_DESTROY
+} command_type;
+
+static command_type command;
+static int dev_count;
+static int mtddevs[1024];
+static ssize_t substripe_size;
+static int raid_level;
+static int destroy_dev;
+
+static const char *optstring = "s:l:h";
+
+static const struct option longopts[] = {
+ {"level", 1, NULL, 'l'},
+ {"substripe-size", 1, NULL, 's'},
+ {"help", 0, NULL, 'h'},
+ {NULL, 0, NULL, 0}
+};
+
+#ifndef MTD_CHAR_MAJOR
+/*
+ * This is taken from kernel <linux/mtd/mtd.h> and is unlikely to change anytime
+ * soon.
+ */
+#define MTD_CHAR_MAJOR 90
+#endif
+
+/**
+ * mtd_node_to_num - converts device node to MTD number.
+ * @mtd_dev_node: path to device node to convert
+ *
+ * This function converts given @mtd_dev_node to MTD device number.
+ * @mtd_dev_node should contain path to the MTD device node. Returns MTD device
+ * number in case of success and %-1 in case of failure (errno is set).
+ *
+ * XXX This is a copy from ubi-utils/libubi.c.
+ * TODO:
+ * Move the generic files from ubi-utils to top level and then
+ * kill the duplication of mtd_node_to_num, even more we can move mtdinfo
+ * from ubi-utils to misc-utils.
+ */
+static int mtd_node_to_num(const char *mtd_dev_node)
+{
+ int major, minor;
+ struct stat sb;
+
+ if (stat(mtd_dev_node, &sb) < 0) {
+ sys_errmsg("cannot stat \"%s\"", mtd_dev_node);
+ return -EINVAL;
+ }
+
+ if (!S_ISCHR(sb.st_mode)) {
+ sys_errmsg("\"%s\" is not a character device",
+ mtd_dev_node);
+ return -EINVAL;
+ }
+
+ major = major(sb.st_rdev);
+ minor = minor(sb.st_rdev);
+
+ if (major != MTD_CHAR_MAJOR) {
+ sys_errmsg("\"%s\" is not an MTD device", mtd_dev_node);
+ return -EINVAL;
+ }
+
+ return minor / 2;
+}
+
+static enum mtd_raid_level get_raid_level(const char *level_str)
+{
+ if (strcmp(level_str, "single") == 0) {
+ return MTD_RAID_LEVEL_SINGLE;
+ } else if (strcmp(level_str, "0") == 0) {
+ return MTD_RAID_LEVEL_RAID0;
+ } else if (strcmp(level_str, "1") == 0) {
+ return MTD_RAID_LEVEL_RAID1;
+ } else {
+ return -EINVAL;
+ }
+}
+
+static void process_options(int argc, char * const argv[])
+{
+ int mtd_num = 0;
+ const char *s_command = argv[optind++];
+
+ if (strcmp(s_command, "destroy") == 0 && argc == 3)
+ command = COMMAND_DESTROY;
+ else if (strcmp(s_command, "create") == 0 && argc > 2)
+ command = COMMAND_CREATE;
+ else
+ goto err;
+
+ while (1) {
+ int c = getopt_long(argc, argv, optstring, longopts, NULL);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'l':
+ raid_level = get_raid_level(optarg);
+ if (raid_level < 0)
+ goto err;
+ break;
+ case 's':
+ substripe_size = strtoull(optarg, NULL, 0);
+ break;
+ case 'h':
+ display_help(EXIT_SUCCESS);
+ break;
+ case '?':
+ goto err;
+ }
+ }
+
+ if (command == COMMAND_CREATE) {
+ int i = 0;
+
+ while (optind < argc) {
+ mtd_num = mtd_node_to_num(argv[optind++]);
+ if (mtd_num < 0)
+ goto err;
+ if (i >= 1024)
+ goto err;
+ mtddevs[i++] = mtd_num;
+ }
+ dev_count = i;
+ if (dev_count == 0)
+ goto err;
+ } else if (command == COMMAND_DESTROY) {
+ mtd_num = mtd_node_to_num(argv[optind++]);
+ if (mtd_num < 0)
+ goto err;
+ destroy_dev = mtd_num;
+ }
+
+ return;
+err:
+ display_help(EXIT_FAILURE);
+}
+
+
+int main(int argc, char * const argv[])
+{
+ int fd, i = 0;
+ struct mtd_raid_create_req *create_req = NULL;
+ struct mtd_raid_destroy_req *destroy_req = NULL;
+
+ process_options(argc, argv);
+
+ fd = open("/dev/mtd_raid_ctrl", O_RDWR | O_CLOEXEC);
+ if (fd == -1)
+ sys_errmsg_die("Cannot open /dev/mtd_raid_ctrl");
+
+ switch (command) {
+ case COMMAND_CREATE:
+ create_req = malloc(sizeof(*create_req) + sizeof(int) * dev_count);
+ if (!create_req)
+ sys_errmsg_die("malloc error");
+ memset(create_req, 0, sizeof(*create_req) + sizeof(int) * dev_count);
+ create_req->raid_level = raid_level;
+ create_req->dev_count = dev_count;
+ for (i = 0; i < dev_count; i++)
+ create_req->mtd_nums[i] = mtddevs[i];
+ create_req->substripe_size = substripe_size;
+
+ if (ioctl(fd, MTD_RAID_IOC_CREATE, create_req))
+ sys_errmsg_die("Failed to issue MTD_RAID_IOC_CREATE ioctl");
+ break;
+ case COMMAND_DESTROY:
+ destroy_req = malloc(sizeof(*destroy_req));
+ if (!destroy_req)
+ sys_errmsg_die("malloc error");
+ memset(destroy_req, 0, sizeof(*destroy_req));
+ destroy_req->mtd_num = destroy_dev;
+ if (ioctl(fd, MTD_RAID_IOC_DESTROY, destroy_req))
+ sys_errmsg_die("Failed to issue MTD_RAID_IOC_DESTROY ioctl, %d", destroy_req->mtd_num);
+ break;
+ }
+
+ close(fd);
+ /* Exit happy */
+ return EXIT_SUCCESS;
+}
--
1.8.4.2
More information about the linux-mtd
mailing list