From: "Vladimir 'φ-coder/phcoder' Serbinenko" <phcoder@gmail.com>
To: The development of GNU GRUB <grub-devel@gnu.org>
Subject: Re: [PATCH] Install to LVM PVs
Date: Thu, 26 Sep 2013 10:53:19 +0200 [thread overview]
Message-ID: <5243F5FF.4000804@gmail.com> (raw)
In-Reply-To: <l1ulib$iun$1@ger.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 10367 bytes --]
On 25.09.2013 14:39, Gabriel de Perthuis wrote:
> Hello,
> This patch lets grub install to a reserved area in LVM physical volumes.
> These bootloader areas can be created with LVM 2.02.99 and the
> --bootloaderareasize argument to pvcreate and vgconvert.
> I tested it in QEMU, installing to and booting a disk that contains a PV
> and no partition table.
>
This is not how the use of this area was imagined. There are couple of
subtleties which your patch didn't take in account.
Currently there is joint developpement with LVM guys but it wasn't
published yet.
>
> === modified file 'grub-core/disk/lvm.c'
> --- grub-core/disk/lvm.c 2012-06-25 15:52:20 +0000
> +++ grub-core/disk/lvm.c 2013-09-25 11:03:21 +0000
> @@ -95,6 +95,38 @@
> }
> }
>
> +static struct grub_lvm_pv_header *
> +grub_lvm_get_pvh(grub_disk_t disk, char buf[static GRUB_LVM_LABEL_SIZE])
> +{
> + struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
> + unsigned int i;
> +
> + /* Search for label. */
> + for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
> + {
> + if (grub_disk_read (disk, i, 0, GRUB_LVM_LABEL_SIZE, buf))
> + return NULL;
> +
> + if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
> + sizeof (lh->id)))
> + && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
> + sizeof (lh->type))))
> + break;
> + }
> +
> + /* Return if we didn't find a label. */
> + if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
> + {
> +#ifdef GRUB_UTIL
> + grub_util_info ("no LVM signature found");
> +#endif
> + return NULL;
> + }
> +
> + return (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
> +}
> +
> +
> static struct grub_diskfilter_vg *
> grub_lvm_detect (grub_disk_t disk,
> struct grub_diskfilter_pv_id *id,
> @@ -102,11 +134,10 @@
> {
> grub_err_t err;
> grub_uint64_t mda_offset, mda_size;
> - char buf[GRUB_LVM_LABEL_SIZE];
> char vg_id[GRUB_LVM_ID_STRLEN+1];
> char pv_id[GRUB_LVM_ID_STRLEN+1];
> + char buf[GRUB_LVM_LABEL_SIZE];
> char *metadatabuf, *p, *q, *vgname;
> - struct grub_lvm_label_header *lh = (struct grub_lvm_label_header *) buf;
> struct grub_lvm_pv_header *pvh;
> struct grub_lvm_disk_locn *dlocn;
> struct grub_lvm_mda_header *mdah;
> @@ -115,30 +146,9 @@
> struct grub_diskfilter_vg *vg;
> struct grub_diskfilter_pv *pv;
>
> - /* Search for label. */
> - for (i = 0; i < GRUB_LVM_LABEL_SCAN_SECTORS; i++)
> - {
> - err = grub_disk_read (disk, i, 0, sizeof(buf), buf);
> - if (err)
> - goto fail;
> -
> - if ((! grub_strncmp ((char *)lh->id, GRUB_LVM_LABEL_ID,
> - sizeof (lh->id)))
> - && (! grub_strncmp ((char *)lh->type, GRUB_LVM_LVM2_LABEL,
> - sizeof (lh->type))))
> - break;
> - }
> -
> - /* Return if we didn't find a label. */
> - if (i == GRUB_LVM_LABEL_SCAN_SECTORS)
> - {
> -#ifdef GRUB_UTIL
> - grub_util_info ("no LVM signature found");
> -#endif
> - goto fail;
> - }
> -
> - pvh = (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
> + pvh = grub_lvm_get_pvh(disk, buf);
> + if (! pvh)
> + goto fail;
>
> for (i = 0, j = 0; i < GRUB_LVM_ID_LEN; i++)
> {
> @@ -151,7 +161,7 @@
> dlocn = pvh->disk_areas_xl;
>
> dlocn++;
> - /* Is it possible to have multiple data/metadata areas? I haven't
> + /* Is it possible to have multiple data areas? I haven't
> seen devices that have it. */
> if (dlocn->offset)
> {
> @@ -746,6 +756,88 @@
> return NULL;
> }
>
> +#ifdef GRUB_UTIL
> +int
> +grub_util_is_lvm(grub_disk_t disk)
> +{
> + struct grub_diskfilter_pv_id id;
> + struct grub_diskfilter_vg *vg;
> + grub_disk_addr_t start_sector;
> + vg = grub_lvm_detect(disk, &id, &start_sector);
> + if (! vg)
> + return 0;
> + /* don't free the vg, it's held by grub_diskfilter_vg_register */
> + grub_free(id.uuid);
> + return 1;
> +}
> +
> +grub_err_t
> +grub_util_lvm_embed (struct grub_disk *disk, unsigned int *nsectors,
> + unsigned int max_nsectors,
> + grub_embed_type_t embed_type,
> + grub_disk_addr_t **sectors)
> +{
> + char buf[GRUB_LVM_LABEL_SIZE];
> + struct grub_lvm_pv_header *pvh;
> + struct grub_lvm_pv_header_ext *pvh_ext;
> + struct grub_diskfilter_pv *pv = NULL;
> + struct grub_diskfilter_vg *vg = NULL;
> + struct grub_lvm_disk_locn *dlocn;
> + grub_uint64_t ba_offset, ba_size, ba_start_sector;
> + unsigned int i;
> +
> + if (embed_type != GRUB_EMBED_PCBIOS)
> + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
> + "LVM curently supports only PC-BIOS embedding");
> + if (disk->partition)
> + return grub_error (GRUB_ERR_BUG, "disk isn't LVM");
> + pv = grub_diskfilter_get_pv_from_disk (disk, &vg);
> + if (! pv)
> + return grub_error (GRUB_ERR_BUG, "disk isn't LVM");
> +
> + pvh = grub_lvm_get_pvh(disk, buf);
> + if (! pvh)
> + return grub_error (GRUB_ERR_BUG, "disk isn't LVM");
> +
> + dlocn = pvh->disk_areas_xl;
> +
> + /* skip past the data area list */
> + while (dlocn->offset)
> + dlocn++;
> + dlocn++;
> + /* and the metadata area list */
> + while (dlocn->offset)
> + dlocn++;
> + dlocn++;
> +
> + pvh_ext = (struct grub_lvm_pv_header_ext*)dlocn;
> + if (! pvh_ext->version_xl)
> + return grub_error (GRUB_ERR_BUG, "LVM PV doesn't have a bootloader area");
> +
> + dlocn = pvh_ext->disk_areas_xl;
> + ba_offset = grub_le_to_cpu64 (dlocn->offset);
> + ba_size = grub_le_to_cpu64 (dlocn->size);
> + if (! (ba_offset && ba_size))
> + return grub_error (GRUB_ERR_BUG, "LVM PV doesn't have a bootloader area");
> + /* could be worked around with extra arithmetic if this actually happens */
> + if (ba_offset % GRUB_DISK_SECTOR_SIZE)
> + return grub_error (
> + GRUB_ERR_BUG, "LVM bootloader area is improperly aligned");
> + ba_start_sector = ba_offset / GRUB_DISK_SECTOR_SIZE;
> +
> + *nsectors = ba_size / GRUB_DISK_SECTOR_SIZE;
> + if (*nsectors > max_nsectors)
> + *nsectors = max_nsectors;
> +
> + *sectors = grub_malloc (*nsectors * sizeof (**sectors));
> + if (!*sectors)
> + return grub_errno;
> + for (i = 0; i < *nsectors; i++)
> + (*sectors)[i] = ba_start_sector + i;
> +
> + return GRUB_ERR_NONE;
> +}
> +#endif
> \f
>
> static struct grub_diskfilter grub_lvm_dev = {
>
> === modified file 'include/grub/diskfilter.h'
> --- include/grub/diskfilter.h 2012-06-25 15:36:50 +0000
> +++ include/grub/diskfilter.h 2013-09-25 08:59:05 +0000
> @@ -75,6 +75,9 @@
> #ifdef GRUB_UTIL
> char **partmaps;
> #endif
> + /* Optional bootloader embedding area */
> + grub_uint64_t ba_offset;
> + grub_uint64_t ba_size;
> };
>
> struct grub_diskfilter_lv {
>
> === modified file 'include/grub/emu/hostdisk.h'
> --- include/grub/emu/hostdisk.h 2013-08-22 14:50:12 +0000
> +++ include/grub/emu/hostdisk.h 2013-09-25 07:59:06 +0000
> @@ -44,9 +44,16 @@
> char *
> grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
> int
> +grub_util_is_lvm (grub_disk_t disk);
> +int
> grub_util_is_ldm (grub_disk_t disk);
> #ifdef GRUB_UTIL
> grub_err_t
> +grub_util_lvm_embed (struct grub_disk *disk, unsigned int *nsectors,
> + unsigned int max_nsectors,
> + grub_embed_type_t embed_type,
> + grub_disk_addr_t **sectors);
> +grub_err_t
> grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
> unsigned int max_nsectors,
> grub_embed_type_t embed_type,
>
> === modified file 'include/grub/lvm.h'
> --- include/grub/lvm.h 2012-01-29 13:28:01 +0000
> +++ include/grub/lvm.h 2013-09-25 08:32:31 +0000
> @@ -62,6 +62,13 @@
> struct grub_lvm_disk_locn disk_areas_xl[0]; /* Two lists */
> } __attribute__ ((packed));
>
> +struct grub_lvm_pv_header_ext {
> + grub_uint32_t version_xl;
> + grub_uint32_t flags_xl;
> + /* NULL-terminated list of bootloader embedding areas */
> + struct grub_lvm_disk_locn disk_areas_xl[0];
> +} __attribute__ ((packed));
> +
> #define GRUB_LVM_FMTT_MAGIC "\040\114\126\115\062\040\170\133\065\101\045\162\060\116\052\076"
> #define GRUB_LVM_FMTT_VERSION 1
> #define GRUB_LVM_MDA_HEADER_SIZE 512
>
> === modified file 'util/grub-setup.c'
> --- util/grub-setup.c 2013-04-04 06:55:06 +0000
> +++ util/grub-setup.c 2013-09-25 11:31:47 +0000
> @@ -387,7 +387,7 @@
> .container = dest_dev->disk->partition,
> .multiple_partmaps = 0
> };
> - int is_ldm;
> + int is_ldm, is_lvm;
> grub_err_t err;
> grub_disk_addr_t *sectors;
> int i;
> @@ -411,8 +411,9 @@
> grub_errno = GRUB_ERR_NONE;
>
> is_ldm = grub_util_is_ldm (dest_dev->disk);
> + is_lvm = grub_util_is_lvm (dest_dev->disk);
>
> - if (fs_probe)
> + if (!is_lvm && fs_probe)
> {
> if (!fs && !ctx.dest_partmap)
> grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
> @@ -459,7 +460,7 @@
>
> free (tmp_img);
>
> - if (! ctx.dest_partmap && ! fs && !is_ldm)
> + if (! ctx.dest_partmap && ! fs && !is_ldm && !is_lvm)
> {
> grub_util_warn ("%s", _("Attempting to install GRUB to a partitionless disk or to a partition. This is a BAD idea."));
> goto unable_to_embed;
> @@ -492,7 +493,10 @@
> maxsec = ((0x78000 - GRUB_KERNEL_I386_PC_LINK_ADDR)
> >> GRUB_DISK_SECTOR_BITS);
>
> - if (is_ldm)
> + if (is_lvm)
> + err = grub_util_lvm_embed (dest_dev->disk, &nsec, maxsec,
> + GRUB_EMBED_PCBIOS, §ors);
> + else if (is_ldm)
> err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
> GRUB_EMBED_PCBIOS, §ors);
> else if (ctx.dest_partmap)
> @@ -588,7 +592,7 @@
>
> if (dest_dev->disk->dev->id != root_dev->disk->dev->id)
> grub_util_error ("%s", _("embedding is not possible, but this is required for "
> - "RAID and LVM install"));
> + "RAID install"));
>
> {
> grub_fs_t fs;
>
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> https://lists.gnu.org/mailman/listinfo/grub-devel
>
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 291 bytes --]
next prev parent reply other threads:[~2013-09-26 8:53 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-09-25 12:39 [PATCH] Install to LVM PVs Gabriel de Perthuis
2013-09-26 8:53 ` Vladimir 'φ-coder/phcoder' Serbinenko [this message]
2013-09-27 10:39 ` Gabriel de Perthuis
2013-09-27 12:48 ` Vladimir 'φ-coder/phcoder' Serbinenko
2013-09-27 13:56 ` Gabriel de Perthuis
2013-09-27 14:27 ` Andrey Borzenkov
2015-02-15 10:47 ` Andrei Borzenkov
-- strict thread matches above, loose matches on Subject: below --
2016-05-08 4:53 Dryden Personalis
2016-05-08 6:05 ` Andrei Borzenkov
2016-05-08 8:47 ` Andrei Borzenkov
2016-05-08 13:10 ` Dryden Personalis
2016-05-08 17:16 ` Dryden Personalis
2016-05-08 17:40 ` Dryden Personalis
2016-05-08 13:01 ` Dryden Personalis
2016-05-09 6:07 ` Andrei Borzenkov
2016-05-09 8:41 ` Dryden Personalis
2016-05-09 16:10 ` Dryden Personalis
2016-05-09 16:18 ` Dryden Personalis
2016-05-09 17:56 ` Dryden Personalis
2016-05-17 18:01 ` Dryden Personalis
2016-05-08 9:23 ` Andrei Borzenkov
2016-05-08 13:09 ` Dryden Personalis
2016-05-09 0:10 ` Xen
2016-05-09 0:10 ` Dryden Personalis
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=5243F5FF.4000804@gmail.com \
--to=phcoder@gmail.com \
--cc=grub-devel@gnu.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 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).