/* * mdadm - manage Linux "md" devices aka RAID arrays. * * Copyright (C) 2010 Neil Brown * * * 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: * */ /* * '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", };