From b827625471a8d781980ea58fdc2ae0b7be5ad18a Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Thu, 16 May 2024 15:23:40 +1000 Subject: [PATCH] freebsd/kstat: replace existing kstat if name is reused Normally, when trying to add a sysctl name that already exists, the kernel rejects it with a warning. This changes the code to search for a sysctl with the wanted name in same root. If it exists, it is destroyed, allowing the new one to go in. Arguably, a collision like this shouldn't ever happen, but during import multiple vdev_t (and so vdev_queue_t, and so vdev_queue stats) can exist at the same time for the same guid. There's no real way to tell which is which without substantial refactoring in the import and vdev init codepaths, whch is probably worthwhile but not for today. Sponsored-by: Klara, Inc. Sponsored-by: Syneto Signed-off-by: Rob Norris --- module/os/freebsd/spl/spl_kstat.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/module/os/freebsd/spl/spl_kstat.c b/module/os/freebsd/spl/spl_kstat.c index 2e20e42d7d..4ab6e05144 100644 --- a/module/os/freebsd/spl/spl_kstat.c +++ b/module/os/freebsd/spl/spl_kstat.c @@ -420,7 +420,26 @@ kstat_install_named(kstat_t *ksp) if (ksent->data_type != 0) { typelast = ksent->data_type; namelast = ksent->name; + + /* + * If a sysctl with this name already exists on this on + * this root, first remove it by deleting it from its + * old context, and then destroying it. + */ + struct sysctl_oid *oid = NULL; + SYSCTL_FOREACH(oid, + SYSCTL_CHILDREN(ksp->ks_sysctl_root)) { + if (strcmp(oid->oid_name, namelast) == 0) { + kstat_t *oldksp = + (kstat_t *)oid->oid_arg1; + sysctl_ctx_entry_del( + &oldksp->ks_sysctl_ctx, oid); + sysctl_remove_oid(oid, 1, 0); + break; + } + } } + switch (typelast) { case KSTAT_DATA_CHAR: /* Not Implemented */