diff options
author | Joshua M. Clulow <jmc@oxide.computer> | 2022-11-10 11:36:16 -0800 |
---|---|---|
committer | Joshua M. Clulow <josh@sysmgr.org> | 2022-11-10 11:36:17 -0800 |
commit | 8b26092d555bd1deaacf79ea64da374602aefb65 (patch) | |
tree | 78276ecbb871e076e9a362fbef63911045ec32fe | |
parent | 6eeafb34dceabceff80ed689002b6dc3e060f498 (diff) | |
download | illumos-gate-8b26092d555bd1deaacf79ea64da374602aefb65.tar.gz |
15137 ZFS should allow direct import of a root pool from a /devices path
15122 vdev_disk_preroot_fini can race against the child vdev open taskq
Reviewed by: Robert Mustacchi <rm@fingolfin.org>
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: Dan Cross <cross@oxidecomputer.com>
Approved by: Dan McDonald <danmcd@mnx.io>
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 16 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/vdev_impl.h | 3 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev_disk.c | 40 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_vfsops.c | 19 |
4 files changed, 72 insertions, 6 deletions
diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index d390e39195..d6e230fbb4 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -5479,6 +5479,21 @@ spa_import_rootpool(char *devpath, char *devid, uint64_t pool_guid, char *pname; int error; const char *altdevpath = NULL; + const char *rdpath = NULL; + + if ((rdpath = vdev_disk_preroot_force_path()) != NULL) { + /* + * We expect to import a single-vdev pool from a specific + * device such as a ramdisk device. We don't care what the + * pool label says. + */ + config = spa_generate_rootconf(rdpath, NULL, &guid, 0); + if (config != NULL) { + goto configok; + } + cmn_err(CE_NOTE, "Cannot use root disk device '%s'", rdpath); + return (SET_ERROR(EIO)); + } /* * Read the label from the boot device and generate a configuration. @@ -5521,6 +5536,7 @@ spa_import_rootpool(char *devpath, char *devid, uint64_t pool_guid, return (SET_ERROR(EIO)); } +configok: VERIFY(nvlist_lookup_string(config, ZPOOL_CONFIG_POOL_NAME, &pname) == 0); VERIFY(nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, &txg) == 0); diff --git a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h index d1341dbcd3..d542368e7c 100644 --- a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h @@ -588,9 +588,10 @@ typedef struct vdev_buf { * Support routines used during boot from a ZFS pool */ extern int vdev_disk_read_rootlabel(const char *, const char *, nvlist_t **); -extern void vdev_disk_preroot_init(void); +extern void vdev_disk_preroot_init(const char *); extern void vdev_disk_preroot_fini(void); extern const char *vdev_disk_preroot_lookup(uint64_t, uint64_t); +extern const char *vdev_disk_preroot_force_path(void); #ifdef __cplusplus } diff --git a/usr/src/uts/common/fs/zfs/vdev_disk.c b/usr/src/uts/common/fs/zfs/vdev_disk.c index 1cdc458974..cd5e80d769 100644 --- a/usr/src/uts/common/fs/zfs/vdev_disk.c +++ b/usr/src/uts/common/fs/zfs/vdev_disk.c @@ -301,6 +301,7 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, int otyp; boolean_t validate_devid = B_FALSE; uint64_t capacity = 0, blksz = 0, pbsize; + const char *rdpath = vdev_disk_preroot_force_path(); /* * We must have a pathname, and it must be absolute. @@ -328,7 +329,8 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, /* * Allow bypassing the devid. */ - if (vd->vdev_devid != NULL && vdev_disk_bypass_devid) { + if (vd->vdev_devid != NULL && + (vdev_disk_bypass_devid || rdpath != NULL)) { vdev_dbgmsg(vd, "vdev_disk_open, devid %s bypassed", vd->vdev_devid); spa_strfree(vd->vdev_devid); @@ -364,6 +366,17 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, error = EINVAL; /* presume failure */ + if (rdpath != NULL) { + /* + * We have been asked to open only a specific root device, and + * to fail otherwise. + */ + error = ldi_open_by_name((char *)rdpath, spa_mode(spa), kcred, + &dvd->vd_lh, zfs_li); + validate_devid = B_TRUE; + goto rootdisk_only; + } + if (vd->vdev_path != NULL) { if (vd->vdev_wholedisk == -1ULL) { size_t len = strlen(vd->vdev_path) + 3; @@ -501,6 +514,7 @@ vdev_disk_open(vdev_t *vd, uint64_t *psize, uint64_t *max_psize, } } +rootdisk_only: if (error != 0) { vd->vdev_stat.vs_aux = VDEV_AUX_OPEN_FAILED; vdev_dbgmsg(vd, "vdev_disk_open: failed to open [error=%d]", @@ -1158,6 +1172,7 @@ vdev_disk_read_rootlabel(const char *devpath, const char *devid, struct veb { list_t veb_ents; boolean_t veb_scanned; + char *veb_force_path; }; struct veb_ent { @@ -1269,8 +1284,22 @@ vdev_disk_preroot_lookup(uint64_t pool_guid, uint64_t vdev_guid) return (path); } +const char * +vdev_disk_preroot_force_path(void) +{ + const char *force_path = NULL; + + mutex_enter(&veb_lock); + if (veb != NULL) { + force_path = veb->veb_force_path; + } + mutex_exit(&veb_lock); + + return (force_path); +} + void -vdev_disk_preroot_init(void) +vdev_disk_preroot_init(const char *force_path) { mutex_init(&veb_lock, NULL, MUTEX_DEFAULT, NULL); @@ -1279,6 +1308,9 @@ vdev_disk_preroot_init(void) list_create(&veb->veb_ents, sizeof (struct veb_ent), offsetof(struct veb_ent, vebe_link)); veb->veb_scanned = B_FALSE; + if (force_path != NULL) { + veb->veb_force_path = spa_strdup(force_path); + } } void @@ -1295,6 +1327,10 @@ vdev_disk_preroot_fini(void) kmem_free(vebe, sizeof (*vebe)); } + if (veb->veb_force_path != NULL) { + spa_strfree(veb->veb_force_path); + } + kmem_free(veb, sizeof (*veb)); veb = NULL; } diff --git a/usr/src/uts/common/fs/zfs/zfs_vfsops.c b/usr/src/uts/common/fs/zfs/zfs_vfsops.c index 87b4b36a7d..288dc93e3c 100644 --- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c +++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c @@ -1767,6 +1767,7 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why) vnode_t *vp = NULL; char *zfs_bootfs; char *zfs_devid; + char *zfs_rootdisk_path; uint64_t zfs_bootpool; uint64_t zfs_bootvdev; @@ -1806,12 +1807,19 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why) zfs_bootvdev = spa_get_bootprop_uint64("zfs-bootvdev", 0); /* + * If we have been given a root disk override path, we want to + * ignore device paths from the pool configuration and use only + * the specific path we were given in the boot properties. + */ + zfs_rootdisk_path = spa_get_bootprop("zfs-rootdisk-path"); + + /* * Initialise the early boot device rescan mechanism. A scan * will not actually be performed unless we need to do so in * order to find the correct /devices path for a relocated * device. */ - vdev_disk_preroot_init(); + vdev_disk_preroot_init(zfs_rootdisk_path); error = spa_import_rootpool(rootfs.bo_name, zfs_devid, zfs_bootpool, zfs_bootvdev); @@ -1820,6 +1828,7 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why) if (error != 0) { spa_free_bootprop(zfs_bootfs); + spa_free_bootprop(zfs_rootdisk_path); vdev_disk_preroot_fini(); cmn_err(CE_NOTE, "spa_import_rootpool: error %d", error); @@ -1828,6 +1837,7 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why) if (error = zfs_parse_bootfs(zfs_bootfs, rootfs.bo_name)) { spa_free_bootprop(zfs_bootfs); + spa_free_bootprop(zfs_rootdisk_path); vdev_disk_preroot_fini(); cmn_err(CE_NOTE, "zfs_parse_bootfs: error %d", error); @@ -1835,10 +1845,12 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why) } spa_free_bootprop(zfs_bootfs); - vdev_disk_preroot_fini(); + spa_free_bootprop(zfs_rootdisk_path); - if (error = vfs_lock(vfsp)) + if ((error = vfs_lock(vfsp)) != 0) { + vdev_disk_preroot_fini(); return (error); + } if (error = zfs_domount(vfsp, rootfs.bo_name)) { cmn_err(CE_NOTE, "zfs_domount: error %d", error); @@ -1864,6 +1876,7 @@ zfs_mountroot(vfs_t *vfsp, enum whymountroot why) vfs_add((struct vnode *)0, vfsp, (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0); out: + vdev_disk_preroot_fini(); vfs_unlock(vfsp); return (error); } else if (why == ROOT_REMOUNT) { |