@@ -91,6 +91,10 @@ MON_OBJS = mdmon.o monitor.o managemon.o util.o mdstat.o sysfs.o config.o \
super-ddf.o sha1.o crc32.o msg.o Monitor.o bitmap.o \
platform-intel.o probe_roms.o
+DM2MD_OBJS = dm2md.o mdopen.o util.o mdstat.o super0.o super1.o super-intel.o \
+ super-ddf.o sha1.o crc32.o msg.o platform-intel.o probe_roms.o \
+ sysfs.o config.o sg_io.o dlink.o ReadMe.o mapfile.o Kill.o \
+ bitmap.o
STATICSRC = pwgr.c
STATICOBJS = pwgr.o
@@ -105,7 +109,7 @@ ASSEMBLE_SRCS += $(ASSEMBLE_AUTO_SRCS)
ASSEMBLE_FLAGS += -DMDASSEMBLE_AUTO
endif
-all : mdadm mdmon mdadm.man md.man mdadm.conf.man
+all : mdadm mdmon mdadm.man md.man mdadm.conf.man dm2md
everything: all mdadm.static swap_super test_stripe \
mdassemble mdassemble.auto mdassemble.static mdassemble.man \
@@ -139,6 +143,9 @@ mdmon : $(MON_OBJS)
$(CC) $(LDFLAGS) -o mdmon $(MON_OBJS) $(LDLIBS)
msg.o: msg.c msg.h
+dm2md : $(DM2MD_OBJS) mdadm.h
+ $(CC) $(LDFLAGS) -o dm2md $(DM2MD_OBJS) $(LDLIBS)
+
test_stripe : restripe.c mdadm.h
$(CC) $(CXFLAGS) $(LDFLAGS) -o test_stripe -DMAIN restripe.c
@@ -185,6 +192,7 @@ sha1.o : sha1.c sha1.h md5.h
install : mdadm mdmon install-man install-udev
$(INSTALL) -D $(STRIP) -m 755 mdadm $(DESTDIR)$(BINDIR)/mdadm
$(INSTALL) -D $(STRIP) -m 755 mdmon $(DESTDIR)$(BINDIR)/mdmon
+ $(INSTALL) -D $(STRIP) -m 755 dm2md $(DESTDIR)$(BINDIR)/dm2md
install-static : mdadm.static install-man
$(INSTALL) -D $(STRIP) -m 755 mdadm.static $(DESTDIR)$(BINDIR)/mdadm
@@ -213,7 +221,8 @@ test: mdadm test_stripe swap_super
@echo "Please run 'sh ./test' as root"
clean :
- rm -f mdadm mdmon $(OBJS) $(MON_OBJS) $(STATICOBJS) core *.man \
+ rm -f mdadm mdmon $(OBJS) $(MON_OBJS) $(STATICOBJS) $(DM2MD_OBJS) \
+ core *.man dm2md \
mdadm.tcc mdadm.uclibc mdadm.static *.orig *.porig *.rej *.alt \
mdadm.Os mdadm.O2 \
mdassemble mdassemble.static mdassemble.auto mdassemble.uclibc \
new file mode 100644
@@ -0,0 +1,617 @@
+/*
+ * dm2md - Activate dmraid tables with md
+ *
+ * Copyright (C) 2009 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope 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.
+ */
+#define HAVE_STDINT_H 1
+#include "mdadm.h"
+#include "sha1.h"
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+enum dm_target_type {
+ DMRAID45 = 0,
+ DMRAID1,
+ DMRAID0,
+};
+
+static const char *dm_targets[] = {
+ "raid45",
+ "mirror",
+ "striped",
+};
+
+static const int dm_target_cnt = sizeof(dm_targets) / sizeof(char *);
+
+struct member {
+ char *name;
+ char *offset;
+ unsigned long start_offset;
+ int major;
+ int minor;
+};
+
+struct dm2md_info {
+ char *name;
+ int level;
+ int dosync;
+ int layout;
+ int chunk_size;
+ int raid_disks;
+ unsigned long long component_size;
+ struct member *inf;
+};
+
+static struct member *parse_members(int num_members)
+{
+ struct member *m = calloc(num_members, sizeof(*m));
+ int i;
+ int rc;
+ struct stat st;
+ char *end;
+ char *tok;
+ char *last_off;
+
+ if (!m) {
+ fprintf(stderr, "dm2md: failed to allocate %d members\n",
+ num_members);
+ return NULL;
+ }
+
+ for (i = 0; i < num_members * 2; i++) {
+ tok = strtok(NULL, " ");
+ if (!tok)
+ break;
+ if (i & 1)
+ m[i/2].offset = tok;
+ else
+ m[i/2].name = tok;
+ }
+ if (i < num_members * 2) {
+ fprintf(stderr, "dm2md: failed to parse member %d\n", i/2);
+ free(m);
+ return NULL;
+ }
+
+ /* all members should be valid block devices */
+ for (i = 0; i < num_members; i++) {
+ rc = stat(m[i].name, &st);
+ if (rc < 0) {
+ char *nm;
+
+ /* initial stat failed, but check to see if
+ * /dev/mapper/ devices are available under
+ * /dev/md/
+ */
+ if (strncmp(m[i].name, "/dev/mapper/",
+ strlen("/dev/mapper/")) != 0)
+ break;
+ nm = m[i].name + strlen("/dev/mapper/");
+ sprintf(m[i].name, "/dev/md/%s", nm);
+ i--;
+ continue; /* retry */
+ }
+ if (!S_ISBLK(st.st_mode))
+ break;
+ m[i].major = major(st.st_rdev);
+ m[i].minor = minor(st.st_rdev);
+ }
+ if (i < num_members) {
+ if (rc == 0)
+ fprintf(stderr, "dm2md: \'%s\' not a block device\n", m[i].name);
+ else
+ fprintf(stderr, "dm2md: \'%s\' stat failed\n", m[i].name);
+ free(m);
+ return NULL;
+ }
+
+ /* the last start offset may end in \n, chop it off */
+ last_off = m[num_members - 1].offset;
+ i = strlen(last_off);
+ if (last_off[i - 1] == '\n')
+ last_off[i - 1] = '\0';
+
+ /* convert and check start offsets */
+ for (i = 0; i < num_members; i++) {
+ m[i].start_offset = strtoul(m[i].offset, &end, 10);
+ if (end == m[i].offset || *end != '\0')
+ break;
+ }
+ if (i < num_members) {
+ fprintf(stderr, "dm2md: invalid start offset for member%d \'%s\'\n",
+ i, m[i].offset);
+ free(m);
+ return NULL;
+ }
+
+ return m;
+}
+
+static int dm2md_raid5_layout(char *layout)
+{
+ if (strcmp(layout, "raid5_la") == 0)
+ return ALGORITHM_LEFT_ASYMMETRIC;
+ else if (strcmp(layout, "raid5_ra") == 0)
+ return ALGORITHM_RIGHT_ASYMMETRIC;
+ else if (strcmp(layout, "raid5_ls") == 0)
+ return ALGORITHM_LEFT_SYMMETRIC;
+ else if (strcmp(layout, "raid5_rs") == 0)
+ return ALGORITHM_RIGHT_SYMMETRIC;
+ else
+ return -1;
+}
+
+static void uuid_from_dm(struct dm2md_info *d2m, int uuid[4])
+{
+ char buf[20];
+ struct sha1_ctx ctx;
+
+ sha1_init_ctx(&ctx);
+ sha1_process_bytes(d2m->name, strlen(d2m->name), &ctx);
+ sha1_finish_ctx(&ctx, buf);
+ memcpy(uuid, buf, 4*4);
+}
+
+static int assemble(struct dm2md_info *d2m)
+{
+ int mdfd;
+ char buf[100];
+ char path[30];
+ char chosen_name[500];
+ struct mdinfo mdi;
+ struct mdinfo *sra;
+ int uuid[4];
+ int i;
+ int rc = 0;
+ unsigned long long resync_start = d2m->dosync ? 0 : ~0ULL;
+ struct map_ent *map = NULL;
+
+ sprintf(buf, "/dev/md/%s", d2m->name);
+
+ map_lock(&map);
+ mdfd = create_mddev(buf, d2m->name, 3, LOCAL, chosen_name);
+ if (mdfd < 0) {
+ fprintf(stderr, "dm2md: failed to open %s (%s)\n",
+ buf, strerror(errno));
+ free(d2m->inf);
+ map_unlock(&map);
+ return 1;
+ }
+ uuid_from_dm(d2m, uuid);
+ map_update(&map, fd2devnum(mdfd), "none", uuid, chosen_name);
+ map_unlock(&map);
+
+ sra = sysfs_read(mdfd, fd2devnum(mdfd), GET_VERSION);
+ rc |= sysfs_set_num(sra, NULL, "chunk_size", d2m->chunk_size);
+ rc |= sysfs_set_num(sra, NULL, "layout", d2m->layout);
+ sprintf(buf, "raid%d", d2m->level);
+ rc |= sysfs_set_str(sra, NULL, "level", buf);
+ rc |= sysfs_set_str(sra, NULL, "metadata_version", "none");
+ rc |= sysfs_set_num(sra, NULL, "raid_disks", d2m->raid_disks);
+ rc |= sysfs_set_num(sra, NULL, "component_size", d2m->component_size/2);
+ if (d2m->level > 0)
+ rc |= sysfs_set_num(sra, NULL, "resync_start", resync_start);
+
+ for (i = 0; i < d2m->raid_disks; i++) {
+ struct member *m = &d2m->inf[i];
+ int rv;
+ char *nm;
+
+ sprintf(buf, "%d:%d", m->major, m->minor);
+ rc |= sysfs_set_str(sra, NULL, "new_dev", buf);
+ sprintf(path, "/sys/dev/block/%d:%d",
+ m->major, m->minor);
+ rv = readlink(path, buf, sizeof(buf) - 1);
+ if (rv <= 0) {
+ rc |= -1;
+ break;
+ }
+ buf[rv] = '\0';
+ nm = strrchr(buf, '/');
+ if (!nm) {
+ rc |= -1;
+ break;
+ }
+ nm++;
+ sprintf(mdi.sys_name, "dev-%s", nm);
+ rc |= sysfs_set_num(sra, &mdi, "offset", m->start_offset);
+ rc |= sysfs_set_num(sra, &mdi, "slot", i);
+ rc |= sysfs_set_num(sra, &mdi, "size", (d2m->component_size+1)/2);
+ }
+ if (rc || sysfs_set_str(sra, NULL, "array_state", "readonly")) {
+ fprintf(stderr, "dm2md: failed to start array\n");
+ rc = 1;
+ } else {
+ wait_for(chosen_name);
+ rc = 0;
+ }
+ sysfs_free(sra);
+ free(d2m->inf);
+ close(mdfd);
+
+ return rc;
+}
+
+static int dmraid0(char *name, unsigned long long array_size)
+{
+ char *tok;
+ int i;
+ char *num;
+ char *end;
+ char *bps;
+ unsigned long blocks_per_strip;
+ unsigned long num_members;
+ struct member *dev_info;
+ struct dm2md_info d2m;
+
+ for (i = 0; i < 2; i++) {
+ tok = strtok(NULL, " ");
+ if (!tok)
+ break;
+ if (i == 0)
+ num = tok;
+ else if (i == 1)
+ bps = tok;
+ }
+ if (i < 2) {
+ fprintf(stderr, "dm2md: %s failed to retrieve field %d\n",
+ __func__, i+4);
+ return 1;
+ }
+ blocks_per_strip = strtoul(bps, &end, 10);
+ if (bps == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid blocks per strip \'%s\'\n",
+ __func__, bps);
+ return 1;
+ }
+ num_members = strtoul(num, &end, 10);
+ if (num == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid number of members \'%s\'\n",
+ __func__, num);
+ return 1;
+ }
+
+ dev_info = parse_members(num_members);
+ if (!dev_info)
+ return 1;
+
+ do {
+ d2m.name = name;
+ d2m.level = 0;
+ d2m.layout = 0;
+ d2m.chunk_size = (blocks_per_strip / 2) * 1024;
+ if (d2m.chunk_size != (blocks_per_strip / 2) * 1024)
+ break;
+ d2m.raid_disks = num_members;
+ if (d2m.raid_disks != num_members)
+ break;
+ d2m.component_size = array_size / num_members;
+ d2m.inf = dev_info;
+
+ return assemble(&d2m);
+ } while (0);
+
+ fprintf(stderr, "dm2md: %s conversion error chunk: %lu disks: %lu\n",
+ __func__, (blocks_per_strip / 2) * 1024, num_members);
+ free(dev_info);
+
+ return 1;
+}
+
+static int dmraid1(char *name, unsigned long long array_size)
+{
+ char *tok;
+ int i;
+ char *log;
+ unsigned long log_region_size;
+ char *sync;
+ char *num;
+ char *end;
+ unsigned long num_members;
+ struct member *dev_info;
+ struct dm2md_info d2m;
+
+ for (i = 0; i < 5; i++) {
+ tok = strtok(NULL, " ");
+ if (!tok)
+ break;
+ if (i == 0 && strcmp(tok, "core") != 0)
+ break;
+ else if (i == 1 && strcmp(tok, "2") != 0)
+ break;
+ else if (i == 2)
+ log = tok;
+ else if (i == 3)
+ sync = tok;
+ else if (i == 4)
+ num = tok;
+ }
+ if (i < 5) {
+ fprintf(stderr, "dm2md: %s failed to retrieve field %d\n",
+ __func__, i+4);
+ return 1;
+ }
+ log_region_size = strtoul(log, &end, 10);
+ if (log == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid log region size \'%s\'\n",
+ __func__, log);
+ return 1;
+ }
+ if (strcmp(sync, "sync") != 0 && strcmp(sync, "nosync") != 0) {
+ fprintf(stderr, "dm2md: %s invalid sync field \'%s\'\n",
+ __func__, sync);
+ return 1;
+ }
+ num_members = strtoul(num, &end, 10);
+ if (num == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid number of members \'%s\'\n",
+ __func__, num);
+ return 1;
+ }
+
+ dev_info = parse_members(num_members);
+ if (!dev_info)
+ return 1;
+
+ do {
+ d2m.name = name;
+ d2m.level = 1;
+ d2m.layout = 0;
+ d2m.dosync = strcmp(sync, "sync") == 0;
+ d2m.chunk_size = 65536;
+ d2m.raid_disks = num_members;
+ if (d2m.raid_disks != num_members)
+ break;
+ d2m.component_size = array_size;
+ d2m.inf = dev_info;
+
+ return assemble(&d2m);
+ } while (0);
+
+ fprintf(stderr, "dm2md: %s conversion error disks: %lu\n",
+ __func__, num_members);
+ free(dev_info);
+
+ return 1;
+}
+
+
+/* sample line and fields:
+ * isw_iageiijgf_Volume0: 0 41943552 raid45 core 2 8192
+ * nosync raid5_la 1 128 4 4232814
+ * /dev/sdb 0 /dev/sdc 0 /dev/sdd 0 /dev/sde 0
+ * device name: 0 array_size target core 2 log_region_size
+ * (no)sync raid5_[l|r][a|s] 1 blocks_per_strip num_members failed_disk_number
+ * (member start_offset)[num_members]
+ */
+static int dmraid45(char *name, unsigned long long array_size)
+{
+ char *log;
+ unsigned long log_region_size;
+ char *sync;
+ char *layout;
+ char *bps;
+ unsigned long blocks_per_strip;
+ char *num;
+ unsigned long num_members;
+ char *failed;
+ unsigned long failed_info;
+ char *tok;
+ int i;
+ char *end;
+ struct member *dev_info;
+ struct dm2md_info d2m;
+
+ for (i = 0; i < 9; i++) {
+ tok = strtok(NULL, " ");
+ if (!tok)
+ break;
+ if (i == 0 && strcmp(tok, "core") != 0)
+ break;
+ else if (i == 1 && strcmp(tok, "2") != 0)
+ break;
+ else if (i == 2)
+ log = tok;
+ else if (i == 3)
+ sync = tok;
+ else if (i == 4)
+ layout = tok;
+ else if (i == 5 && strcmp(tok, "1") != 0)
+ break;
+ else if (i == 6)
+ bps = tok;
+ else if (i == 7)
+ num = tok;
+ else if (i == 8)
+ failed = tok;
+ }
+ if (i < 9) {
+ fprintf(stderr, "dm2md: %s failed to retrieve field %d\n",
+ __func__, i+4);
+ return 1;
+ }
+
+ log_region_size = strtoul(log, &end, 10);
+ if (log == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid log region size \'%s\'\n",
+ __func__, log);
+ return 1;
+ }
+ if (strcmp(sync, "sync") != 0 && strcmp(sync, "nosync") != 0) {
+ fprintf(stderr, "dm2md: %s invalid sync field \'%s\'\n",
+ __func__, sync);
+ return 1;
+ }
+ if (strcmp(layout, "raid5_la") != 0 &&
+ strcmp(layout, "raid5_ra") != 0 &&
+ strcmp(layout, "raid5_ls") != 0 &&
+ strcmp(layout, "raid5_rs") != 0) {
+ fprintf(stderr, "dm2md: %s invalid layout field \'%s\'\n",
+ __func__, layout);
+ return 1;
+ }
+ blocks_per_strip = strtoul(bps, &end, 10);
+ if (bps == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid blocks per strip \'%s\'\n",
+ __func__, bps);
+ return 1;
+ }
+ num_members = strtoul(num, &end, 10);
+ if (num == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid number of members \'%s\'\n",
+ __func__, num);
+ return 1;
+ }
+ failed_info = strtoul(failed, &end, 10);
+ if (failed == end || *end != '\0') {
+ fprintf(stderr, "dm2md: %s invalid failed info \'%s\'\n",
+ __func__, failed);
+ return 1;
+ }
+
+ dev_info = parse_members(num_members);
+ if (!dev_info)
+ return 1;
+
+ do {
+ d2m.name = name;
+ d2m.level = 5;
+ d2m.layout = dm2md_raid5_layout(layout);
+ d2m.dosync = strcmp(sync, "sync") == 0;
+ if (d2m.layout < 0)
+ break;
+ d2m.chunk_size = (blocks_per_strip / 2) * 1024;
+ if (d2m.chunk_size != (blocks_per_strip / 2) * 1024)
+ break;
+ d2m.raid_disks = num_members;
+ if (d2m.raid_disks != num_members)
+ break;
+ d2m.component_size = array_size / (num_members - 1);
+ d2m.inf = dev_info;
+
+ return assemble(&d2m);
+ } while (0);
+
+ fprintf(stderr, "dm2md: %s conversion error layout: %s chunk: %lu disks: %lu\n",
+ __func__, layout, (blocks_per_strip / 2) * 1024, num_members);
+ free(dev_info);
+
+ return 1;
+}
+
+static int handle_table_ent(char *line)
+{
+ char *name;
+ char *size;
+ unsigned long long array_size;
+ char *type;
+ char *tok;
+ char *end;
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ tok = strtok(i ? NULL : line, " ");
+ if (!tok)
+ break;
+ if (i == 0)
+ name = tok;
+ else if (i == 1 && *tok != '0')
+ break;
+ else if (i == 2)
+ size = tok;
+ else if (i == 3)
+ type = tok;
+ }
+ if (i < 4) {
+ fprintf(stderr, "dm2md: failed to determine dmraid type\n");
+ return 1;
+ }
+
+ if (name[strlen(name) - 1] != ':') {
+ fprintf(stderr, "dm2md: invalid name field \'%s\'\n", name);
+ return 1;
+ }
+ name[strlen(name) - 1] = '\0';
+
+ array_size = strtoull(size, &end, 10);
+ if (end == size || *end != '\0') {
+ fprintf(stderr, "dm2md: invalid size \'%s\'\n", size);
+ return 1;
+ }
+
+ for (i = 0; i < dm_target_cnt; i++)
+ if (strcmp(type, dm_targets[i]) == 0)
+ switch (i) {
+ case DMRAID45:
+ return dmraid45(name, array_size);
+ case DMRAID1:
+ return dmraid1(name, array_size);
+ case DMRAID0:
+ return dmraid0(name, array_size);
+ default:
+ /* can't happen */
+ return 1;
+ }
+
+ fprintf(stderr, "dm2md: \'%s\' not a valid dmraid type\n", type);
+
+ return 1;
+}
+
+int main(int argc, char *argv[])
+{
+ char *line = NULL;
+ FILE *table;
+ int rc;
+ size_t n;
+
+ if (argc == 1)
+ table = stdin;
+ else if (argc == 2) {
+ table = fopen(argv[1], "r");
+ if (!table) {
+ fprintf(stderr, "dm2md: failed to open %s (%s)\n",
+ argv[1], strerror(errno));
+ return 1;
+ }
+ } else {
+ fprintf(stderr, "usage: dmraid -tay | dm2md\n");
+ fprintf(stderr, " - or -\n");
+ fprintf(stderr, "usage: dm2md <dmraid_table>\n");
+ return 1;
+ }
+
+ while (getline(&line, &n, table) > 0) {
+ if (line[0] != '#')
+ rc = handle_table_ent(line);
+ else
+ rc = 0;
+ if (line) {
+ free(line);
+ line = NULL;
+ }
+ if (rc)
+ return rc;
+ }
+
+ return 0;
+}
+