Hi again.
(My developer nick, same address for now).
I've updated the patch from 2013 that enabled Grub to be installable on
a PV using the --bootloaderareasize flag to pvcreate. I have not used
Grub git, but enabled it at least on the source that comes with latest
Ubuntu.
Which is 2.02 beta 2.
Link to post on grub-devel:
https://lists.gnu.org/archive/html/grub-devel/2016-05/msg00010.html
Original patch:
https://lists.gnu.org/archive/html/grub-devel/2013-09/msg00113.html
I will attach the patch here as well for convenience, if you care.
Regards.
D.
=== 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
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/setup.c'
--- util/setup.c 2016-05-08 01:00:00.000000000 +0200
+++ util/setup.c 2016-05-08 02:00:00.000000000 +0200
@@ -390,7 +390,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;
@@ -423,8 +423,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"),
@@ -462,7 +463,7 @@
}
- 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;
@@ -499,7 +500,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)
@@ -602,7 +606,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;
_______________________________________________
linux-lvm mailing list
linux-lvm@redhat.com
https://www.redhat.com/mailman/listinfo/linux-lvm
read the LVM HOW-TO at http://tldp.org/HOWTO/LVM-HOWTO/