diff --git a/include/sys/vdev_file.h b/include/sys/vdev_file.h index fddecbfe1ab5..9b343bfb7b39 100644 --- a/include/sys/vdev_file.h +++ b/include/sys/vdev_file.h @@ -39,6 +39,7 @@ typedef struct vdev_file { extern void vdev_file_init(void); extern void vdev_file_fini(void); +extern mode_t vdev_file_open_mode(spa_mode_t spa_mode); #ifdef __cplusplus } diff --git a/include/sys/zia.h b/include/sys/zia.h index 5a806a74093a..a53e66ba3610 100644 --- a/include/sys/zia.h +++ b/include/sys/zia.h @@ -118,9 +118,9 @@ void zia_prop_warn(boolean_t val, const char *name); int zia_init(void); int zia_fini(void); -void *zia_get_provider(const char *name); +void *zia_get_provider(const char *name, vdev_t *vdev); const char *zia_get_provider_name(void *provider); -int zia_put_provider(void **provider); +int zia_put_provider(void **provider, vdev_t *vdev); /* * turn off offloading for this zio as well as diff --git a/module/os/linux/zfs/vdev_file.c b/module/os/linux/zfs/vdev_file.c index 8e7483b21b3d..b50be29a118e 100644 --- a/module/os/linux/zfs/vdev_file.c +++ b/module/os/linux/zfs/vdev_file.c @@ -69,7 +69,7 @@ vdev_file_rele(vdev_t *vd) ASSERT(vd->vdev_path != NULL); } -static mode_t +mode_t vdev_file_open_mode(spa_mode_t spa_mode) { mode_t mode = 0; diff --git a/module/zfs/spa.c b/module/zfs/spa.c index 01cd0544789d..14890fbb2da8 100644 --- a/module/zfs/spa.c +++ b/module/zfs/spa.c @@ -2194,7 +2194,8 @@ spa_unload(spa_t *spa) spa->spa_raidz_expand = NULL; if (zia_get_props(spa)->provider != NULL) { - zia_put_provider(&zia_get_props(spa)->provider); + zia_put_provider(&zia_get_props(spa)->provider, + spa->spa_root_vdev); } spa_config_exit(spa, SCL_ALL, spa); @@ -9499,8 +9500,10 @@ spa_sync_props(void *arg, dmu_tx_t *tx) case ZPOOL_PROP_ZIA_PROVIDER: strval = fnvpair_value_string(elem); if (zia_props->provider != NULL) - zia_put_provider(&zia_props->provider); - zia_props->provider = zia_get_provider(strval); + zia_put_provider(&zia_props->provider, + spa->spa_root_vdev); + zia_props->provider = zia_get_provider(strval, + spa->spa_root_vdev); zia_props->can_offload = !!zia_props->provider; /* diff --git a/module/zfs/zia.c b/module/zfs/zia.c index f5354452e3af..f3eb3575745a 100644 --- a/module/zfs/zia.c +++ b/module/zfs/zia.c @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -289,8 +290,39 @@ zia_fini(void) return (ZIA_OK); } +#ifdef ZIA +/* recursively find all leaf vdevs and open them */ +static void zia_open_vdevs(vdev_t *vd) { + vdev_ops_t *ops = vd->vdev_ops; + if (ops->vdev_op_leaf) { + ASSERT(!vd->vdev_zia_handle); + + const size_t len = strlen(ops->vdev_op_type); + if (len == 4) { + if (memcmp(ops->vdev_op_type, "file", 4) == 0) { + zia_file_open(vd, vd->vdev_path, + vdev_file_open_mode(spa_mode(vd->vdev_spa)), + 0); + } +#ifdef _KERNEL + else if (memcmp(ops->vdev_op_type, "disk", 4) == 0) { + /* first member is struct block_device * */ + void *disk = vd->vdev_tsd; + zia_disk_open(vd, vd->vdev_path, disk); + } +#endif + } + } else { + for (uint64_t i = 0; i < vd->vdev_children; i++) { + vdev_t *child = vd->vdev_child[i]; + zia_open_vdevs(child); + } + } +} +#endif + void * -zia_get_provider(const char *name) +zia_get_provider(const char *name, vdev_t *vdev) { #ifdef ZIA if (!dpusm) { @@ -303,6 +335,11 @@ zia_get_provider(const char *name) printk("Z.I.A. obtained handle to provider \"%s\" (%p)", name, provider); #endif + + /* set up Z.I.A. for existing vdevs */ + if (vdev) { + zia_open_vdevs(vdev); + } return (provider); #else (void) name; (void) vdev; @@ -324,14 +361,47 @@ zia_get_provider_name(void *provider) #endif } +#ifdef ZIA +/* recursively find all leaf vdevs and close them */ +static void zia_close_vdevs(vdev_t *vd) { + vdev_ops_t *ops = vd->vdev_ops; + if (ops->vdev_op_leaf) { + const size_t len = strlen(ops->vdev_op_type); + if (len == 4) { + if (memcmp(ops->vdev_op_type, "file", 4) == 0) { + zia_file_close(vd); + } +#ifdef _KERNEL + else if (memcmp(ops->vdev_op_type, "disk", 4) == 0) { + zia_disk_close(vd); + } +#endif + } + } else { + for (uint64_t i = 0; i < vd->vdev_children; i++) { + vdev_t *child = vd->vdev_child[i]; + zia_close_vdevs(child); + } + } +} +#endif + int -zia_put_provider(void **provider) +zia_put_provider(void **provider, vdev_t *vdev) { #ifdef ZIA if (!dpusm || !provider || !*provider) { return (ZIA_FALLBACK); } + /* + * if the zpool is not going down, but the provider is going away, + * make sure the vdevs don't keep pointing to the invalid provider + */ + if (vdev) { + zia_close_vdevs(vdev); + } + #ifdef _KERNEL const char *name = zia_get_provider_name(*provider); #endif