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 @@ -104,9 +104,10 @@ #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))) + 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 +137,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 @@ -2632,6 +2632,54 @@ lkpi_net_maxpps)); } +static struct rwlock lkpi_charp_lock; +RW_SYSINIT(lkpi_charp_init, &lkpi_charp_lock, "lkpi charp module param lock"); + +int +lkpi_sysctl_handle_charp(SYSCTL_HANDLER_ARGS) +{ + char **charp = arg1; + int error = 0; + + rw_rlock(&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) { + rw_runlock(&lkpi_charp_lock); + return (error); + } + + if (!rw_try_upgrade(&lkpi_charp_lock)) { + rw_runlock(&lkpi_charp_lock); + rw_wlock(&lkpi_charp_lock); + } + + if (*charp != NULL) + 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: + rw_wunlock(&lkpi_charp_lock); + return (error); +} + #if defined(__i386__) || defined(__amd64__) bool linux_cpu_has_clflush; #endif