Attached my current working patch.
Also attached some housekeeping.
Not sure if it applies to current git version.
Take from it what you like.
diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
index 22c7b64..37e715a 100644
--- a/grub-core/disk/lvm.c
+++ b/grub-core/disk/lvm.c
@@ -95,6 +95,78 @@ grub_lvm_check_flag (char *p, const char *str, const char *flag)
}
}
+/**
+ * Attribute function obtaining PV header from disk. Currently scans the
+ * first 4 sectors and returns anything found in either of those sectors.
+ *
+ * Sets *first_sector to 1 if header was in first sector, 0 otherwise.
+ * May print first_sector info message if verbose was set.
+ *
+ * Returns header if found, NULL otherwise. Also returns header if first_sector.
+ */
+static struct grub_lvm_pv_header *
+grub_lvm_get_pvh_at(grub_disk_t disk, char buf[static GRUB_LVM_LABEL_SIZE],
+#ifdef GRUB_UTIL
+ int *first_sector, int verbose
+#else
+ int *first_sector
+#endif
+ )
+
+{
+ 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;
+ }
+
+#ifdef GRUB_UTIL
+ if (first_sector) *first_sector = 0;
+#endif
+
+ /* 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;
+ }
+ else if (i == 0)
+ {
+#ifdef GRUB_UTIL
+ if (verbose) grub_util_info ("LVM signature in first sector");
+#endif
+ if (first_sector) *first_sector = 1;
+ }
+
+ return (struct grub_lvm_pv_header *) (buf + grub_le_to_cpu32(lh->offset_xl));
+}
+
+static inline struct grub_lvm_pv_header *grub_lvm_get_pvh(grub_disk_t disk, char buf[static GRUB_LVM_LABEL_SIZE])
+{
+#ifdef GRUB_UTIL
+ return grub_lvm_get_pvh_at(disk, buf, NULL, 0);
+#else
+ return grub_lvm_get_pvh_at(disk, buf, NULL);
+#endif
+}
+
+/**
+ * Preexisting function that detects the LVM PV header from disk and proceeds
+ * to fill in VG datastructures. Called from diskfilter as part of the
+ * "driver->detect" functionality.
+ */
static struct grub_diskfilter_vg *
grub_lvm_detect (grub_disk_t disk,
struct grub_diskfilter_pv_id *id,
@@ -106,7 +178,6 @@ grub_lvm_detect (grub_disk_t disk,
char vg_id[GRUB_LVM_ID_STRLEN+1];
char pv_id[GRUB_LVM_ID_STRLEN+1];
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;
@@ -116,30 +187,9 @@ grub_lvm_detect (grub_disk_t disk,
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++)
{
@@ -770,6 +820,112 @@ grub_lvm_detect (grub_disk_t disk,
return NULL;
}
+#ifdef GRUB_UTIL
+/**
+ * Requests physical volume from disk and checks whether relations hold up?
+ *
+ * This function only returns true iff a volume group was found
+ */
+int grub_util_has_lvm_vg (grub_disk_t disk)
+{
+ struct grub_diskfilter_pv *pv = NULL;
+ struct grub_diskfilter_vg *vg = NULL;
+
+ pv = grub_diskfilter_get_pv_from_disk(disk, &vg);
+ return pv && vg && vg == vg->driver->detect(disk, &pv->id, &pv->start_sector)
+ ? 1 : 0;
+}
+
+/**
+ * Does nothing other than scanning the first 4 sectors of the device for
+ * a LVM PV header
+ */
+int grub_util_is_lvm (grub_disk_t disk)
+{
+ char buf[GRUB_LVM_LABEL_SIZE];
+ return grub_lvm_get_pvh(disk, buf) ? 1 : 0;
+}
+
+/**
+ * This function embeds the bootloader inside an LVM PV bootloaderarea
+ * specified by --bootloaderareasize on the pvcreate command line.
+ *
+ * It is called from setup.c and returns an error message to the caller,
+ * that gets treated as a warning, if it fails.
+*/
+
+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_vg *vg = NULL;
+ struct grub_lvm_disk_locn *dlocn;
+ grub_uint64_t ba_offset, ba_size, ba_start_sector;
+ unsigned int i;
+ int first_sector;
+
+ if (embed_type != GRUB_EMBED_PCBIOS)
+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
+ "LVM curently supports only PC-BIOS embedding");
+#ifdef GRUB_UTIL
+ pvh = grub_lvm_get_pvh_at(disk, buf, &first_sector, 1);
+#else
+ pvh = grub_lvm_get_pvh_at(disk, buf, &first_sector);
+#endif
+ /* if pvh is NULL, we probably have a bug */
+ if (!pvh)
+ return grub_error (GRUB_ERR_BUG, "trying to install on non-existing PV header, but should already have been prevented by initial screening");
+
+ if (first_sector)
+ return grub_error (GRUB_ERR_BAD_DEVICE, "PV detected inside boot sector, but we need the boot sector to install in");
+
+ /* for some reason the bootloaderarea check will fail if we don't do this here */
+ grub_diskfilter_get_pv_from_disk(disk, &vg);
+
+ 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_BAD_DEVICE, "trying to install on LVM PV but it does not have a bootloader area to embed in. Check pvcreate --bootloaderareasize");
+
+ 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_BAD_DEVICE, "trying to install on LVM PV but it does not have a bootloader area to embed in. Check pvcreate --bootloaderareasize");
+ /* could be worked around with extra arithmetic if this actually happens */
+ if (ba_offset % GRUB_DISK_SECTOR_SIZE)
+ return grub_error (
+ GRUB_ERR_BAD_DEVICE, "LVM bootloader area is not aligned on sector boundaries (%d)", GRUB_DISK_SECTOR_SIZE);
+ 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 = {
diff --git a/include/grub/diskfilter.h b/include/grub/diskfilter.h
index 1aedcd3..ca95dea 100644
--- a/include/grub/diskfilter.h
+++ b/include/grub/diskfilter.h
@@ -75,6 +75,9 @@ struct grub_diskfilter_pv {
#ifdef GRUB_UTIL
char **partmaps;
#endif
+ /* Optional bootloader embedding area */
+ grub_uint64_t ba_offset;
+ grub_uint64_t ba_size;
};
struct grub_diskfilter_lv {
diff --git a/include/grub/emu/hostdisk.h b/include/grub/emu/hostdisk.h
index e233d37..4e4ddea 100644
--- a/include/grub/emu/hostdisk.h
+++ b/include/grub/emu/hostdisk.h
@@ -44,6 +44,14 @@ char *grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
int grub_util_is_ldm (grub_disk_t disk);
#ifdef GRUB_UTIL
+int grub_util_is_lvm (grub_disk_t disk);
+int grub_util_has_lvm_vg (grub_disk_t disk);
+
+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,
diff --git a/include/grub/lvm.h b/include/grub/lvm.h
index 30a609c..dd19552 100644
--- a/include/grub/lvm.h
+++ b/include/grub/lvm.h
@@ -62,6 +62,13 @@ struct grub_lvm_pv_header {
struct grub_lvm_disk_locn disk_areas_xl[0]; /* Two lists */
} GRUB_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
diff --git a/util/setup.c b/util/setup.c
index 7c60083..34c7f80 100644
--- a/util/setup.c
+++ b/util/setup.c
@@ -390,7 +390,7 @@ SETUP (const char *dir,
.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,15 +423,17 @@ SETUP (const char *dir,
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 (!fs && !ctx.dest_partmap)
- grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"),
- dest_dev->disk->name);
- if (fs && !fs->reserved_first_sector)
- /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it. */
- grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
+ /* Doubt there can be any FS signature on LVM? */
+ if (!is_lvm && !fs && !ctx.dest_partmap)
+ grub_util_error (_("unable to identify a filesystem in %s; safety check can't be performed"), dest_dev->disk->name);
+
+ if (fs && !fs->reserved_first_sector)
+ /* TRANSLATORS: Filesystem may reserve the space just GRUB isn't sure about it. */
+ grub_util_error (_("%s appears to contain a %s filesystem which isn't known to "
"reserve space for DOS-style boot. Installing GRUB there could "
"result in FILESYSTEM DESTRUCTION if valuable data is overwritten "
"by grub-setup (--skip-fs-probe disables this "
@@ -462,12 +464,12 @@ SETUP (const char *dir,
}
- 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;
}
- if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))
+ if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || ((is_ldm || is_lvm) && fs))
{
grub_util_warn ("%s", _("Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet."));
goto unable_to_embed;
@@ -499,7 +501,10 @@ SETUP (const char *dir,
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 +607,7 @@ unable_to_embed:
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"));
+ "LVM and RAID install"));
{
grub_fs_t fs;
diff --git a/grub-core/disk/lvm.c b/grub-core/disk/lvm.c
index 483c17e..22c7b64 100644
--- a/grub-core/disk/lvm.c
+++ b/grub-core/disk/lvm.c
@@ -160,7 +160,7 @@ grub_lvm_detect (grub_disk_t disk,
"we don't support multiple LVM data areas");
#ifdef GRUB_UTIL
- grub_util_info ("we don't support multiple LVM data areas\n");
+ grub_util_info ("we don't support multiple LVM data areas");
#endif
goto fail;
}
@@ -189,7 +189,7 @@ grub_lvm_detect (grub_disk_t disk,
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"unknown LVM metadata header");
#ifdef GRUB_UTIL
- grub_util_info ("unknown LVM metadata header\n");
+ grub_util_info ("unknown LVM metadata header");
#endif
goto fail2;
}
@@ -213,7 +213,7 @@ grub_lvm_detect (grub_disk_t disk,
if (q == metadatabuf + mda_size)
{
#ifdef GRUB_UTIL
- grub_util_info ("error parsing metadata\n");
+ grub_util_info ("error parsing metadata");
#endif
goto fail2;
}
@@ -230,7 +230,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("couldn't find ID\n");
+ grub_util_info ("couldn't find ID");
#endif
goto fail3;
}
@@ -258,7 +258,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown extent size\n");
+ grub_util_info ("unknown extent size");
#endif
goto fail4;
}
@@ -306,7 +306,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown pe_start\n");
+ grub_util_info ("unknown pe_start");
#endif
goto pvs_fail;
}
@@ -315,7 +315,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("error parsing pe_start\n");
+ grub_util_info ("error parsing pe_start");
#endif
goto pvs_fail;
}
@@ -402,7 +402,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("couldn't find ID\n");
+ grub_util_info ("couldn't find ID");
#endif
goto lvs_fail;
}
@@ -422,7 +422,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown segment_count\n");
+ grub_util_info ("unknown segment_count");
#endif
goto lvs_fail;
}
@@ -436,7 +436,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown segment\n");
+ grub_util_info ("unknown segment");
#endif
goto lvs_segment_fail;
}
@@ -445,7 +445,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown start_extent\n");
+ grub_util_info ("unknown start_extent");
#endif
goto lvs_segment_fail;
}
@@ -453,7 +453,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown extent_count\n");
+ grub_util_info ("unknown extent_count");
#endif
goto lvs_segment_fail;
}
@@ -475,7 +475,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown stripe_count\n");
+ grub_util_info ("unknown stripe_count");
#endif
goto lvs_segment_fail;
}
@@ -491,7 +491,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown stripes\n");
+ grub_util_info ("unknown stripes");
#endif
goto lvs_segment_fail2;
}
@@ -533,7 +533,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown mirror_count\n");
+ grub_util_info ("unknown mirror_count");
#endif
goto lvs_segment_fail;
}
@@ -545,7 +545,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown mirrors\n");
+ grub_util_info ("unknown mirrors");
#endif
goto lvs_segment_fail2;
}
@@ -603,7 +603,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown device_count\n");
+ grub_util_info ("unknown device_count");
#endif
goto lvs_segment_fail;
}
@@ -612,7 +612,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown stripe_size\n");
+ grub_util_info ("unknown stripe_size");
#endif
goto lvs_segment_fail;
}
@@ -625,7 +625,7 @@ grub_lvm_detect (grub_disk_t disk,
if (p == NULL)
{
#ifdef GRUB_UTIL
- grub_util_info ("unknown mirrors\n");
+ grub_util_info ("unknown mirrors");
#endif
goto lvs_segment_fail2;
}
@@ -672,7 +672,7 @@ grub_lvm_detect (grub_disk_t disk,
p2 = grub_strchr (p, '"');
if (p2)
*p2 = 0;
- grub_util_info ("unknown LVM type %s\n", p);
+ grub_util_info ("unknown LVM type %s", p);
if (p2)
*p2 ='"';
#endif
diff --git a/include/grub/emu/hostdisk.h b/include/grub/emu/hostdisk.h
index e006f0b..e233d37 100644
--- a/include/grub/emu/hostdisk.h
+++ b/include/grub/emu/hostdisk.h
@@ -26,8 +26,8 @@
#include <grub/emu/hostfile.h>
grub_util_fd_t
-grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
- grub_disk_addr_t *max);
+grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector,
+ int flags, grub_disk_addr_t *max);
void grub_util_biosdisk_init (const char *dev_map);
void grub_util_biosdisk_fini (void);
@@ -35,17 +35,14 @@ char *grub_util_biosdisk_get_grub_dev (const char *os_dev);
const char *grub_util_biosdisk_get_osdev (grub_disk_t disk);
int grub_util_biosdisk_is_present (const char *name);
int grub_util_biosdisk_is_floppy (grub_disk_t disk);
-const char *
-grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk);
+const char *grub_util_biosdisk_get_compatibility_hint (grub_disk_t disk);
grub_err_t grub_util_biosdisk_flush (struct grub_disk *disk);
grub_err_t
grub_cryptodisk_cheat_mount (const char *sourcedev, const char *cheat);
-const char *
-grub_util_cryptodisk_get_uuid (grub_disk_t disk);
-char *
-grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
-int
-grub_util_is_ldm (grub_disk_t disk);
+const char *grub_util_cryptodisk_get_uuid (grub_disk_t disk);
+char *grub_util_get_ldm (grub_disk_t disk, grub_disk_addr_t start);
+int grub_util_is_ldm (grub_disk_t disk);
+
#ifdef GRUB_UTIL
grub_err_t
grub_util_ldm_embed (struct grub_disk *disk, unsigned int *nsectors,
diff --git a/util/setup.c b/util/setup.c
index 3945eff..7c60083 100644
--- a/util/setup.c
+++ b/util/setup.c
@@ -1,4 +1,4 @@
-/* grub-setup.c - make GRUB usable */
+/* setup.c - make GRUB usable */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel