Re: Problem updating bootcode on ZFS on root system with MBR

From: Thomas Hoffmann <trh411_at_gmail.com>
Date: Tue, 21 Jan 2014 16:11:22 -0500
On Tue, Jan 21, 2014 at 10:47 AM, Andriy Gapon <avg_at_freebsd.org> wrote:

> on 21/01/2014 13:18 Andrey V. Elsukov said the following:
> > On 21.01.2014 14:45, Andriy Gapon wrote:
> >>>> What do I need to do to get the boot2 code written to /dev/ada0s1a?
> >>>
> >>> This will work only if ada0s1a isn't in use. The debugflags trick works
> >>> only for whole disk, i.e. for geoms with rank=1. Another way is
> >>> calculate needed offset and write bootcode directly to ada0.
> >>
> >>
> >> And ultimately we should extend our ZFS interface with an ioctl to
> write a blob
> >> to a boot code area of a specified ZFS leaf vdev.  This would the right
> way to
> >> install zfsboot.
> >
> > Hi Andriy,
> >
> > do you have some patches to test? :-)
> >
>
> I don't, but the following patch can serve as a very good example.
> It adds an ioctl that serves a slightly different but quite similar
> purpose:
>
> commit 54802d6659ec134fd221c3daaa8fdf9cee985d39
> Author: Andriy Gapon <avg_at_icyb.net.ua>
> Date:   Fri Sep 14 23:15:43 2012 +0300
>
>     [wip] zfs: add a new ioctl that allows to place text data into pad2
> area
>
>     The data is placed into Pad2 area of the first vdev label of a given
>     vdev in a given pool.
>
> diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
> b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
> index fb30ea9..4a46cc2 100644
> --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
> +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/sys/vdev.h
> _at__at_ -162,6 +162,8 _at__at_ typedef enum {
>
>  extern int vdev_label_init(vdev_t *vd, uint64_t txg, vdev_labeltype_t
> reason);
>
> +extern int vdev_label_write_pad2(vdev_t *vd, const char *buf, size_t
> size);
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
> b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
> index c7dd3ad..55c87d8 100644
> --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
> +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/vdev_label.c
> _at__at_ -855,6 +855,44 _at__at_ retry:
>         return (error);
>  }
>
> +int
> +vdev_label_write_pad2(vdev_t *vd, const char *buf, size_t size)
> +{
> +       spa_t *spa = vd->vdev_spa;
> +       zio_t *zio;
> +       char *pad2;
> +       int flags = ZIO_FLAG_CONFIG_WRITER | ZIO_FLAG_CANFAIL;
> +       int error;
> +
> +       if (size > VDEV_PAD_SIZE)
> +               return (EINVAL);
> +
> +       if (!vd->vdev_ops->vdev_op_leaf)
> +               return (ENODEV);
> +       if (vdev_is_dead(vd))
> +               return (ENXIO);
> +
> +       ASSERT(spa_config_held(spa, SCL_ALL, RW_WRITER) == SCL_ALL);
> +
> +       pad2 = zio_buf_alloc(VDEV_PAD_SIZE);
> +       bzero(pad2, VDEV_PAD_SIZE);
> +       memcpy(pad2, buf, size);
> +
> +retry:
> +       zio = zio_root(spa, NULL, NULL, flags);
> +       vdev_label_write(zio, vd, 0, pad2,
> +           offsetof(vdev_label_t, vl_pad2),
> +           VDEV_PAD_SIZE, NULL, NULL, flags);
> +       error = zio_wait(zio);
> +       if (error != 0 && !(flags & ZIO_FLAG_TRYHARD)) {
> +               flags |= ZIO_FLAG_TRYHARD;
> +               goto retry;
> +       }
> +
> +       zio_buf_free(pad2, VDEV_PAD_SIZE);
> +       return (error);
> +}
> +
>  /*
>   *
> ==========================================================================
>   * uberblock load/sync
> diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
> b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
> index e208ed8..ff90839 100644
> --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
> +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_ioctl.c
> _at__at_ -3404,6 +3404,53 _at__at_ zfs_ioc_log_history(const char *unused, nvlist_t
> *innvl,
> nvlist_t *outnvl)
>         return (error);
>  }
>
> +#ifdef __FreeBSD__
> +static int
> +zfs_ioc_nextboot(const char *unused, nvlist_t *innvl, nvlist_t *outnvl)
> +{
> +       char name[MAXNAMELEN];
> +       spa_t *spa;
> +       vdev_t *vd;
> +       char *command;
> +       uint64_t pool_guid;
> +       uint64_t vdev_guid;
> +       int error;
> +
> +       if (nvlist_lookup_uint64(innvl,
> +           ZPOOL_CONFIG_POOL_GUID, &pool_guid) != 0)
> +               return (EINVAL);
> +       if (nvlist_lookup_uint64(innvl,
> +           ZPOOL_CONFIG_GUID, &vdev_guid) != 0)
> +               return (EINVAL);
> +       if (nvlist_lookup_string(innvl,
> +           "command", &command) != 0)
> +               return (EINVAL);
> +
> +       mutex_enter(&spa_namespace_lock);
> +       spa = spa_by_guid(pool_guid, vdev_guid);
> +       if (spa != NULL)
> +               strcpy(name, spa_name(spa));
> +       mutex_exit(&spa_namespace_lock);
> +       if (spa == NULL)
> +               return (ENOENT);
> +
> +       if ((error = spa_open(name, &spa, FTAG)) != 0)
> +               return (error);
> +       spa_vdev_state_enter(spa, SCL_ALL);
> +       vd = spa_lookup_by_guid(spa, vdev_guid, B_TRUE);
> +       if (vd == NULL) {
> +               (void) spa_vdev_state_exit(spa, NULL, ENXIO);
> +               spa_close(spa, FTAG);
> +               return (ENODEV);
> +       }
> +       error = vdev_label_write_pad2(vd, command, strlen(command));
> +       (void) spa_vdev_state_exit(spa, NULL, 0);
> +       txg_wait_synced(spa->spa_dsl_pool, 0);
> +       spa_close(spa, FTAG);
> +       return (error);
> +}
> +#endif
> +
>  /*
>   * The dp_config_rwlock must not be held when calling this, because the
>   * unmount may need to write out data.
> _at__at_ -5605,6 +5652,9 _at__at_ zfs_ioctl_init(void)
>             zfs_secpolicy_config, POOL_CHECK_NONE);
>         zfs_ioctl_register_dataset_nolog(ZFS_IOC_UNJAIL, zfs_ioc_unjail,
>             zfs_secpolicy_config, POOL_CHECK_NONE);
> +       zfs_ioctl_register("fbsd_nextboot", ZFS_IOC_NEXTBOOT,
> +           zfs_ioc_nextboot, zfs_secpolicy_config, NO_NAME,
> +           POOL_CHECK_NONE, B_FALSE, B_FALSE);
>  #endif
>  }
>
> diff --git a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
> b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
> index 454c28a..917223dc 100644
> --- a/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
> +++ b/sys/cddl/contrib/opensolaris/uts/common/sys/fs/zfs.h
> _at__at_ -839,6 +839,7 _at__at_ typedef enum zfs_ioc {
>         ZFS_IOC_SEND_NEW,
>         ZFS_IOC_SEND_SPACE,
>         ZFS_IOC_CLONE,
> +       ZFS_IOC_NEXTBOOT,
>         ZFS_IOC_LAST
>  } zfs_ioc_t;
>
>
> --
> Andriy Gapon
>

Thanks for the responses. My apologies for going silent, but I had to step
away from the problem for a bit. I was able to resolve my problem by doing
the following:

After upgrading my zpools and after my aborted attempt to update the
bootcode as reported above, I copied /boot/zfsboot (or more precisely
/bootpool/boot/zfsboot) to a USB thumb drive. I attempted to reboot my
system, which failed due to unsupported zfs features. This was expected,
but I thought, hey, I might get lucky. I then booted into a Live CD,
mounted my USB thumb drive on /tmp/usb and executed:

sysctl kern.geom.debugflags=0x10
dd if=/tmp/usb/zfsboot of=/dev/ada0s1 count=1
dd if=/tmp/usb/zfsboot of=/dev/ada0s1d skip=1 seek=1024

Then I rebooted and all is well. All zpools support all features. While
this procedure was not tedious, it would still be nice if, as Andriy
stated, FreeBSD contained a native way do this zfs bootcode update for MBR
schemes that is as simple as for the GPT schemes.

Its been a gazillion years since I've done any C programming, but I'll take
a look at the patches. Thanks, Andriy and Andrey.

- Tom
Received on Tue Jan 21 2014 - 20:11:24 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:40:46 UTC