* [PATCH] Install to LVM PVs @ 2016-05-08 4:53 Dryden Personalis 2016-05-08 6:05 ` Andrei Borzenkov 2016-05-08 9:23 ` Andrei Borzenkov 0 siblings, 2 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-08 4:53 UTC (permalink / raw) To: grub-devel [-- Attachment #1: Type: text/plain, Size: 1402 bytes --] I updated this guy's patch to work with 2.02 beta 2, at least. I've just worked on the version that gets downloaded and unpacked on Kubuntu / Ubuntu 16.04. One part of the patch didn't apply because apparently some tabs have entered a file, namely grub-core/disk/lvm.c. Another part didn't apply because code had been refactored from grub-setup.c to setup.c. I've only compiled with these extra packages: - bison - flex - libdevmapper-dev and automake was also required. I've had to symlink the 1.15 executables to 1.14. I'm not sure why the patch never made it into mainline grub, but back then (2013) the argument was that it was doing something to an area that was not meant for that. However LVM contains the --bootloaderareasize flag that seems to be meant for this, and if you put it to 2048 sectors (or 1M) it ought to work cq. just works. ie. pvcreate --bootloaderareasize 2048s /dev/sda, followed by, grub-install /dev/sda, will just work and result in a bootable system from that harddisk. I don't know if I can attach here, and I don't know what will happen with tabs if I inline it. So I will attach first. Regards. ps. I did not test booting from the harddisk to a system on the harddisk, but it boots a system on another device just fine, so I see no reason why it wouldn't work. reference: https://lists.gnu.org/archive/html/grub-devel/2013-09/msg00113.html [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: grub-install-to-partitionless-lvm-pv_2.02~beta2.patch --] [-- Type: text/x-diff; name=grub-install-to-partitionless-lvm-pv_2.02~beta2.patch, Size: 8957 bytes --] === 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/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; ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 4:53 [PATCH] Install to LVM PVs Dryden Personalis @ 2016-05-08 6:05 ` Andrei Borzenkov 2016-05-08 8:47 ` Andrei Borzenkov 2016-05-08 13:01 ` Dryden Personalis 2016-05-08 9:23 ` Andrei Borzenkov 1 sibling, 2 replies; 24+ messages in thread From: Andrei Borzenkov @ 2016-05-08 6:05 UTC (permalink / raw) To: The development of GNU GRUB 08.05.2016 07:53, Dryden Personalis пишет: > I updated this guy's patch to work with 2.02 beta 2, at least. > > I've just worked on the version that gets downloaded and unpacked on > Kubuntu / Ubuntu 16.04. > > One part of the patch didn't apply because apparently some tabs have > entered a file, namely grub-core/disk/lvm.c. > > Another part didn't apply because code had been refactored from > grub-setup.c to setup.c. > > I've only compiled with these extra packages: > > - bison > - flex > - libdevmapper-dev > > and automake was also required. I've had to symlink the 1.15 executables > to 1.14. > > Did you actually test it by installing GRUB on PV? Does it boot? Did you test it both with unpartitioned disk and PV in partition? > I'm not sure why the patch never made it into mainline grub, but back > then (2013) the argument was that it was doing something to an area that > was not meant for that. > Neither am I :) I understand that Vladimir had plans to stuff more information in this area (personally I'd like to use it for environment block as example) but just guessing. In any case, we really always can cut off part of this area by artificially reducing size. > However LVM contains the --bootloaderareasize flag that seems to be > meant for this, and if you put it to 2048 sectors (or 1M) it ought to > work cq. just works. > > ie. pvcreate --bootloaderareasize 2048s /dev/sda, followed by, > grub-install /dev/sda, will just work and result in a bootable system > from that harddisk. > > I don't know if I can attach here, and I don't know what will happen > with tabs if I inline it. > > So I will attach first. > That's fine. > Regards. > > > ps. I did not test booting from the harddisk to a system on the > harddisk, but it boots a system on another device just fine, so I see no > reason why it wouldn't work. > > reference: > https://lists.gnu.org/archive/html/grub-devel/2013-09/msg00113.html > > === 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]; Why reordering buf definition? > 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 Could you explain why you deleted "metadata"? > 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; > +} > + This has side effect of adding duplicate VG definitions; this may later confuse grub. What about just checking array->driver for LVM? Go through registered arrays, find disk match and check array driver. See scan_disk_partition_iter () for example. > +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"); Why? What's wrong with PV on partition? > + 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"); > + Please, more specific error message, so they are actually useful to identify what happened. None of those is bug; this should probably be GRUB_ERR_BAD_DEVICE. > + 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"); > + Again, this is not a bug. > + 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"); And this. > + /* 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) No, we want to probe for FS here to eliminate corner case of both PV and FS metadata. > { > 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; And you need to add check for LVM here if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && 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 +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; ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 13:01 ` Dryden Personalis 1 sibling, 2 replies; 24+ messages in thread From: Andrei Borzenkov @ 2016-05-08 8:47 UTC (permalink / raw) To: The development of GNU GRUB 08.05.2016 09:05, Andrei Borzenkov пишет: >> >> +#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; >> +} >> + > > This has side effect of adding duplicate VG definitions; this may later > confuse grub. What about just checking array->driver for LVM? Go through > registered arrays, find disk match and check array driver. See > scan_disk_partition_iter () for example. > Which is basically call grub_diskfilter_get_pv_from_disk() and check vg_out->driver. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 8:47 ` Andrei Borzenkov @ 2016-05-08 13:10 ` Dryden Personalis 2016-05-08 17:16 ` Dryden Personalis 1 sibling, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-08 13:10 UTC (permalink / raw) To: The development of GNU GRUB Andrei Borzenkov schreef op 08-05-2016 10:47: > 08.05.2016 09:05, Andrei Borzenkov пишет: >>> >>> +#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; >>> +} >>> + >> >> This has side effect of adding duplicate VG definitions; this may >> later >> confuse grub. What about just checking array->driver for LVM? Go >> through >> registered arrays, find disk match and check array driver. See >> scan_disk_partition_iter () for example. >> > > Which is basically call grub_diskfilter_get_pv_from_disk() and check > vg_out->driver. Roger. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 1 sibling, 1 reply; 24+ messages in thread From: Dryden Personalis @ 2016-05-08 17:16 UTC (permalink / raw) To: The development of GNU GRUB Andrei Borzenkov schreef op 08-05-2016 10:47: > 08.05.2016 09:05, Andrei Borzenkov пишет: >>> >>> +#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; >>> +} >>> + >> >> This has side effect of adding duplicate VG definitions; this may >> later >> confuse grub. What about just checking array->driver for LVM? Go >> through >> registered arrays, find disk match and check array driver. See >> scan_disk_partition_iter () for example. >> > > Which is basically call grub_diskfilter_get_pv_from_disk() and check > vg_out->driver. This method also has the downside that is_lvm will fail without any indication as to why, when no volume group has been created. lvm_detect will return null because it can only return a VG. And, you cannot error out on that if a non-existing LVM should be okay. So this call to lvm_detect is pretty annoying. If it had more info, I could at least give an error in setup.c. I am not sure whether installation is *possible* without a VG but it would be odd if it couldn't? Anyway I would like a better error message on this because I just wasted 2 hours trying to get GRUB_UTIL to work and failing. That means as per your method I can probably distinguish between PV present and VG present (or not present). Then the only way I know how to report back is to give more values to is_lvm, but do we need a VG? Why error out on no VG? I will test. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 17:16 ` Dryden Personalis @ 2016-05-08 17:40 ` Dryden Personalis 0 siblings, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-08 17:40 UTC (permalink / raw) To: The development of GNU GRUB Dryden Personalis schreef op 08-05-2016 19:16: > I just wasted 2 hours trying to get GRUB_UTIL to work and failing. I am just not always that brilliant. Why on earth is that flag in there? If you enable it, stuff won't compile anymore. And I merely needed to turn on verbose output for grub-install :p. Not that it would have helped much, but at least troubleshooting would have been faster. Omg. I blame the heat. Trying to get a system working that already works just fine. :( :P. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 6:05 ` Andrei Borzenkov 2016-05-08 8:47 ` Andrei Borzenkov @ 2016-05-08 13:01 ` Dryden Personalis 2016-05-09 6:07 ` Andrei Borzenkov 1 sibling, 1 reply; 24+ messages in thread From: Dryden Personalis @ 2016-05-08 13:01 UTC (permalink / raw) To: The development of GNU GRUB Andrei Borzenkov schreef op 08-05-2016 8:05: > Did you actually test it by installing GRUB on PV? Does it boot? Did > you > test it both with unpartitioned disk and PV in partition? Hi Andrei, I must say I have for the most part just copied the patch as it was, and just tried to fix it so that the patch would actually apply in full. I have no experience yet with Grub code, so I may not be able to answer any or all of your questions. I must say that I did try the former, but not the latter yet. My system is not installed though so I can try at any point. What I haven't tried yet is booting FROM the PV in the sense of loading a system from it (and not just the boot loader) so at this point I have only booted a different system from the boot loader on my /dev/sda residing in a partitionless PV. Testing a PV with partitions is trivial, I will do that shortly. I plan on readily installing a system on that disk after I have my scheme sorted out, so then I can test for real the real use case (but only in the case of partitionless). > Neither am I :) I understand that Vladimir had plans to stuff more > information in this area (personally I'd like to use it for environment > block as example) but just guessing. In any case, we really always can > cut off part of this area by artificially reducing size. >> === 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 >> @@ -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]; > > Why reordering buf definition? That was just in the original patch. You can see the dates. I put some artificial times on the latest hunk, from yesterday. I didn't do anything really to the hunks from 2012/2013. So I don't know the rationale, we'd have to ask the original author, it probably makes no sense from my POV, but it does seem nicer lol. >> - /* Is it possible to have multiple data/metadata areas? I haven't >> + /* Is it possible to have multiple data areas? I haven't > > Could you explain why you deleted "metadata"? I don't know but I think the guy wanted to simplify by only having one block? Or something of the kind? > >> 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; >> +} >> + > > This has side effect of adding duplicate VG definitions; this may later > confuse grub. What about just checking array->driver for LVM? Go > through > registered arrays, find disk match and check array driver. See > scan_disk_partition_iter () for example. Alright this is beyond me at this point, I'd prefer if you gave feedback on the other items first. But do you mean not to use grub_lvm_detect? Are you saying that "array->driver" would already be loaded before we do grub_lvm_detect? (Or rather, before grub_util_is_lvm)? You are meaning to imply to just use a different identification measure right, because apparently grub_lvm_detect has already been done in that case. >> +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"); > > Why? What's wrong with PV on partition? Just for my recollection: * The function "grub_util_info" now calls "grub_util_is_lvm" * grub_util_is_lvm only scans the first 4 sectors of a disk, so it will not find anything on a partitioned /dev/sda * The above function grub_util_lvm_embed is only called when it does return true. * If you don't have a VG in the PV, the error never gets triggered. I don't know, the guy designed the feature for partitionless. Does it make sense to use if you don't have partitions? If it is all equivalent to Grub, I don't see why it shouldn't be possible. It means you'd want to embed grub in a partition that has a PV. Don't see why it shouldn't be possible. I can remove it but I will have to find out how to boot from an actual partition to test it :p. Maybe easiest is to clear the MBR and set bootable flag? Don't know if that works for grub. If default msdos label has such code.... >> + 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"); >> + > > Please, more specific error message, so they are actually useful to > identify what happened. Yes, can do. If I understand get_pvh, but that shouldn't be hard. > None of those is bug; this should probably be GRUB_ERR_BAD_DEVICE. Aye, it even reports as a warning while being fatal. Can do. >> + return grub_error (GRUB_ERR_BUG, "LVM PV doesn't have a >> bootloader area"); >> + > > Again, this is not a bug. Roger. Will find some other error if I can. >> - if (fs_probe) >> + if (!is_lvm && fs_probe) > > No, we want to probe for FS here to eliminate corner case of both PV > and > FS metadata. You mean you want to change it to: ...something that gives a different error as in: if (fs_probe) { if (is_lvm && fs ) { grub_util_error (_("a filesystem signature is present on %s, but embedding in an LVM PV was requested"), dest_dev->disk->name); } else 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); } <therest> } That is just my coding style, I understand yours. >> - 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; > > And you need to add check for LVM here > > if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && > fs)) I take it you mean: if (!is_lvm && (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs))) ? Or do you mean: if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm && fs) || is_lvm)) ? I take it the former: with is_lvm there should be no warning. I will work on the changes and post a new patch (not git format, but shouldn't matter). ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 13:01 ` Dryden Personalis @ 2016-05-09 6:07 ` Andrei Borzenkov 2016-05-09 8:41 ` Dryden Personalis ` (2 more replies) 0 siblings, 3 replies; 24+ messages in thread From: Andrei Borzenkov @ 2016-05-09 6:07 UTC (permalink / raw) To: The development of GNU GRUB 08.05.2016 16:01, Dryden Personalis пишет: > >>> - if (fs_probe) >>> + if (!is_lvm && fs_probe) >> >> No, we want to probe for FS here to eliminate corner case of both PV and >> FS metadata. > > You mean you want to change it to: > No, I do not want to change it at all. It should remain as is and always probe for FS so that test below actually works ... >> And you need to add check for LVM here >> >> if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm >> && fs)) > > I take it you mean: > > if (!is_lvm && (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || > (is_ldm && fs))) > I mean if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || ((is_ldm || is_lvm) && fs)) ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-09 6:07 ` Andrei Borzenkov @ 2016-05-09 8:41 ` Dryden Personalis 2016-05-09 16:10 ` Dryden Personalis 2016-05-17 18:01 ` Dryden Personalis 2 siblings, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-09 8:41 UTC (permalink / raw) To: The development of GNU GRUB Andrei Borzenkov schreef op 09-05-2016 8:07: > No, I do not want to change it at all. It should remain as is and > always > probe for FS so that test below actually works But its output makes no sense, there cannot be a filesystem in a PV. It could check for existence of VG AND LV AND filesystem but does it do that right now? Installing Grub is generally a non-destructive operation, apart from overwriting the boot sector. Anyway my foot is hurting and I can't sit behind the computer, I will just show the code at some point so to discuss that alright. >> I take it you mean: >> >> if (!is_lvm && (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || >> (is_ldm && fs))) >> > > I mean > > if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || ((is_ldm || > is_lvm) && fs)) Yes, I realized. Sorry. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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-17 18:01 ` Dryden Personalis 2 siblings, 1 reply; 24+ messages in thread From: Dryden Personalis @ 2016-05-09 16:10 UTC (permalink / raw) To: The development of GNU GRUB Currently: - still searches in first sector for label, and reports error if found there - get_pvh split into regular and one with 2 extra parameters for first_sector detection - some documentation - VG is not required to install - does not even check for VG, but function is retained - is lvm returns true iff header is found - currently still skips filesystem check for lvm. - untested installing on partitions - note: LVM does not support first sector PVs - we could also skip checking the first sector (my beautiful code) - in that case split get_pvh is (currently) not needed, but you would also not warn people about the bootsector. The header would just not be found. So in principle the solution becomes really simple (not requiring VG). You can however corrupt the thing by first installing a bootloaderareasize PV, then a regular one on top of that, and the code will mistakenly believe there is room. But this is all I can do without diving into the mechanics currently. This is the function I thought Andrei wanted: 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; } If you are okay, I will attach the patch, but I also did some cleanup in lvm.c particularly (removing extraneous \n for instance messing up info messages) but I need to separate that with Git. If you still feel VG should be required, let me know. But also whether filesystem check (without -s) should be required when none can ever be found (at least not in our case here). I have reverted to that of the patch (or similar): if (fs_probe) { 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); ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-09 16:10 ` Dryden Personalis @ 2016-05-09 16:18 ` Dryden Personalis 2016-05-09 17:56 ` Dryden Personalis 0 siblings, 1 reply; 24+ messages in thread From: Dryden Personalis @ 2016-05-09 16:18 UTC (permalink / raw) To: The development of GNU GRUB Dryden Personalis schreef op 09-05-2016 18:10: > I have reverted to that of the patch (or similar): > > if (fs_probe) > { > 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); In particular I feel !is_lvm and !ctx.dest_partmap are equivalent. Why, they both indicate partitions, instead of being a partition (with a filesystem). ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-09 16:18 ` Dryden Personalis @ 2016-05-09 17:56 ` Dryden Personalis 0 siblings, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-09 17:56 UTC (permalink / raw) To: The development of GNU GRUB [-- Attachment #1: Type: text/plain, Size: 145 bytes --] Attached my current working patch. Also attached some housekeeping. Not sure if it applies to current git version. Take from it what you like. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: grub-install-to-partitionless-lvm-pv_2.02~beta2_v3.patch --] [-- Type: text/x-diff; name=grub-install-to-partitionless-lvm-pv_2.02~beta2_v3.patch, Size: 12369 bytes --] 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 \f 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; [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #3: housekeeping.patch --] [-- Type: text/x-diff; name=housekeeping.patch, Size: 6968 bytes --] 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. ^ permalink raw reply related [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-09 6:07 ` Andrei Borzenkov 2016-05-09 8:41 ` Dryden Personalis 2016-05-09 16:10 ` Dryden Personalis @ 2016-05-17 18:01 ` Dryden Personalis 2 siblings, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-17 18:01 UTC (permalink / raw) To: The development of GNU GRUB Andrei Borzenkov schreef op 09-05-2016 8:07: I'm sorry, this email had gone missing from my system. I just found it back in the trash, after thinking I had already searched for it. I'm not sure why no one responds anymore, of course Andrei was the only one to respond in the first place. I hope nothing is the matter with Andrei himself, I mean it could be personal circumstances. I have basically implemented all suggestions, with just two questions that I would like to have answered: - is it okay to drop the requirement of having a VG configured in the PV - is it okay to skip the FS-presence test in a LVM that cannot have it in any case? If the group or the ones in charge of this software would be willing to shed their light on these issues, I could at least make something that you would agree with, if it would be intended for real submission. So from my perspective the feature works, I tend to think these are the only choices to make, and perhaps additional safety checks are required to deal with the size of the bootloaderarea, which I can look into if needed. Presently I do not have the knowledge about the PV structure yet. I did not write the original patch, after all. I could easily test or demonstrate what would happen if the bootloaderareasize were really small; whether grub would overwrite essential structures if I did. I think safety is the biggest requirement here? As demonstrated, booting itself is not an issue except that I cannot test installing on partitions (at all) currently. I do not know why, but Grub on my system will not install on any partition whatsoever, not the new version, or the standard ubuntu version. I have still not installed my system again on that harddisk, still working off of a USB stick. ;-). So I am actually waiting with installing until people have indicated whether additional development or testing is required? I would hope to work with you on this. (Not just grub, I'm also worried about LVM thin safety, but that is another issue). I'm sorry if I seem not to understand how things work around here, or if I actually do not (understand). I have tried to reach Andrei off-list, but no response. But I've waited for a week, so I need to go and start doing something else if it is not going to happen anyway. So please. And regards, and thanks for cooperating (thus far) and of having been of help, in any case, regardless. Regards. > 08.05.2016 16:01, Dryden Personalis пишет: >> >>>> - if (fs_probe) >>>> + if (!is_lvm && fs_probe) >>> >>> No, we want to probe for FS here to eliminate corner case of both PV >>> and >>> FS metadata. >> >> You mean you want to change it to: >> > > No, I do not want to change it at all. It should remain as is and > always > probe for FS so that test below actually works > ... >>> And you need to add check for LVM here >>> >>> if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || (is_ldm >>> && fs)) >> >> I take it you mean: >> >> if (!is_lvm && (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || >> (is_ldm && fs))) >> > > I mean > > if (ctx.multiple_partmaps || (ctx.dest_partmap && fs) || ((is_ldm || > is_lvm) && fs)) ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 4:53 [PATCH] Install to LVM PVs Dryden Personalis 2016-05-08 6:05 ` Andrei Borzenkov @ 2016-05-08 9:23 ` Andrei Borzenkov 2016-05-08 13:09 ` Dryden Personalis 2016-05-09 0:10 ` Xen 1 sibling, 2 replies; 24+ messages in thread From: Andrei Borzenkov @ 2016-05-08 9:23 UTC (permalink / raw) To: The development of GNU GRUB 08.05.2016 07:53, Dryden Personalis пишет: > + if (is_lvm) > + err = grub_util_lvm_embed (dest_dev->disk, &nsec, maxsec, > + GRUB_EMBED_PCBIOS, §ors); PV label may be in the first sector. In this case label will be overwritten later by boot image. This needs additional check. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-08 9:23 ` Andrei Borzenkov @ 2016-05-08 13:09 ` Dryden Personalis 2016-05-09 0:10 ` Xen 1 sibling, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-08 13:09 UTC (permalink / raw) To: The development of GNU GRUB; +Cc: Grub-devel Andrei Borzenkov schreef op 08-05-2016 11:23: > 08.05.2016 07:53, Dryden Personalis пишет: >> + if (is_lvm) >> + err = grub_util_lvm_embed (dest_dev->disk, &nsec, maxsec, >> + GRUB_EMBED_PCBIOS, §ors); > > PV label may be in the first sector. In this case label will be > overwritten later by boot image. This needs additional check. Is that only true for the first sector? I saw it checks the first 4. So I don't know what it does by default? pvcreate will not work on disks that have a partition, but they are okay with having a label but no partitions. the man page suggests wiping the first sector, but it says nothing about where it will install itself. You are suggesting to check whether PV header is in 1-3, and not proceed if it is in 0. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 1 sibling, 1 reply; 24+ messages in thread From: Xen @ 2016-05-09 0:10 UTC (permalink / raw) To: The development of GNU GRUB Andrei Borzenkov schreef op 08-05-2016 11:23: > PV label may be in the first sector. In this case label will be > overwritten later by boot image. This needs additional check. Pardon my last mail. ON OLD PV SIGNATURES -------------------- If you have an old PV that had a boatloaderarea, then wiping and or recreating the PV doesn't actually clear or reset or reformat that thing so as to fail. It is not necessary to have a VG in order to install grub to a PV. However, if the VG code is not called (both grub_lvm_detect and grub_diskfilter_get_pv_from_disk) then the code will not know how big the bootloaderarea is going to be (or whether you have one) -- you still don't need a VG, you just need to call that function the way this patch is. Having or not having a VG in the PV makes no difference as to the results of any operation. My code currently pretends that having a PV header is enough, and it works out just fine. I have not exhaustively tested what happens if you create a VG after (successfully booting) but I doubt it is going to give issues. So the most important thing for this checking code currently is that the PV is actually created on a clean disk, ie a simple: dd if=/dev/zero of=/dev/sda bs=1M count=20 Will ensure correct behaviour. So it is possible to create a PV without a bootloaderarea on top of an older PV that did have one, and the code will see the data structures of the old one, but the real PV and its VGs will be based on the new one (you can see the difference in that you lose an extent if you create or remove an area of 4M). So the code is not entirely correct in that sense (And I do not understand it yet at all) but in most cases it functions correctly. LOCATION OF SANITY CHECKING --------------------------- Presently what I am doing is to let the code in setup.c only check the basics, if a PV header is present, fine, let's get on with it. The embedding code (in lvm.c) then checks whether everything is alright. The annoying part is that if (and only if) you have placed your PV header in the first sector (the way we needed to prevent cq. check) it can mean that some info message is going to be output multiple times. Each time the checking function is called, it will see the header sitting in the first sector, and output some message. Apart from that the error resolution is pretty outstanding currently. So I propose to: - not need any VG - is_lvm will return true if only a header is present - sanity checking is not done much in setup.c unless it is a call to lvm.c If you really have zero sector PV header, currently the "info" message will be output at least twice, and possibly trice: - in lvm_detect - in lvm_embed - in any checking function called from setup.c I have put a parameter to get_lvh that supresses the verbosity if zero. You will see. At this point the whole VG initialisation system for embedding is only apparently needed to check the actual bootloaderarea. CURRENT RESULTS: ---------------- First off, booting works fine from a non-partition setup. I assume there is no difference installing to a disk with a partition table and no LVM. Personally I cannot get Grub to install on /dev/sda1: error: cannot find a GRUB drive for /dev/sdal. Check your device.map. Presently, this is the output if you try to install on a first-sector PV without VG: info: Scanning for lvm devices on disk hostdisk//dev/sda. info: couldn't find ID info: LVM signature in first sector. warning: installing inside LVM PV, but its header is sitting in the first sector; cannot install there. error: embedding is not possible, but this is required for LVM and RAID install. Upon creating a volume group, LVM will actually restore the PV header to the 2nd sector, if you've botched it. A zero sector (first sector) PV is just not reality. They are not recognized. Installing on a PV without bootloaderarea will result in: info: Scanning for lvm devices on disk hostdisk//dev/sda. info: Found array linux. info: Inserting hostdisk//dev/sda (+0,976773168) into linux (lvm) info: drive = 1. info: the size of hostdisk//dev/sda is 976773168. info: Scanning for DISKFILTER devices on disk hostdisk//dev/sda. warning: you have chosen to install inside an LVM PV, but it doesn't have a bootloader area (check pvcreate --bootloaderareasize). error: embedding is not possible, but this is required for LVM and RAID install. When a VG is present. I don't think it actually checks for the SIZE of the bootloaderarea but that could easily be added I think. When you do the same without a VG: info: Scanning for lvm devices on disk hostdisk//dev/sda. info: couldn't find ID warning: you have chosen to install inside an LVM PV, but it doesn't have a bootloader area (check pvcreate --bootloaderareasize). error: embedding is not possible, but this is required for LVM and RAID install. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2016-05-09 0:10 ` Xen @ 2016-05-09 0:10 ` Dryden Personalis 0 siblings, 0 replies; 24+ messages in thread From: Dryden Personalis @ 2016-05-09 0:10 UTC (permalink / raw) To: Grub devel Andrei Borzenkov schreef op 08-05-2016 11:23: > PV label may be in the first sector. In this case label will be > overwritten later by boot image. This needs additional check. Pardon my last mail. ON OLD PV SIGNATURES -------------------- If you have an old PV that had a boatloaderarea, then wiping and or recreating the PV doesn't actually clear or reset or reformat that thing so as to fail. It is not necessary to have a VG in order to install grub to a PV. However, if the VG code is not called (both grub_lvm_detect and grub_diskfilter_get_pv_from_disk) then the code will not know how big the bootloaderarea is going to be (or whether you have one) -- you still don't need a VG, you just need to call that function the way this patch is. Having or not having a VG in the PV makes no difference as to the results of any operation. My code currently pretends that having a PV header is enough, and it works out just fine. I have not exhaustively tested what happens if you create a VG after (successfully booting) but I doubt it is going to give issues. So the most important thing for this checking code currently is that the PV is actually created on a clean disk, ie a simple: dd if=/dev/zero of=/dev/sda bs=1M count=20 Will ensure correct behaviour. So it is possible to create a PV without a bootloaderarea on top of an older PV that did have one, and the code will see the data structures of the old one, but the real PV and its VGs will be based on the new one (you can see the difference in that you lose an extent if you create or remove an area of 4M). So the code is not entirely correct in that sense (And I do not understand it yet at all) but in most cases it functions correctly. LOCATION OF SANITY CHECKING --------------------------- Presently what I am doing is to let the code in setup.c only check the basics, if a PV header is present, fine, let's get on with it. The embedding code (in lvm.c) then checks whether everything is alright. The annoying part is that if (and only if) you have placed your PV header in the first sector (the way we needed to prevent cq. check) it can mean that some info message is going to be output multiple times. Each time the checking function is called, it will see the header sitting in the first sector, and output some message. Apart from that the error resolution is pretty outstanding currently. So I propose to: - not need any VG - is_lvm will return true if only a header is present - sanity checking is not done much in setup.c unless it is a call to lvm.c If you really have zero sector PV header, currently the "info" message will be output at least twice, and possibly trice: - in lvm_detect - in lvm_embed - in any checking function called from setup.c I have put a parameter to get_lvh that supresses the verbosity if zero. You will see. At this point the whole VG initialisation system for embedding is only apparently needed to check the actual bootloaderarea. CURRENT RESULTS: ---------------- First off, booting works fine from a non-partition setup. I assume there is no difference installing to a disk with a partition table and no LVM. Personally I cannot get Grub to install on /dev/sda1: error: cannot find a GRUB drive for /dev/sdal. Check your device.map. Presently, this is the output if you try to install on a first-sector PV without VG: info: Scanning for lvm devices on disk hostdisk//dev/sda. info: couldn't find ID info: LVM signature in first sector. warning: installing inside LVM PV, but its header is sitting in the first sector; cannot install there. error: embedding is not possible, but this is required for LVM and RAID install. Upon creating a volume group, LVM will actually restore the PV header to the 2nd sector, if you've botched it. A zero sector (first sector) PV is just not reality. They are not recognized. Installing on a PV without bootloaderarea will result in: info: Scanning for lvm devices on disk hostdisk//dev/sda. info: Found array linux. info: Inserting hostdisk//dev/sda (+0,976773168) into linux (lvm) info: drive = 1. info: the size of hostdisk//dev/sda is 976773168. info: Scanning for DISKFILTER devices on disk hostdisk//dev/sda. warning: you have chosen to install inside an LVM PV, but it doesn't have a bootloader area (check pvcreate --bootloaderareasize). error: embedding is not possible, but this is required for LVM and RAID install. When a VG is present. I don't think it actually checks for the SIZE of the bootloaderarea but that could easily be added I think. When you do the same without a VG: info: Scanning for lvm devices on disk hostdisk//dev/sda. info: couldn't find ID warning: you have chosen to install inside an LVM PV, but it doesn't have a bootloader area (check pvcreate --bootloaderareasize). error: embedding is not possible, but this is required for LVM and RAID install. ^ permalink raw reply [flat|nested] 24+ messages in thread
* [PATCH] Install to LVM PVs @ 2013-09-25 12:39 Gabriel de Perthuis 2013-09-26 8:53 ` Vladimir 'φ-coder/phcoder' Serbinenko 0 siblings, 1 reply; 24+ messages in thread From: Gabriel de Perthuis @ 2013-09-25 12:39 UTC (permalink / raw) To: grub-devel 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. === 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; ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2013-09-25 12:39 Gabriel de Perthuis @ 2013-09-26 8:53 ` Vladimir 'φ-coder/phcoder' Serbinenko 2013-09-27 10:39 ` Gabriel de Perthuis 0 siblings, 1 reply; 24+ messages in thread From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-26 8:53 UTC (permalink / raw) To: The development of GNU GRUB [-- 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 --] ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 2013-09-26 8:53 ` Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-27 10:39 ` Gabriel de Perthuis 2013-09-27 12:48 ` Vladimir 'φ-coder/phcoder' Serbinenko 0 siblings, 1 reply; 24+ messages in thread From: Gabriel de Perthuis @ 2013-09-27 10:39 UTC (permalink / raw) To: GRUB development, LVM2 development, Peter Rajnoha Le 26/09/2013 10:53, Vladimir 'φ-coder/phcoder' Serbinenko a écrit: > 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. For anyone else who may be interested, apparently patches exist and are waiting for Peter Rajnoha to finish them. They haven't been posted or discussed publicly and I've never seen them. According to Vladimir: > the zone will be subdivided to cover more cases and the agreement was to use "pvs" to get offsets rather than having own code for this As shipped in 2.02.99, pvs exposes exactly one ba_start/ba_size area. Other areas will have to use extra extension fields and extra fields in the pvs output, to be compatible with released versions of LVM. Parsing pvs output would be easy, and will behave exactly the same as this patch. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 ` (2 more replies) 0 siblings, 3 replies; 24+ messages in thread From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2013-09-27 12:48 UTC (permalink / raw) To: grub-devel [-- Attachment #1: Type: text/plain, Size: 1724 bytes --] On 27.09.2013 12:39, Gabriel de Perthuis wrote: > Le 26/09/2013 10:53, Vladimir 'φ-coder/phcoder' Serbinenko a écrit: >> 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. > > For anyone else who may be interested, apparently patches exist and are > waiting for Peter Rajnoha to finish them. They haven't been posted or > discussed publicly and I've never seen them. > > According to Vladimir: >> the zone will be subdivided to cover more cases and the agreement was > to use "pvs" to get offsets rather than having own code for this > > As shipped in 2.02.99, pvs exposes exactly one ba_start/ba_size area. > Other areas will have to use extra extension fields and extra fields in > the pvs output, to be compatible with released versions of LVM. No, you didn't understand: this area will have another header, GRUB one which will subdivide it. LVM gives us area and we take care of subdivision. > Parsing pvs output would be easy, and will behave exactly the same as > this patch. > > _______________________________________________ > 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 --] ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 2 siblings, 0 replies; 24+ messages in thread From: Gabriel de Perthuis @ 2013-09-27 13:56 UTC (permalink / raw) To: grub-devel, LVM2 development Le 27/09/2013 14:48, Vladimir 'φ-coder/phcoder' Serbinenko a écrit : > On 27.09.2013 12:39, Gabriel de Perthuis wrote: >> Le 26/09/2013 10:53, Vladimir 'φ-coder/phcoder' Serbinenko a écrit: >>> 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. >> >> For anyone else who may be interested, apparently patches exist and are >> waiting for Peter Rajnoha to finish them. They haven't been posted or >> discussed publicly and I've never seen them. >> >> According to Vladimir: >>> the zone will be subdivided to cover more cases and the agreement was >> to use "pvs" to get offsets rather than having own code for this >> >> As shipped in 2.02.99, pvs exposes exactly one ba_start/ba_size area. >> Other areas will have to use extra extension fields and extra fields in >> the pvs output, to be compatible with released versions of LVM. > No, you didn't understand: this area will have another header, GRUB one > which will subdivide it. LVM gives us area and we take care of subdivision. Or you could split the task in two: embed Grub on PVs, like it does on partition tables, ext2-ext4, Btrfs; then add advanced embedding that does some mini-partitioning of embedding areas. The first task is really easy and brings an immediate benefit in making LVM-only disks bootable. I don't feel qualified to discuss the second task, because I'm not seeing the use case. I don't think it's been brought up. ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 2 siblings, 0 replies; 24+ messages in thread From: Andrey Borzenkov @ 2013-09-27 14:27 UTC (permalink / raw) To: grub-devel [-- Attachment #1: Type: text/plain, Size: 2020 bytes --] В Fri, 27 Sep 2013 14:48:33 +0200 Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com> пишет: > On 27.09.2013 12:39, Gabriel de Perthuis wrote: > > Le 26/09/2013 10:53, Vladimir 'φ-coder/phcoder' Serbinenko a écrit: > >> 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. > > > > For anyone else who may be interested, apparently patches exist and are > > waiting for Peter Rajnoha to finish them. They haven't been posted or > > discussed publicly and I've never seen them. > > > > According to Vladimir: > >> the zone will be subdivided to cover more cases and the agreement was > > to use "pvs" to get offsets rather than having own code for this > > > > As shipped in 2.02.99, pvs exposes exactly one ba_start/ba_size area. > > Other areas will have to use extra extension fields and extra fields in > > the pvs output, to be compatible with released versions of LVM. > No, you didn't understand: this area will have another header, GRUB one > which will subdivide it. LVM gives us area and we take care of subdivision. Is it something specific for LVM? Or useable in all other cases when grub currently does embedding? > > Parsing pvs output would be easy, and will behave exactly the same as > > this patch. > > > > > _______________________________________________ > > Grub-devel mailing list > > Grub-devel@gnu.org > > https://lists.gnu.org/mailman/listinfo/grub-devel > > > > [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 198 bytes --] ^ permalink raw reply [flat|nested] 24+ messages in thread
* Re: [PATCH] Install to LVM PVs 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 2 siblings, 0 replies; 24+ messages in thread From: Andrei Borzenkov @ 2015-02-15 10:47 UTC (permalink / raw) To: Vladimir 'φ-coder/phcoder' Serbinenko; +Cc: grub-devel [-- Attachment #1: Type: text/plain, Size: 1995 bytes --] В Fri, 27 Sep 2013 14:48:33 +0200 Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com> пишет: > On 27.09.2013 12:39, Gabriel de Perthuis wrote: > > Le 26/09/2013 10:53, Vladimir 'φ-coder/phcoder' Serbinenko a écrit: > >> 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. > > > > For anyone else who may be interested, apparently patches exist and are > > waiting for Peter Rajnoha to finish them. They haven't been posted or > > discussed publicly and I've never seen them. > > > > According to Vladimir: > >> the zone will be subdivided to cover more cases and the agreement was > > to use "pvs" to get offsets rather than having own code for this > > > > As shipped in 2.02.99, pvs exposes exactly one ba_start/ba_size area. > > Other areas will have to use extra extension fields and extra fields in > > the pvs output, to be compatible with released versions of LVM. > No, you didn't understand: this area will have another header, GRUB one > which will subdivide it. LVM gives us area and we take care of subdivision. Did anything happen with it? Do you have any pointers to suggested design? > > Parsing pvs output would be easy, and will behave exactly the same as > > this patch. > > > > > _______________________________________________ > > 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: 181 bytes --] ^ permalink raw reply [flat|nested] 24+ messages in thread
end of thread, other threads:[~2016-05-17 18:01 UTC | newest] Thread overview: 24+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2016-05-08 4:53 [PATCH] Install to LVM PVs 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 -- strict thread matches above, loose matches on Subject: below -- 2013-09-25 12:39 Gabriel de Perthuis 2013-09-26 8:53 ` Vladimir 'φ-coder/phcoder' Serbinenko 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
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).