diff options
-rw-r--r-- | Create.c | 17 | ||||
-rw-r--r-- | Grow.c | 22 | ||||
-rw-r--r-- | Manage.c | 5 | ||||
-rw-r--r-- | mdadm.h | 1 | ||||
-rw-r--r-- | super-ddf.c | 2 | ||||
-rw-r--r-- | util.c | 176 |
6 files changed, 210 insertions, 13 deletions
@@ -375,11 +375,22 @@ int Create(struct supertype *st, char *mddev, warn |= check_ext2(fd, dname); warn |= check_reiser(fd, dname); warn |= check_raid(fd, dname); - if (st && strcmp(st->ss->name, "1.x") == 0 && + if (strcmp(st->ss->name, "1.x") == 0 && + st->minor_version >= 1) + /* metadata at front */ + warn |= check_partitions(fd, dname, 0); + else if (level == 1 || level == LEVEL_CONTAINER) + /* partitions could be meaningful */ + warn |= check_partitions(fd, dname, freesize*2); + else + /* partitions cannot be meaningful */ + warn |= check_partitions(fd, dname, 0); + if (strcmp(st->ss->name, "1.x") == 0 && st->minor_version >= 1 && did_default && - level == 1) { - warn = 1; + level == 1 && + (warn & 1024) == 0) { + warn |= 1024; fprintf(stderr, Name ": Note: this array has metadata at the start and\n" " may not be suitable as a boot device. If you plan to\n" " store '/' or '/boot' on this device please ensure that\n" @@ -569,10 +569,17 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, goto release; } ioctl(fd, GET_ARRAY_INFO, &array); + size = get_component_size(fd); + if (size == 0) + size = array.size; if (!quiet) - fprintf(stderr, Name ": component size of %s has been set to %dK\n", - devname, array.size); + fprintf(stderr, Name ": component size of %s has been set to %lluK\n", + devname, size); changed = 1; + } else { + size = get_component_size(fd); + if (size == 0) + size = array.size; } /* ======= set level =========== */ @@ -844,10 +851,10 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, if (chunksize) { nchunk = chunksize * 1024; - if (array.size % chunksize) { - fprintf(stderr, Name ": component size %dK is not" + if (size % chunksize) { + fprintf(stderr, Name ": component size %lluK is not" " a multiple of chunksize %dK\n", - array.size, chunksize); + size, chunksize); break; } } @@ -891,13 +898,12 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file, } /* Check that we can hold all the data */ - size = ndata * (long long)array.size; get_dev_size(fd, NULL, &array_size); - if (size < (array_size/1024)) { + if (ndata * size < (array_size/1024)) { fprintf(stderr, Name ": this change will reduce the size of the array.\n" " use --grow --array-size first to truncate array.\n" " e.g. mdadm --grow %s --array-size %llu\n", - devname, size); + devname, ndata * size); rv = 1; break; } @@ -565,7 +565,10 @@ int Manage_subdevs(char *devname, int fd, disc.state |= 1 << MD_DISK_WRITEMOSTLY; if (dv->writemostly == 2) disc.state &= ~(1 << MD_DISK_WRITEMOSTLY); - if (ioctl(fd, ADD_NEW_DISK, &disc) == 0) { + /* don't even try if disk is marked as faulty */ + errno = 0; + if ((disc.state & 1) == 0 && + ioctl(fd, ADD_NEW_DISK, &disc) == 0) { if (verbose >= 0) fprintf(stderr, Name ": re-added %s\n", dv->devname); continue; @@ -807,6 +807,7 @@ extern int parse_layout_faulty(char *layout); extern int check_ext2(int fd, char *name); extern int check_reiser(int fd, char *name); extern int check_raid(int fd, char *name); +extern int check_partitions(int fd, char *dname, unsigned long long freesize); extern int get_mdp_major(void); extern int dev_open(char *dev, int flags); diff --git a/super-ddf.c b/super-ddf.c index 14f8330..3e30229 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -1739,7 +1739,7 @@ static int init_super_ddf(struct supertype *st, memset(pd, 0xff, pdsize); memset(pd, 0, sizeof(*pd)); - pd->magic = DDF_PHYS_DATA_MAGIC; + pd->magic = DDF_PHYS_RECORDS_MAGIC; pd->used_pdes = __cpu_to_be16(0); pd->max_pdes = __cpu_to_be16(max_phys_disks); memset(pd->pad, 0xff, 52); @@ -65,6 +65,43 @@ struct blkpg_partition { char volname[BLKPG_VOLNAMELTH]; /* volume label */ }; +/* partition table structures so we can check metadata position + * against the end of the last partition. + * Only handle MBR ant GPT partition tables. + */ +struct MBR_part_record { + __u8 bootable; + __u8 first_head; + __u8 first_sector; + __u8 first_cyl; + __u8 part_type; + __u8 last_head; + __u8 last_sector; + __u8 last_cyl; + __u32 first_sect_lba; + __u32 blocks_num; +}; + +struct GPT_part_entry { + unsigned char type_guid[16]; + unsigned char partition_guid[16]; + unsigned char starting_lba[8]; + unsigned char ending_lba[8]; + unsigned char attr_bits[8]; + unsigned char name[72]; +}; + +/* MBR/GPT magic numbers */ +#define MBR_SIGNATURE_MAGIC __cpu_to_le16(0xAA55) +#define GPT_SIGNATURE_MAGIC __cpu_to_le64(0x5452415020494645ULL) + +#define MBR_SIGNATURE_OFFSET 510 +#define MBR_PARTITION_TABLE_OFFSET 446 +#define MBR_PARTITIONS 4 +#define MBR_GPT_PARTITION_TYPE 0xEE +#define GPT_ALL_PARTITIONS_OFFSET 80 +#define GPT_ENTRY_SIZE_OFFSET 84 + /* * Parse a 128 bit uuid in 4 integers * format is 32 hexx nibbles with options :.<space> separator @@ -1096,6 +1133,145 @@ int get_dev_size(int fd, char *dname, unsigned long long *sizep) return 1; } + +/* Sets endofpart parameter to the last block used by the last GPT partition on the device. + * Returns: 1 if successful + * -1 for unknown partition type + * 0 for other errors + */ +static int get_gpt_last_partition_end(int fd, unsigned long long *endofpart) +{ + unsigned char buf[512]; + unsigned char empty_gpt_entry[16]= {0}; + struct GPT_part_entry *part; + unsigned long long curr_part_end; + unsigned all_partitions, entry_size; + int part_nr; + + *endofpart = 0; + + /* read GPT header */ + lseek(fd, 512, SEEK_SET); + if (read(fd, buf, 512) != 512) + return 0; + + /* get the number of partition entries and the entry size */ + all_partitions = __le32_to_cpu(buf[GPT_ALL_PARTITIONS_OFFSET]); + entry_size = __le32_to_cpu(buf[GPT_ENTRY_SIZE_OFFSET]); + + /* Check GPT signature*/ + if (*((__u64*)buf) != GPT_SIGNATURE_MAGIC) + return -1; + + /* sanity checks */ + if (all_partitions > 1024 || + entry_size > 512) + return -1; + + /* read first GPT partition entries */ + if (read(fd, buf, 512) != 512) + return 0; + + part = (struct GPT_part_entry*)buf; + + for (part_nr=0; part_nr < all_partitions; part_nr++) { + /* is this valid partition? */ + if (memcmp(part->type_guid, empty_gpt_entry, 16) != 0) { + /* check the last lba for the current partition */ + curr_part_end = __le64_to_cpu(*(__u64*)part->ending_lba); + if (curr_part_end > *endofpart) + *endofpart = curr_part_end; + } + + part = (struct GPT_part_entry*)((unsigned char*)part + entry_size); + + if ((unsigned char *)part >= buf + 512) { + if (read(fd, buf, 512) != 512) + return 0; + part = (struct GPT_part_entry*)buf; + } + } + return 1; +} + +/* Sets endofpart parameter to the last block used by the last partition on the device. + * Returns: 1 if successful + * -1 for unknown partition type + * 0 for other errors + */ +static int get_last_partition_end(int fd, unsigned long long *endofpart) +{ + unsigned char boot_sect[512]; + struct MBR_part_record *part; + unsigned long long curr_part_end; + int part_nr; + int retval = 0; + + *endofpart = 0; + + /* read MBR */ + lseek(fd, 0, 0); + if (read(fd, boot_sect, 512) != 512) + goto abort; + + /* check MBP signature */ + if (*((__u16*)(boot_sect + MBR_SIGNATURE_OFFSET)) + == MBR_SIGNATURE_MAGIC) { + retval = 1; + /* found the correct signature */ + part = (struct MBR_part_record*) + (boot_sect + MBR_PARTITION_TABLE_OFFSET); + + for (part_nr=0; part_nr < MBR_PARTITIONS; part_nr++) { + /* check for GPT type */ + if (part->part_type == MBR_GPT_PARTITION_TYPE) { + retval = get_gpt_last_partition_end(fd, endofpart); + break; + } + /* check the last used lba for the current partition */ + curr_part_end = __le32_to_cpu(part->first_sect_lba) + + __le32_to_cpu(part->blocks_num); + if (curr_part_end > *endofpart) + *endofpart = curr_part_end; + + part++; + } + } else { + /* Unknown partition table */ + retval = -1; + } + abort: + return retval; +} + +int check_partitions(int fd, char *dname, unsigned long long freesize) +{ + /* + * Check where the last partition ends + */ + unsigned long long endofpart; + int ret; + + if ((ret = get_last_partition_end(fd, &endofpart)) > 0) { + /* There appears to be a partition table here */ + if (freesize == 0) { + /* partitions will not be visible in new device */ + fprintf(stderr, + Name ": partition table exists on %s but will be lost or\n" + " meaningless after creating array\n", + dname); + return 1; + } else if (endofpart > freesize) { + /* last partition overlaps metadata */ + fprintf(stderr, + Name ": metadata will over-write last partition on %s.\n", + dname); + return 1; + } + } + return 0; +} + void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk) { int d; |