diff --git a/sys/compat/linuxkpi/common/include/linux/moduleparam.h b/sys/compat/linuxkpi/common/include/linux/moduleparam.h --- a/sys/compat/linuxkpi/common/include/linux/moduleparam.h +++ b/sys/compat/linuxkpi/common/include/linux/moduleparam.h @@ -53,6 +53,7 @@ #define LINUXKPI_PARAM_PASS(...) __VA_ARGS__ #define LINUXKPI_PARAM_DESC(name) LINUXKPI_PARAM_CONCAT(linuxkpi_,LINUXKPI_PARAM_PREFIX,name,_desc) #define LINUXKPI_PARAM_NAME(name) LINUXKPI_PARAM_CONCAT(LINUXKPI_PARAM_PREFIX,name,,) +#define LINUXKPI_PARAM_UNINIT(name) LINUXKPI_PARAM_CONCAT(linuxkpi_,LINUXKPI_PARAM_PREFIX,name,_uninit) #define LINUXKPI_PARAM_bool(name, var, perm) \ extern const char LINUXKPI_PARAM_DESC(name)[]; \ @@ -104,9 +105,13 @@ #define LINUXKPI_PARAM_charp(name, var, perm) \ extern const char LINUXKPI_PARAM_DESC(name)[]; \ - LINUXKPI_PARAM_PASS(SYSCTL_STRING(LINUXKPI_PARAM_PARENT, OID_AUTO, \ - LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \ - LINUXKPI_PARAM_DESC(name))) + static void LINUXKPI_PARAM_UNINIT(name)(void *data) { kfree(LINUXKPI_PARAM_DESC(name)); } \ + SYSUNINIT(LINUXKPI_PARAM_UNINIT(name), SI_SUB_KLD, SI_ORDER_MIDDLE, \ + LINUXKPI_PARAM_UNINIT(name), NULL); \ + LINUXKPI_PARAM_PASS(SYSCTL_PROC(LINUXKPI_PARAM_PARENT, OID_AUTO, \ + LINUXKPI_PARAM_NAME(name), \ + LINUXKPI_PARAM_PERM(perm) | CTLTYPE_STRING | CTLFLAG_MPSAFE, \ + &(var), 0, lkpi_sysctl_handle_charp, "A", LINUXKPI_PARAM_DESC(name))) #define module_param_string(name, str, len, perm) \ extern const char LINUXKPI_PARAM_DESC(name)[]; \ @@ -136,4 +141,6 @@ SYSCTL_DECL(_compat_linuxkpi); +extern int lkpi_sysctl_handle_charp(SYSCTL_HANDLER_ARGS); + #endif /* _LINUXKPI_LINUX_MODULEPARAM_H_ */ diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c --- a/sys/compat/linuxkpi/common/src/linux_compat.c +++ b/sys/compat/linuxkpi/common/src/linux_compat.c @@ -2728,6 +2728,47 @@ return (io_mapping_init_wc(mapping, base, size)); } +static struct sx lkpi_charp_lock; +SX_SYSINIT(lkpi_charp, &lkpi_charp_lock, "lkpi charp module param lock"); + +int +lkpi_sysctl_handle_charp(SYSCTL_HANDLER_ARGS) +{ + char **charp = arg1; + int error = 0; + + sx_xlock(&lkpi_charp_lock); + + if (req->oldptr != NULL) { + error = SYSCTL_OUT_STR(req, *charp == NULL ? "" : *charp); + } else { + error = SYSCTL_OUT(req, NULL, *charp == NULL ? 1 : strlen(*charp) + 1); + } + if (error || !req->newptr) { + goto end; + } + + kfree(*charp); + + if (req->newlen == 0) { + *charp = NULL; + goto end; + } + + *charp = kzalloc(req->newlen + 1, GFP_KERNEL); + error = SYSCTL_IN(req, *charp, req->newlen); + if (error) { + kfree(*charp); + *charp = NULL; + } else { + (*charp)[req->newlen] = '\0'; + } + +end: + sx_xunlock(&lkpi_charp_lock); + return (error); +} + #if defined(__i386__) || defined(__amd64__) bool linux_cpu_has_clflush; #endif