diff options
-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 6364f19ed7..db3317e4cd 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -5496,6 +5496,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. @@ -5538,6 +5553,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 4e42247345..d760127ed9 100644 --- a/usr/src/uts/common/fs/zfs/sys/vdev_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/vdev_impl.h @@ -589,9 +589,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 a114e260b4..228529d9fe 100644 --- a/usr/src/uts/common/fs/zfs/vdev_disk.c +++ b/usr/src/uts/common/fs/zfs/vdev_disk.c @@ -304,6 +304,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. @@ -331,7 +332,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); @@ -367,6 +369,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; @@ -504,6 +517,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]", @@ -1166,6 +1180,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 { @@ -1277,8 +1292,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); @@ -1287,6 +1316,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 @@ -1303,6 +1335,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 606bcb8999..95a2be6239 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) { |