grub-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH] Install to LVM PVs


From: Vladimir 'φ-coder/phcoder' Serbinenko
Subject: Re: [PATCH] Install to LVM PVs
Date: Thu, 26 Sep 2013 10:53:19 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130821 Icedove/17.0.8

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
>  
>  
>  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, &sectors);
> +    else if (is_ldm)
>        err = grub_util_ldm_embed (dest_dev->disk, &nsec, maxsec,
>                                GRUB_EMBED_PCBIOS, &sectors);
>      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
> address@hidden
> https://lists.gnu.org/mailman/listinfo/grub-devel
> 


Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]