Problem updating bootcode on ZFS on root system with MBR
Andriy Gapon
avg at FreeBSD.org
Tue Jan 21 15:49:04 UTC 2014
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
@@ -162,6 +162,8 @@ 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
@@ -855,6 +855,44 @@ 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
@@ -3404,6 +3404,53 @@ 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.
@@ -5605,6 +5652,9 @@ 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
@@ -839,6 +839,7 @@ 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
More information about the freebsd-current
mailing list