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

From: Andriy Gapon <avg_at_FreeBSD.org>
Date: Tue, 21 Jan 2014 17:47:37 +0200
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
Received on Tue Jan 21 2014 - 14:49:04 UTC

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