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_ext2(fd, dname);
|
||||||
warn |= check_reiser(fd, dname);
|
warn |= check_reiser(fd, dname);
|
||||||
warn |= check_raid(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 &&
|
st->minor_version >= 1 &&
|
||||||
did_default &&
|
did_default &&
|
||||||
level == 1) {
|
level == 1 &&
|
||||||
warn = 1;
|
(warn & 1024) == 0) {
|
||||||
|
warn |= 1024;
|
||||||
fprintf(stderr, Name ": Note: this array has metadata at the start and\n"
|
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"
|
" may not be suitable as a boot device. If you plan to\n"
|
||||||
" store '/' or '/boot' on this device please ensure that\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_ext2(int fd, char *name);
|
||||||
extern int check_reiser(int fd, char *name);
|
extern int check_reiser(int fd, char *name);
|
||||||
extern int check_raid(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 get_mdp_major(void);
|
||||||
extern int dev_open(char *dev, int flags);
|
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 */
|
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
|
* Parse a 128 bit uuid in 4 integers
|
||||||
* format is 32 hexx nibbles with options :.<space> separator
|
* 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;
|
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)
|
void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk)
|
||||||
{
|
{
|
||||||
int d;
|
int d;
|
||||||
|
|
Loading…
Reference in New Issue