Check partition tables when creating array.
When creating an array, check if the devices have partition tables and print a warning if the table or the partitions might be destroyed by array creation. Signed-off-by: NeilBrown <neilb@suse.de>
This commit is contained in:
parent
f98841b385
commit
034b203a47
17
Create.c
17
Create.c
|
@ -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"
|
||||
|
|
1
mdadm.h
1
mdadm.h
|
@ -787,6 +787,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);
|
||||
|
|
176
util.c
176
util.c
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue