* [patch 1/1] [mdadm] Add partition checks when creating a new array
@ 2009-11-05 12:01 Trela, Maciej
0 siblings, 0 replies; 10+ messages in thread
From: Trela, Maciej @ 2009-11-05 12:01 UTC (permalink / raw)
To: linux-raid@vger.kernel.org
For the IMSM compatibility add partition checking when creating an array.
If the metadata overwrite the last partition, show the warning to the user.
The patch supports only MBR and GPT partition table types.
Regards,
Maciek.
--- util.c 2009-11-02 16:45:00.000000000 +0100
+++ ../../../../mdadm_neil/vobs/trelliscruzbay/mdadm/util.c 2009-10-26 15:13:32.000000000 +0100
@@ -65,6 +65,39 @@ struct blkpg_partition {
char volname[BLKPG_VOLNAMELTH]; /* volume label */
};
+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 +1129,142 @@ int get_dev_size(int fd, char *dname, un
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
+*/
+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;
+
+ // 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)) {
+ // 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
+*/
+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) {
+ if (endofpart > freesize) {
+ fprintf(stderr,
+ Name ": Not enough space for metadata on %s.\n",
+ dname);
+ return 1;
+ }
+ } else {
+ if (ret < 0) {
+ fprintf(stderr,
+ Name ": Unknown parition table on %s.\n",
+ dname);
+ } else {
+ fprintf(stderr,
+ Name ": Unknown error while reading %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;
--- mdadm.h 2009-11-02 16:44:57.000000000 +0100
+++ ../../../../mdadm_neil/vobs/trelliscruzbay/mdadm/mdadm.h 2009-10-26 15:13:23.000000000 +0100
@@ -787,6 +787,7 @@ extern int parse_layout_faulty(char *lay
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 *name, unsigned long long freesize);
extern int get_mdp_major(void);
extern int dev_open(char *dev, int flags);
--- Create.c 2009-11-02 16:44:54.000000000 +0100
+++ ../../../../mdadm_neil/vobs/trelliscruzbay/mdadm/Create.c 2009-10-24 01:50:20.000000000 +0200
@@ -334,8 +334,8 @@ int Create(struct supertype *st, char *m
fail = 1;
continue;
}
- }
-
+ }
+
freesize /= 2; /* convert to K */
if (chunk) {
/* round to chunk size */
@@ -368,6 +368,8 @@ int Create(struct supertype *st, char *m
warn |= check_ext2(fd, dname);
warn |= check_reiser(fd, dname);
warn |= check_raid(fd, dname);
+ // May metadata overwrite any partition?
+ warn |= check_partitions(fd, dname, freesize*2);
close(fd);
}
}
--
---------------------------------------------------------------------
Intel Technology Poland sp. z o.o.
z siedziba w Gdansku
ul. Slowackiego 173
80-298 Gdansk
Sad Rejonowy Gdansk Polnoc w Gdansku,
VII Wydzial Gospodarczy Krajowego Rejestru Sadowego,
numer KRS 101882
NIP 957-07-52-316
Kapital zakladowy 200.000 zl
This e-mail and any attachments may contain confidential material for
the sole use of the intended recipient(s). Any review or distribution
by others is strictly prohibited. If you are not the intended
recipient, please contact the sender and delete all copies.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [patch 1/1] [mdadm] Add partition checks when creating a new array
@ 2009-11-12 12:39 Trela, Maciej
2009-11-13 2:49 ` Neil Brown
0 siblings, 1 reply; 10+ messages in thread
From: Trela, Maciej @ 2009-11-12 12:39 UTC (permalink / raw)
To: linux-raid@vger.kernel.org, NeilBrown; +Cc: Williams, Dan J, Ciechanowski, Ed
Hello Neil,
I'm sending the patch that is connected with intel metadata compatibility.
The new code checks for existing partitions when creating an array.
If the metadata overwrites the last partition, the warning is shown to the user. The patch supports only MBR and GPT partition table types.
Despite the patch was implemented as IMSM compatibility issue I've decided to include the partition check for all metadata types as a generic code.
I would appreciate any feedback.
Regards,
Maciek.
diff --git a/Create.c b/Create.c
index c96b319..4849ac5 100644
--- a/Create.c
+++ b/Create.c
@@ -368,6 +368,8 @@ int Create(struct supertype *st, char *mddev,
warn |= check_ext2(fd, dname);
warn |= check_reiser(fd, dname);
warn |= check_raid(fd, dname);
+ // May metadata overwrite any partition?
+ warn |= check_partitions(fd, dname, freesize*2);
close(fd);
}
}
diff --git a/mdadm.h b/mdadm.h
index 261cdb7..3906571 100644
--- a/mdadm.h
+++ b/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 *name, unsigned long long freesize);
extern int get_mdp_major(void);
extern int dev_open(char *dev, int flags);
diff --git a/util.c b/util.c
index 048c39f..a9e2504 100644
--- a/util.c
+++ b/util.c
@@ -65,6 +65,39 @@ struct blkpg_partition {
char volname[BLKPG_VOLNAMELTH]; /* volume label */
};
+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 +1129,142 @@ 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
+*/
+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;
+
+ // 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)) {
+ // 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
+*/
+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) {
+ if (endofpart > freesize) {
+ fprintf(stderr,
+ Name ": Not enough space for metadata on %s.\n",
+ dname);
+ return 1;
+ }
+ } else {
+ if (ret < 0) {
+ fprintf(stderr,
+ Name ": Unknown parition table on %s.\n",
+ dname);
+ } else {
+ fprintf(stderr,
+ Name ": Unknown error while reading %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;
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-12 12:39 [patch 1/1] [mdadm] Add partition checks when creating a new array Trela, Maciej
@ 2009-11-13 2:49 ` Neil Brown
2009-11-19 15:40 ` Trela, Maciej
2009-11-20 17:03 ` Luca Berra
0 siblings, 2 replies; 10+ messages in thread
From: Neil Brown @ 2009-11-13 2:49 UTC (permalink / raw)
To: Trela, Maciej
Cc: linux-raid@vger.kernel.org, Williams, Dan J, Ciechanowski, Ed
On Thursday November 12, Maciej.Trela@intel.com wrote:
> Hello Neil,
> I'm sending the patch that is connected with intel metadata compatibility.
>
> The new code checks for existing partitions when creating an array.
> If the metadata overwrites the last partition, the warning is shown to the user. The patch supports only MBR and GPT partition table types.
> Despite the patch was implemented as IMSM compatibility issue I've decided to include the partition check for all metadata types as a generic code.
> I would appreciate any feedback.
Sorry for not responding the first time you posted this.
I agree with the principle. However I would rather not add code for
reading different partition types to mdadm. It would be much nicer if
that code came from a library.
Is there a good library that we could use?
libparted might be a possibility, but it seems rather over-weight.
/lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
Are there any other libraries for reading different partition tables?
I guess we can open-code it if we have to but I'd be happy if another
solution could be found.
I should probably change to using libblkid to check for the various
filesystem types...
Is this check really relevant for anything other RAID1 array. For any
other level, the fact that the metadata lies inside or outside the
current partitions is quite irrelevant as the old data will not be
useful anyway.
And I don't think it is sensible to report "unknown partition table".
If there is no partition table, there is nothing to check.
NeilBrown
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-13 2:49 ` Neil Brown
@ 2009-11-19 15:40 ` Trela, Maciej
2009-12-08 5:10 ` Neil Brown
2009-11-20 17:03 ` Luca Berra
1 sibling, 1 reply; 10+ messages in thread
From: Trela, Maciej @ 2009-11-19 15:40 UTC (permalink / raw)
To: Neil Brown; +Cc: linux-raid@vger.kernel.org, Williams, Dan J, Ciechanowski, Ed
>-----Original Message-----
>From: Neil Brown [mailto:neilb@suse.de]
>Sent: Friday, November 13, 2009 3:49 AM
>
>On Thursday November 12, Maciej.Trela@intel.com wrote:
>> Hello Neil,
>> I'm sending the patch that is connected with intel metadata
>compatibility.
>>
>> The new code checks for existing partitions when creating an array.
>> If the metadata overwrites the last partition, the warning is shown to
>the user. The patch supports only MBR and GPT partition table types.
>> Despite the patch was implemented as IMSM compatibility issue I've
>decided to include the partition check for all metadata types as a generic
>code.
>> I would appreciate any feedback.
>
>Sorry for not responding the first time you posted this.
>
>I agree with the principle. However I would rather not add code for
>reading different partition types to mdadm. It would be much nicer if
>that code came from a library.
>Is there a good library that we could use?
>libparted might be a possibility, but it seems rather over-weight.
>/lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
>
>Are there any other libraries for reading different partition tables?
>I guess we can open-code it if we have to but I'd be happy if another
>solution could be found.
>
Hello Neil,
I made some research but unfortunately I couldn't find any other library except libparted.
Assuming there are no other possibilities, do you think we could stay with the current solution or should I switch the patch to libparted?
I have the impression that with libparted this simple patch would be much bigger (given the code size)...
>I should probably change to using libblkid to check for the various
>filesystem types...
>
>Is this check really relevant for anything other RAID1 array. For any
>other level, the fact that the metadata lies inside or outside the
>current partitions is quite irrelevant as the old data will not be
>useful anyway.
Yes, that's right.
However, this check would be also relevant when creating a container with external metadata. Unfortunately in this case we do not know the raid level...
Thus, maybe the following condition would be appropriate:
if ((raid_level == CONTAINER) || ( !(external) && raid_level==1))
{
Check partitions
}
>
>And I don't think it is sensible to report "unknown partition table".
>If there is no partition table, there is nothing to check.
>
>NeilBrown
The idea behind this was that: maybe there is a partition table that we do not support so we should warn the user anyway, but probably this would be too paranoid... I'll change that.
Regards.
Maciek Trela.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-13 2:49 ` Neil Brown
2009-11-19 15:40 ` Trela, Maciej
@ 2009-11-20 17:03 ` Luca Berra
2009-11-20 17:22 ` Mr. James W. Laferriere
2009-12-12 22:50 ` Asdo
1 sibling, 2 replies; 10+ messages in thread
From: Luca Berra @ 2009-11-20 17:03 UTC (permalink / raw)
To: Neil Brown
Cc: Trela, Maciej, linux-raid@vger.kernel.org, Williams, Dan J,
Ciechanowski, Ed
On Fri, Nov 13, 2009 at 01:49:24PM +1100, Neil Brown wrote:
>Is there a good library that we could use?
>libparted might be a possibility, but it seems rather over-weight.
>/lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
>
>Are there any other libraries for reading different partition tables?
>I guess we can open-code it if we have to but I'd be happy if another
>solution could be found.
i don't think so,
but there are two tools
partx from util-linux
kpartix from multipath-tools (which is based on the former)
so we could either grab code from those or just invoke
partx -l (i believe every distro installs util-linux by default)
L.
--
Luca Berra -- bluca@comedia.it
Communication Media & Services S.r.l.
/"\
\ / ASCII RIBBON CAMPAIGN
X AGAINST HTML MAIL
/ \
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-20 17:03 ` Luca Berra
@ 2009-11-20 17:22 ` Mr. James W. Laferriere
2009-11-20 17:25 ` Mr. James W. Laferriere
2009-12-12 22:50 ` Asdo
1 sibling, 1 reply; 10+ messages in thread
From: Mr. James W. Laferriere @ 2009-11-20 17:22 UTC (permalink / raw)
To: Luca Berra
Cc: Neil Brown, Trela, Maciej, linux-raid@vger.kernel.org,
Williams, Dan J, Ciechanowski, Ed
Hello Luca ,
On Fri, 20 Nov 2009, Luca Berra wrote:
> On Fri, Nov 13, 2009 at 01:49:24PM +1100, Neil Brown wrote:
>> Is there a good library that we could use?
>> libparted might be a possibility, but it seems rather over-weight.
>> /lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
>>
>> Are there any other libraries for reading different partition tables?
>> I guess we can open-code it if we have to but I'd be happy if another
>> solution could be found.
>
> i don't think so,
> but there are two tools
> partx from util-linux
> kpartix from multipath-tools (which is based on the former)
>
> so we could either grab code from those or just invoke
> partx -l (i believe every distro installs util-linux by default)
>
> L.
Fyi , It seems Slackware does not install util-linux , It uses
util-linux-ng which does not have partx .
(afaik) util-linux was reported as not be being maintained . But that
is hearsay .
Hth , JimL
--
+------------------------------------------------------------------+
| James W. Laferriere | System Techniques | Give me VMS |
| Network&System Engineer | 3237 Holden Road | Give me Linux |
| babydr@baby-dragons.com | Fairbanks, AK. 99709 | only on AXP |
+------------------------------------------------------------------+
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-20 17:22 ` Mr. James W. Laferriere
@ 2009-11-20 17:25 ` Mr. James W. Laferriere
0 siblings, 0 replies; 10+ messages in thread
From: Mr. James W. Laferriere @ 2009-11-20 17:25 UTC (permalink / raw)
To: Luca Berra
Cc: Neil Brown, Trela, Maciej, linux-raid@vger.kernel.org,
Williams, Dan J, Ciechanowski, Ed
Hello Luca ,
On Fri, 20 Nov 2009, Mr. James W. Laferriere wrote:
> On Fri, 20 Nov 2009, Luca Berra wrote:
>> On Fri, Nov 13, 2009 at 01:49:24PM +1100, Neil Brown wrote:
>>> Is there a good library that we could use?
>>> libparted might be a possibility, but it seems rather over-weight.
>>> /lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
>>>
>>> Are there any other libraries for reading different partition tables?
>>> I guess we can open-code it if we have to but I'd be happy if another
>>> solution could be found.
>>
>> i don't think so,
>> but there are two tools
>> partx from util-linux
>> kpartix from multipath-tools (which is based on the former)
>>
>> so we could either grab code from those or just invoke
>> partx -l (i believe every distro installs util-linux by default)
>>
>> L.
> Fyi , It seems Slackware does not install util-linux , It uses
> util-linux-ng which does not have partx .
> (afaik) util-linux was reported as not be being maintained . But
> that is hearsay .
Sorry about replying to myself here .
It appears that I am mistaken , util-linux-ng DOES have a partx command
. At least the newest one (v2.16.1) does . Sorry about the Noise .
Twyl , JimL
--
+------------------------------------------------------------------+
| James W. Laferriere | System Techniques | Give me VMS |
| Network&System Engineer | 3237 Holden Road | Give me Linux |
| babydr@baby-dragons.com | Fairbanks, AK. 99709 | only on AXP |
+------------------------------------------------------------------+
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-19 15:40 ` Trela, Maciej
@ 2009-12-08 5:10 ` Neil Brown
0 siblings, 0 replies; 10+ messages in thread
From: Neil Brown @ 2009-12-08 5:10 UTC (permalink / raw)
To: Trela, Maciej
Cc: linux-raid@vger.kernel.org, Williams, Dan J, Ciechanowski, Ed
On Thu, 19 Nov 2009 15:40:21 +0000
"Trela, Maciej" <Maciej.Trela@intel.com> wrote:
> Hello Neil,
> I made some research but unfortunately I couldn't find any other library except libparted.
> Assuming there are no other possibilities, do you think we could stay with the current solution or should I switch the patch to libparted?
>
> I have the impression that with libparted this simple patch would be much bigger (given the code size)...
>
Fair enough.
I have made some changes resulting in the following patch.
Thanks,
NeilBrown
From 034b203a4754da7615d7b16bafeabfc4115dabea Mon Sep 17 00:00:00 2001
From: Trela, Maciej <Maciej.Trela@intel.com>
Date: Tue, 8 Dec 2009 16:07:47 +1100
Subject: [PATCH] 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>
---
Create.c | 17 +++++-
mdadm.h | 1 +
util.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 191 insertions(+), 3 deletions(-)
diff --git a/Create.c b/Create.c
index 5b01b63..d104c05 100644
--- a/Create.c
+++ b/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"
diff --git a/mdadm.h b/mdadm.h
index c7f864b..2bfe840 100644
--- a/mdadm.h
+++ b/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);
diff --git a/util.c b/util.c
index a0e4bcf..67c3550 100644
--- a/util.c
+++ b/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;
--
1.6.5.4
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-11-20 17:03 ` Luca Berra
2009-11-20 17:22 ` Mr. James W. Laferriere
@ 2009-12-12 22:50 ` Asdo
2009-12-14 11:33 ` Trela, Maciej
1 sibling, 1 reply; 10+ messages in thread
From: Asdo @ 2009-12-12 22:50 UTC (permalink / raw)
To: Neil Brown, Trela, Maciej, linux-raid@vger.kernel.org,
Williams, Dan J, Ciecha
Luca Berra wrote:
> On Fri, Nov 13, 2009 at 01:49:24PM +1100, Neil Brown wrote:
>> Is there a good library that we could use?
>> libparted might be a possibility, but it seems rather over-weight.
>> /lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
>>
>> Are there any other libraries for reading different partition tables?
>> I guess we can open-code it if we have to but I'd be happy if another
>> solution could be found.
>
> i don't think so,
> but there are two tools
> partx from util-linux
> kpartix from multipath-tools (which is based on the former)
>
> so we could either grab code from those or just invoke
> partx -l (i believe every distro installs util-linux by default)
>
> L.
I'm probably missing something obvious but...
why don't you use the kernel directly to detect if there are partitions
on the device?
Like if the user wants to make a raid on /dev/sdg but the device
/dev/sdg1 exists, that's a problem, you fail the creation. (*)
This would support all the partition types that the kernel supports.
Probing the partitions on the disks and adding them to /dev/sd?N is done
automatically in all recent distributions even for hotpluggable devices
so it's quite guaranteed that it would work
(*) Are there other situations that would overwrite a partition?
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [patch 1/1] [mdadm] Add partition checks when creating a new array
2009-12-12 22:50 ` Asdo
@ 2009-12-14 11:33 ` Trela, Maciej
0 siblings, 0 replies; 10+ messages in thread
From: Trela, Maciej @ 2009-12-14 11:33 UTC (permalink / raw)
To: Asdo, Neil Brown, linux-raid@vger.kernel.org, Williams, Dan J,
"Ciechanowski, Ed" <ed.
> -----Original Message-----
> From: Asdo [mailto:asdo@shiftmail.org]
> Sent: Saturday, December 12, 2009 11:50 PM
> To: Neil Brown; Trela, Maciej; linux-raid@vger.kernel.org; Williams,
> Dan J; Ciechanowski, Ed
> Subject: Re: [patch 1/1] [mdadm] Add partition checks when creating a
> new array
>
> Luca Berra wrote:
> > On Fri, Nov 13, 2009 at 01:49:24PM +1100, Neil Brown wrote:
> >> Is there a good library that we could use?
> >> libparted might be a possibility, but it seems rather over-weight.
> >> /lib/libparted-1.9.so.12.0.0 is larger than /sbin/mdadm !!!
> >>
> >> Are there any other libraries for reading different partition
> tables?
> >> I guess we can open-code it if we have to but I'd be happy if
> another
> >> solution could be found.
> >
> > i don't think so,
> > but there are two tools
> > partx from util-linux
> > kpartix from multipath-tools (which is based on the former)
> >
> > so we could either grab code from those or just invoke
> > partx -l (i believe every distro installs util-linux by default)
> >
> > L.
>
> I'm probably missing something obvious but...
> why don't you use the kernel directly to detect if there are partitions
> on the device?
>
> Like if the user wants to make a raid on /dev/sdg but the device
> /dev/sdg1 exists, that's a problem, you fail the creation. (*)
>
It is ok to create an array if partition exists on a device.
We just want to check if the metadata will overwrite the existing partition data.
If there is not enough space for metadata, the user will be warned.
However, this check is reasonable only if the user may want to preserve the partition data,
like when creating Raid1...
Regards,
Maciek.
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2009-12-14 11:33 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-12 12:39 [patch 1/1] [mdadm] Add partition checks when creating a new array Trela, Maciej
2009-11-13 2:49 ` Neil Brown
2009-11-19 15:40 ` Trela, Maciej
2009-12-08 5:10 ` Neil Brown
2009-11-20 17:03 ` Luca Berra
2009-11-20 17:22 ` Mr. James W. Laferriere
2009-11-20 17:25 ` Mr. James W. Laferriere
2009-12-12 22:50 ` Asdo
2009-12-14 11:33 ` Trela, Maciej
-- strict thread matches above, loose matches on Subject: below --
2009-11-05 12:01 Trela, Maciej
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).