Page MenuHomeFreeBSD

D48941.diff
No OneTemporary

D48941.diff

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
@@ -36,6 +36,7 @@
#ifndef LINUXKPI_PARAM_PARENT
#define LINUXKPI_PARAM_PARENT _compat_linuxkpi
+#define LINUXKPI_PARAM_PARENT_ENV "compat.linuxkpi."
#endif
#ifndef LINUXKPI_PARAM_PREFIX
@@ -109,11 +110,40 @@
LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
LINUXKPI_PARAM_DESC(name)))
+extern int linux_sysctl_handle_charp(SYSCTL_HANDLER_ARGS);
+extern void linux_tunable_charp_init(void *);
+extern void linux_free_charp(void *);
+
+struct tunable_charp {
+ const char *path;
+ char **var;
+};
+#define TUNABLE_CHARP(path, var) \
+ static struct tunable_charp __CONCAT(__tunable_charp_, __LINE__) = { \
+ (path), \
+ (var), \
+ }; \
+ SYSINIT(__CONCAT(__Tunable_init_, __LINE__), \
+ SI_SUB_KMEM + 1, SI_ORDER_ANY, linux_tunable_charp_init, \
+ &__CONCAT(__tunable_charp_, __LINE__))
+
+/* Oid for a character pointer. */
+#define SYSCTL_CHARP(parent, nbr, name, access, arg, descr) \
+ SYSCTL_OID(parent, nbr, name, \
+ CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_NOFETCH | (access), \
+ arg, 0, linux_sysctl_handle_charp, "A", descr); \
+ CTASSERT(((access) & CTLTYPE) == 0 || \
+ ((access) & SYSCTL_CT_ASSERT_MASK) == CTLTYPE_STRING)
+
#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_CHARP(LINUXKPI_PARAM_PARENT, OID_AUTO, \
+ LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), \
+ LINUXKPI_PARAM_DESC(name))); \
+ TUNABLE_CHARP(LINUXKPI_PARAM_PARENT_ENV __XSTRING(LINUXKPI_PARAM_NAME(name)), \
+ &(var)); \
+ SYSUNINIT(linux_free_charp_##name, SI_SUB_KMEM + 1, SI_ORDER_ANY, \
+ linux_free_charp, &(var))
#define module_param_string(name, str, len, perm) \
extern const char LINUXKPI_PARAM_DESC(name)[]; \
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
@@ -2735,6 +2735,134 @@
#endif
}
+static struct sx sysctlcharplock;
+
+int
+linux_sysctl_handle_charp(SYSCTL_HANDLER_ARGS)
+{
+ char **charpp = arg1;
+ char *tmparg;
+ int error = 0;
+
+ /*
+ * If the sysctl isn't writable, microoptimise and treat it as a
+ * read-only string.
+ * In ddb, don't worry about trying to make a malloced snapshot.
+ */
+ if ((oidp->oid_kind & CTLFLAG_WR) == 0 || kdb_active) {
+ size_t outlen;
+
+ outlen = *charpp != NULL ? strlen(*charpp) + 1 : 0;
+ tmparg = req->oldptr != NULL ? *charpp : NULL;
+ error = SYSCTL_OUT(req, tmparg, outlen);
+ } else {
+ size_t outlen;
+
+ if (req->oldptr != NULL) {
+ for (;;) {
+ size_t len1, len2;
+
+ sx_slock(&sysctlcharplock);
+ len1 = *charpp != NULL ? strlen(*charpp) : 0;
+ sx_sunlock(&sysctlcharplock);
+ if (len1 == 0) {
+ tmparg = NULL;
+ outlen = 0;
+ break;
+ }
+
+ tmparg = malloc(len1 + 1, M_KMALLOC, M_WAITOK);
+ sx_slock(&sysctlcharplock);
+ len2 = *charpp != NULL ? strlen(*charpp) : 0;
+ if (len2 > len1) {
+ sx_sunlock(&sysctlcharplock);
+ free(tmparg, M_KMALLOC);
+ continue; /* Retry a snapshot */
+ }
+ memcpy(tmparg, *charpp, len2);
+ sx_sunlock(&sysctlcharplock);
+ tmparg[len2] = '\0';
+ outlen = strlen(tmparg) + 1;
+ break;
+ }
+ } else {
+ tmparg = NULL;
+ sx_slock(&sysctlcharplock);
+ outlen = *charpp != NULL ? strlen(*charpp) + 1 : 0;
+ sx_sunlock(&sysctlcharplock);
+ }
+ error = SYSCTL_OUT(req, tmparg, outlen);
+ free(tmparg, M_KMALLOC);
+ }
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ /* XXX Limit the maximum requested length ? */
+ if (req->newlen - req->newidx < 0) {
+ error = EINVAL;
+ } else if (req->newlen - req->newidx == 0) {
+ char *old;
+
+ sx_xlock(&sysctlcharplock);
+ old = *charpp;
+ *charpp = NULL;
+ sx_xunlock(&sysctlcharplock);
+ free(old, M_KMALLOC);
+ } else {
+ char *old, *new;
+ size_t inlen;
+
+ inlen = req->newlen - req->newidx;
+ new = malloc(inlen + 1, M_KMALLOC, M_WAITOK);
+ error = SYSCTL_IN(req, new, inlen);
+ if (error != 0) {
+ free(new, M_KMALLOC);
+ return (error);
+ }
+
+ sx_xlock(&sysctlcharplock);
+ old = *charpp;
+ new[inlen] = '\0';
+ *charpp = new;
+ sx_xunlock(&sysctlcharplock);
+ free(old, M_KMALLOC);
+ req->newidx += inlen;
+ }
+ return (error);
+}
+
+void
+linux_tunable_charp_init(void *data)
+{
+ struct tunable_charp *d = (struct tunable_charp *)data;
+ char *buf, *penv;
+ size_t len;
+
+ MPASS(*d->var == NULL);
+
+ penv = kern_getenv(d->path);
+ if (penv == NULL)
+ return;
+ if ((len = strlen(penv)) == 0)
+ goto free;
+
+ buf = malloc(len + 1, M_KMALLOC, M_WAITOK);
+ memcpy(buf, penv, len);
+ buf[len] = '\0';
+ *d->var = buf;
+free:
+ freeenv(penv);
+}
+
+void
+linux_free_charp(void *arg)
+{
+ char **p = arg;
+
+ free(*p, M_KMALLOC);
+ *p = NULL;
+}
+
static void
linux_compat_init(void *arg)
{
@@ -2778,6 +2906,7 @@
}
#endif
rw_init(&linux_vma_lock, "lkpi-vma-lock");
+ sx_init(&sysctlcharplock, "linux sysctl charp handler");
rootoid = SYSCTL_ADD_ROOT_NODE(NULL,
OID_AUTO, "sys", CTLFLAG_RD|CTLFLAG_MPSAFE, NULL, "sys");

File Metadata

Mime Type
text/plain
Expires
Sat, Feb 15, 8:30 PM (4 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16664564
Default Alt Text
D48941.diff (5 KB)

Event Timeline