summaryrefslogtreecommitdiffstats
path: root/super-mbr.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--super-mbr.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/super-mbr.c b/super-mbr.c
new file mode 100644
index 0000000..839f000
--- /dev/null
+++ b/super-mbr.c
@@ -0,0 +1,206 @@
+/*
+ * mdadm - manage Linux "md" devices aka RAID arrays.
+ *
+ * Copyright (C) 2010 Neil Brown <neilb@suse.de>
+ *
+ *
+ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Author: Neil Brown
+ * Email: <neil@brown.name>
+ *
+ */
+
+/*
+ * 'mbr' is a pseudo metadata type for devices which have a
+ * partition table in the Master Boot Record (mbr) also known
+ * as a dos partition table.
+ *
+ * Obviously arrays cannot be created or assembled for this type.
+ * It is used to allow a new bare device to have an partition table
+ * added so the member partitions can then be included in other
+ * arrays as relevant.
+ *
+ * The meaning operations are:
+ * examine_super, but not brief_examine_super or export_examine
+ * load_super
+ * store_super
+ */
+
+#include "mdadm.h"
+#include "part.h"
+
+static void free_mbr(struct supertype *st)
+{
+ free(st->sb);
+ st->sb = NULL;
+}
+
+static void examine_mbr(struct supertype *st, char *homehost)
+{
+ struct MBR *sb = st->sb;
+ int i;
+
+ printf(" MBR Magic : %04x\n", sb->magic);
+ for (i = 0; i < MBR_PARTITIONS; i++)
+ /*
+ * Have to make every access through sb rather than using a
+ * pointer to the partition table (or an entry), since the
+ * entries are not properly aligned.
+ */
+ if (sb->parts[i].blocks_num)
+ printf("Partition[%d] : %12lu sectors at %12lu (type %02x)\n",
+ i,
+ (unsigned long)__le32_to_cpu(sb->parts[i].blocks_num),
+ (unsigned long)__le32_to_cpu(sb->parts[i].first_sect_lba),
+ sb->parts[i].part_type);
+
+}
+
+static int load_super_mbr(struct supertype *st, int fd, char *devname)
+{
+ /* try to read an mbr
+ * Return
+ * 0 on success
+ * 1 cannot get record
+ * 2 record is meaningless
+ */
+ struct MBR *super;
+
+ free_mbr(st);
+
+ if (posix_memalign((void**)&super, 512, 512) != 0) {
+ pr_err("could not allocate superblock\n");
+ return 1;
+ }
+
+ lseek(fd, 0, 0);
+ if (read(fd, super, sizeof(*super)) != sizeof(*super)) {
+ if (devname)
+ pr_err("Cannot read partition table on %s\n",
+ devname);
+ free(super);
+ return 1;
+ }
+
+ if (super->magic != MBR_SIGNATURE_MAGIC) {
+ if (devname)
+ pr_err("No partition table found on %s\n",
+ devname);
+ free(super);
+ return 1;
+ }
+
+ st->sb = super;
+
+ if (st->ss == NULL) {
+ st->ss = &mbr;
+ st->minor_version = 0;
+ st->max_devs = 1;
+ st->info = NULL;
+ }
+ return 0;
+}
+
+static int store_mbr(struct supertype *st, int fd)
+{
+ struct MBR *old, *super;
+
+ if (posix_memalign((void**)&old, 512, 512) != 0) {
+ pr_err("could not allocate superblock\n");
+ return 1;
+ }
+
+ lseek(fd, 0, 0);
+ if (read(fd, old, sizeof(*old)) != sizeof(*old)) {
+ free(old);
+ return 1;
+ }
+
+ super = st->sb;
+ memcpy(super->pad, old->pad, sizeof(super->pad));
+ free(old);
+ lseek(fd, 0, 0);
+ if (write(fd, super, sizeof(*super)) != sizeof(*super))
+ return 4;
+ fsync(fd);
+ ioctl(fd, BLKRRPART, 0);
+ return 0;
+}
+
+static void getinfo_mbr(struct supertype *st, struct mdinfo *info, char *map)
+{
+ struct MBR *sb = st->sb;
+ int i;
+
+ memset(&info->array, 0, sizeof(info->array));
+ memset(&info->disk, 0, sizeof(info->disk));
+ strcpy(info->text_version, "mbr");
+ strcpy(info->name, "mbr");
+ info->component_size = 0;
+
+ for (i = 0; i < MBR_PARTITIONS ; i++)
+ /*
+ * Have to make every access through sb rather than using a
+ * pointer to the partition table (or an entry), since the
+ * entries are not properly aligned.
+ */
+ if (sb->parts[i].blocks_num) {
+ unsigned long last =
+ (unsigned long)__le32_to_cpu(sb->parts[i].blocks_num)
+ + (unsigned long)__le32_to_cpu(sb->parts[i].first_sect_lba);
+ if (last > info->component_size)
+ info->component_size = last;
+ }
+
+}
+
+static struct supertype *match_metadata_desc(char *arg)
+{
+ struct supertype *st;
+
+ if (strcmp(arg, "mbr") != 0)
+ return NULL;
+
+ st = xmalloc(sizeof(*st));
+ st->ss = &mbr;
+ st->info = NULL;
+ st->minor_version = 0;
+ st->max_devs = 1;
+ st->sb = NULL;
+ return st;
+}
+
+static int validate_geometry(struct supertype *st, int level,
+ int layout, int raiddisks,
+ int *chunk, unsigned long long size,
+ unsigned long long data_offset,
+ char *subdev, unsigned long long *freesize,
+ int consistency_policy, int verbose)
+{
+ pr_err("mbr metadata cannot be used this way\n");
+ return 0;
+}
+
+struct superswitch mbr = {
+ .examine_super = examine_mbr,
+ .validate_geometry = validate_geometry,
+ .match_metadata_desc = match_metadata_desc,
+ .load_super = load_super_mbr,
+ .store_super = store_mbr,
+ .getinfo_super = getinfo_mbr,
+ .free_super = free_mbr,
+ .name = "mbr",
+};