From: Petr Uzel <petr.uzel@suse.cz>
To: Davidlohr Bueso <dave@gnu.org>
Cc: util-linux <util-linux@vger.kernel.org>
Subject: Re: [PATCH v2 2/2] gpt: create empty disklabels
Date: Thu, 1 Nov 2012 10:06:59 +0100 [thread overview]
Message-ID: <20121101090659.GH3979@foxbat.suse.cz> (raw)
In-Reply-To: <1351358627.2842.3.camel@offbook>
[-- Attachment #1: Type: text/plain, Size: 12339 bytes --]
On Sat, Oct 27, 2012 at 07:23:47PM +0200, Davidlohr Bueso wrote:
> This patch enables creating a new, empty, GPT disklabel from either
> an empty disk or one that already has a disklabel. For this
> purpose, a 'g' option is added to the main menu and is visible to all
> labels. Here's an example for a scsi_debug device (/dev/sdb):
>
> ...
> Device does not contain a recognized partition table
> Building a new DOS disklabel with disk identifier 0x20a614c8.
> 3696: fdisk: CONTEXT: zeroize in-memory first sector buffer
>
> Command (m for help): g
> 3696: fdisk: LABEL: changing to gpt label
>
> 3696: fdisk: CONTEXT: zeroize in-memory first sector buffer
> 3696: fdisk: LABEL: created new empty GPT disklabel (GUID: D4EA0706-F011-46DC-B7DE-6A72C7090AF8)
>
> Command (m for help): w
> The partition table has been altered!
> ...
>
> Signed-off-by: Davidlohr Bueso <dave@gnu.org>
Looks good to me and it also survived my testing.
Reviewed-and-tested-by: Petr Uzel <petr.uzel@suse.cz>
> ---
> fdisks/fdisk.c | 4 ++
> fdisks/gpt.c | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 200 insertions(+), 6 deletions(-)
>
> diff --git a/fdisks/fdisk.c b/fdisks/fdisk.c
> index e271ea1..a3ac087 100644
> --- a/fdisks/fdisk.c
> +++ b/fdisks/fdisk.c
> @@ -90,6 +90,7 @@ static const struct menulist_descr menulist[] = {
> {'e', N_("edit drive data"), {OSF_LABEL, 0}},
> {'f', N_("fix partition order"), {0, DOS_LABEL}},
> {'g', N_("create an IRIX (SGI) partition table"), {0, ANY_LABEL}},
> + {'g', N_("create a new empty GPT partition table"), {ANY_LABEL, 0}},
> {'h', N_("change number of heads"), {0, DOS_LABEL | SUN_LABEL}},
> {'i', N_("change interleave factor"), {0, SUN_LABEL}},
> {'i', N_("change the disk identifier"), {0, DOS_LABEL}},
> @@ -1694,6 +1695,9 @@ static void command_prompt(struct fdisk_context *cxt)
> case 'd':
> delete_partition(cxt, get_existing_partition(cxt, 1, partitions));
> break;
> + case 'g':
> + fdisk_create_disklabel(cxt, "gpt");
> + break;
> case 'i':
> if (disklabel == SGI_LABEL)
> create_sgiinfo(cxt);
> diff --git a/fdisks/gpt.c b/fdisks/gpt.c
> index 48397f3..843dc44 100644
> --- a/fdisks/gpt.c
> +++ b/fdisks/gpt.c
> @@ -19,7 +19,6 @@
> * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
> - *
> */
>
> #include <stdio.h>
> @@ -59,7 +58,8 @@
>
> #define EFI_PMBR_OSTYPE 0xEE
> #define MSDOS_MBR_SIGNATURE 0xAA55
> -#define GPT_PART_NAME_LEN 72 / sizeof(uint16_t)
> +#define GPT_PART_NAME_LEN 72 / sizeof(uint16_t)
> +#define GPT_NPARTITIONS 128
>
> /* Globally unique identifier */
> struct gpt_guid {
> @@ -96,8 +96,8 @@ struct gpt_attr {
>
> /* The GPT Partition entry array contains an array of GPT entries. */
> struct gpt_entry {
> - struct gpt_guid partition_type_guid; /* purpose and type of the partition */
> - struct gpt_guid unique_partition_guid;
> + struct gpt_guid partition_type_guid; /* purpose and type of the partition */
> + struct gpt_guid unique_partition_guid;
> uint64_t lba_start;
> uint64_t lba_end;
> struct gpt_attr attr;
> @@ -115,7 +115,7 @@ struct gpt_header {
> uint64_t alternative_lba; /* backup GPT header */
> uint64_t first_usable_lba; /* first usable logical block for partitions */
> uint64_t last_usable_lba; /* last usable logical block for partitions */
> - struct gpt_guid disk_guid; /* unique disk identifier */
> + struct gpt_guid disk_guid; /* unique disk identifier */
> uint64_t partition_entry_lba; /* stat LBA of the partition entry array */
> uint32_t npartition_entries; /* total partition entries - normally 128 */
> uint32_t sizeof_partition_entry; /* bytes for each GUID pt */
> @@ -298,6 +298,125 @@ static inline int partition_unused(struct gpt_entry e)
> }
>
> /*
> + * Builds a clean new valid protective MBR - will wipe out any existing data.
> + * Returns 0 on success, otherwise < 0 on error.
> + */
> +static int gpt_mknew_pmbr(struct fdisk_context *cxt)
> +{
> + struct gpt_legacy_mbr *pmbr = NULL;
> +
> + if (!cxt || !cxt->firstsector)
> + return -ENOSYS;
> +
> + fdisk_zeroize_firstsector(cxt);
> +
> + pmbr = (struct gpt_legacy_mbr *) cxt->firstsector;
> +
> + pmbr->signature = cpu_to_le16(MSDOS_MBR_SIGNATURE);
> + pmbr->partition_record[0].os_type = EFI_PMBR_OSTYPE;
> + pmbr->partition_record[0].start_sector = 1;
> + pmbr->partition_record[0].end_head = 0xFE;
> + pmbr->partition_record[0].end_sector = 0xFF;
> + pmbr->partition_record[0].end_track = 0xFF;
> + pmbr->partition_record[0].starting_lba = cpu_to_le32(1);
> + pmbr->partition_record[0].size_in_lba =
> + cpu_to_le32(min((uint32_t) cxt->total_sectors - 1, 0xFFFFFFFF));
> +
> + return 0;
> +}
> +
> +/* some universal differences between the headers */
> +static void gpt_mknew_header_common(struct fdisk_context *cxt,
> + struct gpt_header *header, uint64_t lba)
> +{
> + if (!cxt || !header)
> + return;
> +
> + header->my_lba = cpu_to_le64(lba);
> +
> + if (lba == GPT_PRIMARY_PARTITION_TABLE_LBA) { /* primary */
> + header->alternative_lba = cpu_to_le64(cxt->total_sectors - 1);
> + header->partition_entry_lba = cpu_to_le64(2);
> + } else { /* backup */
> + uint64_t esz = le32_to_cpu(header->npartition_entries) * sizeof(struct gpt_entry);
> + uint64_t esects = (esz + cxt->sector_size - 1) / cxt->sector_size;
> +
> + header->alternative_lba = cpu_to_le64(GPT_PRIMARY_PARTITION_TABLE_LBA);
> + header->partition_entry_lba = cpu_to_le64(cxt->total_sectors - 1 - esects);
> + }
> +}
> +
> +/*
> + * Builds a new GPT header (at sector lba) from a backup header2.
> + * If building a primary header, then backup is the secondary, and vice versa.
> + *
> + * Always pass a new (zeroized) header to build upon as we don't
> + * explicitly zero-set some values such as CRCs and reserved.
> + *
> + * Returns 0 on success, otherwise < 0 on error.
> + */
> +static int gpt_mknew_header_from_bkp(struct fdisk_context *cxt,
> + struct gpt_header *header,
> + uint64_t lba,
> + struct gpt_header *header2)
> +{
> + if (!cxt || !header || !header2)
> + return -ENOSYS;
> +
> + header->signature = header2->signature;
> + header->revision = header2->revision;
> + header->size = header2->size;
> + header->npartition_entries = header2->npartition_entries;
> + header->sizeof_partition_entry = header2->sizeof_partition_entry;
> + header->first_usable_lba = header2->first_usable_lba;
> + header->last_usable_lba = header2->last_usable_lba;
> +
> + memcpy(&header->disk_guid,
> + &header2->disk_guid, sizeof(header2->disk_guid));
> + gpt_mknew_header_common(cxt, header, lba);
> +
> + return 0;
> +}
> +
> +/*
> + * Builds a clean new GPT header (currently under revision 1.0).
> + *
> + * Always pass a new (zeroized) header to build upon as we don't
> + * explicitly zero-set some values such as CRCs and reserved.
> + *
> + * Returns 0 on success, otherwise < 0 on error.
> + */
> +static int gpt_mknew_header(struct fdisk_context *cxt,
> + struct gpt_header *header, uint64_t lba)
> +{
> + uint64_t esz = 0;
> +
> + if (!cxt || !header)
> + return -ENOSYS;
> +
> + esz = sizeof(struct gpt_entry) * GPT_NPARTITIONS / cxt->sector_size;
> +
> + header->signature = cpu_to_le64(GPT_HEADER_SIGNATURE);
> + header->revision = cpu_to_le32(GPT_HEADER_REVISION_V1_00);
> + header->size = cpu_to_le32(sizeof(struct gpt_header));
> +
> + /*
> + * 128 partitions is the default. It can go behond this, however,
> + * we're creating a de facto header here, so no funny business.
> + */
> + header->npartition_entries = cpu_to_le32(GPT_NPARTITIONS);
> + header->sizeof_partition_entry = cpu_to_le32(sizeof(struct gpt_entry));
> + header->first_usable_lba = cpu_to_le64(esz + 2);
> + header->last_usable_lba = cpu_to_le64(cxt->total_sectors - 2 - esz);
> +
> + gpt_mknew_header_common(cxt, header, lba);
> + uuid_generate_random((unsigned char *) &header->disk_guid);
> + swap_efi_guid(&header->disk_guid);
> +
> + return 0;
> +}
> +
> +/*
> * Checks if there is a valid protective MBR partition table.
> * Returns 0 if it is invalid or failure. Otherwise, return
> * GPT_MBR_PROTECTIVE or GPT_MBR_HYBRID, depeding on the detection.
> @@ -850,6 +969,22 @@ static void gpt_init(void)
> partitions = le32_to_cpu(pheader->npartition_entries);
> }
>
> +/*
> + * Deinitialize fdisk-specific variables
> + */
> +static void gpt_deinit(void)
> +{
> + free(ents);
> + free(pheader);
> + free(bheader);
> + ents = NULL;
> + pheader = NULL;
> + bheader = NULL;
> +
> + disklabel = ANY_LABEL;
> + partitions = 0;
> +}
> +
> static int gpt_probe_label(struct fdisk_context *cxt)
> {
> int mbr_type;
> @@ -899,6 +1034,7 @@ static char *encode_to_utf8(unsigned char *src, size_t count)
> uint16_t c;
> char *dest = xmalloc(count * sizeof(char));
> size_t i, j, len = count;
> +
> memset(dest, 0, sizeof(char) * count);
>
> for (j = i = 0; i + 2 <= count; i += 2) {
> @@ -1363,6 +1499,60 @@ static void gpt_add_partition(struct fdisk_context *cxt, int partnum,
> printf(_("Created partition %d\n"), partnum + 1);
> }
>
> +/*
> + * Create a new GPT disklabel - destroys any previous data.
> + */
> +static int gpt_create_disklabel(struct fdisk_context *cxt)
> +{
> + int rc = 0;
> + ssize_t entry_sz = 0;
> +
> + /*
> + * Reset space or clear data from headers, pt entries and
> + * protective MBR. Big fat warning: any previous content is
> + * overwritten, so ask users to be sure!.
> + *
> + * When no header, entries or pmbr is set, we're probably
> + * dealing with a new, empty disk - so always allocate memory
> + * to deal with the data structures whatever the case is.
> + */
> + gpt_deinit();
> +
> + rc = gpt_mknew_pmbr(cxt);
> + if (rc < 0)
> + goto done;
> +
> + pheader = xcalloc(1, sizeof(*pheader));
> + rc = gpt_mknew_header(cxt, pheader, GPT_PRIMARY_PARTITION_TABLE_LBA);
> + if (rc < 0)
> + goto done;
> +
> + bheader = xcalloc(1, sizeof(*bheader));
> + rc = gpt_mknew_header_from_bkp(cxt, bheader, last_lba(cxt), pheader);
> + if (rc < 0)
> + goto done;
> +
> + entry_sz = le32_to_cpu(pheader->npartition_entries) *
> + le32_to_cpu(pheader->sizeof_partition_entry);
> + ents = xcalloc(1, sizeof(*ents) * entry_sz);
> +
> + gpt_recompute_crc(pheader, ents);
> + gpt_recompute_crc(bheader, ents);
> +
> + gpt_init();
> + DBG(LABEL, dbgprint("created new empty GPT disklabel "
> + "(GUID: %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X)",
> + pheader->disk_guid.time_low, pheader->disk_guid.time_mid,
> + pheader->disk_guid.time_hi_and_version,
> + pheader->disk_guid.clock_seq_hi,
> + pheader->disk_guid.clock_seq_low,
> + pheader->disk_guid.node[0], pheader->disk_guid.node[1],
> + pheader->disk_guid.node[2], pheader->disk_guid.node[3],
> + pheader->disk_guid.node[4], pheader->disk_guid.node[5]));
> +done:
> + return rc;
> +}
> +
> static struct fdisk_parttype *gpt_get_partition_type(struct fdisk_context *cxt,
> int i)
> {
> @@ -1409,7 +1599,7 @@ const struct fdisk_label gpt_label =
> .probe = gpt_probe_label,
> .write = gpt_write_disklabel,
> .verify = gpt_verify_disklabel,
> - .create = NULL,
> + .create = gpt_create_disklabel,
> .part_add = gpt_add_partition,
> .part_delete = gpt_delete_partition,
> .part_get_type = gpt_get_partition_type,
> --
> 1.7.9.5
>
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe util-linux" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Petr
--
Petr Uzel
IRC: ptr_uzl @ freenode
[-- Attachment #2: Type: application/pgp-signature, Size: 198 bytes --]
next prev parent reply other threads:[~2012-11-01 9:07 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-10-27 17:23 [PATCH v2 2/2] gpt: create empty disklabels Davidlohr Bueso
2012-11-01 9:06 ` Petr Uzel [this message]
2012-11-02 11:35 ` Karel Zak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20121101090659.GH3979@foxbat.suse.cz \
--to=petr.uzel@suse.cz \
--cc=dave@gnu.org \
--cc=util-linux@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.