git: a849842f510a - main - loader: Add support for booting from a ZFS snapshot
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 14 Mar 2023 14:19:37 UTC
The branch main has been updated by allanjude:
URL: https://cgit.FreeBSD.org/src/commit/?id=a849842f510af48717e35ff709623e0dd1b80b20
commit a849842f510af48717e35ff709623e0dd1b80b20
Author: Allan Jude <allanjude@FreeBSD.org>
AuthorDate: 2022-11-26 18:11:13 +0000
Commit: Allan Jude <allanjude@FreeBSD.org>
CommitDate: 2023-03-14 14:18:29 +0000
loader: Add support for booting from a ZFS snapshot
When booting from a snapshot we need to follow a different code path
to turn the objset ID into the name, and for forward lookups we need
to walk the parent's snapnames_zap.
With this, it is possible to set the pools BOOTFS property to a
snapshot and boot with a read-only filesystem of that snapshot.
Reviewed by: tsoome, rew, imp
Sponsored By: Beckhoff Automation GmbH & Co. KG
Sponsored By: Klara, Inc.
Differential Revision: https://reviews.freebsd.org/D38600
---
stand/libsa/zfs/zfsimpl.c | 56 +++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c
index 36c90613e827..76063e76225f 100644
--- a/stand/libsa/zfs/zfsimpl.c
+++ b/stand/libsa/zfs/zfsimpl.c
@@ -3068,11 +3068,12 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
char name[256];
char component[256];
uint64_t dir_obj, parent_obj, child_dir_zapobj;
- dnode_phys_t child_dir_zap, dataset, dir, parent;
+ dnode_phys_t child_dir_zap, snapnames_zap, dataset, dir, parent;
dsl_dir_phys_t *dd;
dsl_dataset_phys_t *ds;
char *p;
int len;
+ boolean_t issnap = B_FALSE;
p = &name[sizeof(name) - 1];
*p = '\0';
@@ -3083,6 +3084,8 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
}
ds = (dsl_dataset_phys_t *)&dataset.dn_bonus;
dir_obj = ds->ds_dir_obj;
+ if (ds->ds_snapnames_zapobj == 0)
+ issnap = B_TRUE;
for (;;) {
if (objset_get_dnode(spa, spa->spa_mos, dir_obj, &dir) != 0)
@@ -3098,6 +3101,34 @@ zfs_rlookup(const spa_t *spa, uint64_t objnum, char *result)
&parent) != 0)
return (EIO);
dd = (dsl_dir_phys_t *)&parent.dn_bonus;
+ if (issnap == B_TRUE) {
+ /*
+ * The dataset we are looking up is a snapshot
+ * the dir_obj is the parent already, we don't want
+ * the grandparent just yet. Reset to the parent.
+ */
+ dd = (dsl_dir_phys_t *)&dir.dn_bonus;
+ /* Lookup the dataset to get the snapname ZAP */
+ if (objset_get_dnode(spa, spa->spa_mos,
+ dd->dd_head_dataset_obj, &dataset))
+ return (EIO);
+ ds = (dsl_dataset_phys_t *)&dataset.dn_bonus;
+ if (objset_get_dnode(spa, spa->spa_mos,
+ ds->ds_snapnames_zapobj, &snapnames_zap) != 0)
+ return (EIO);
+ /* Get the name of the snapshot */
+ if (zap_rlookup(spa, &snapnames_zap, component,
+ objnum) != 0)
+ return (EIO);
+ len = strlen(component);
+ p -= len;
+ memcpy(p, component, len);
+ --p;
+ *p = '@';
+ issnap = B_FALSE;
+ continue;
+ }
+
child_dir_zapobj = dd->dd_child_dir_zapobj;
if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj,
&child_dir_zap) != 0)
@@ -3127,9 +3158,11 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
{
char element[256];
uint64_t dir_obj, child_dir_zapobj;
- dnode_phys_t child_dir_zap, dir;
+ dnode_phys_t child_dir_zap, snapnames_zap, dir, dataset;
dsl_dir_phys_t *dd;
+ dsl_dataset_phys_t *ds;
const char *p, *q;
+ boolean_t issnap = B_FALSE;
if (objset_get_dnode(spa, spa->spa_mos,
DMU_POOL_DIRECTORY_OBJECT, &dir))
@@ -3160,6 +3193,25 @@ zfs_lookup_dataset(const spa_t *spa, const char *name, uint64_t *objnum)
p += strlen(p);
}
+ if (issnap == B_TRUE) {
+ if (objset_get_dnode(spa, spa->spa_mos,
+ dd->dd_head_dataset_obj, &dataset))
+ return (EIO);
+ ds = (dsl_dataset_phys_t *)&dataset.dn_bonus;
+ if (objset_get_dnode(spa, spa->spa_mos,
+ ds->ds_snapnames_zapobj, &snapnames_zap) != 0)
+ return (EIO);
+ /* Actual loop condition #2. */
+ if (zap_lookup(spa, &snapnames_zap, element,
+ sizeof (dir_obj), 1, &dir_obj) != 0)
+ return (ENOENT);
+ *objnum = dir_obj;
+ return (0);
+ } else if ((q = strchr(element, '@')) != NULL) {
+ issnap = B_TRUE;
+ element[q - element] = '\0';
+ p = q + 1;
+ }
child_dir_zapobj = dd->dd_child_dir_zapobj;
if (objset_get_dnode(spa, spa->spa_mos, child_dir_zapobj,
&child_dir_zap) != 0)