Page MenuHomeFreeBSD

D48941.id150847.diff
No OneTemporary

D48941.id150847.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,42 @@
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;
+ int size;
+};
+#define TUNABLE_CHARP(path, var, size) \
+ static struct tunable_charp __CONCAT(__tunable_charp_, __LINE__) = { \
+ (path), \
+ (var), \
+ (size), \
+ }; \
+ 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, len, descr) \
+ SYSCTL_OID(parent, nbr, name, \
+ CTLTYPE_STRING | CTLFLAG_MPSAFE | CTLFLAG_NOFETCH | (access), \
+ arg, len, 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_PASS(SYSCTL_CHARP(LINUXKPI_PARAM_PARENT, OID_AUTO, \
LINUXKPI_PARAM_NAME(name), LINUXKPI_PARAM_PERM(perm), &(var), 0, \
- LINUXKPI_PARAM_DESC(name)))
+ LINUXKPI_PARAM_DESC(name))); \
+ TUNABLE_CHARP(LINUXKPI_PARAM_PARENT_ENV __XSTRING(LINUXKPI_PARAM_NAME(name)), \
+ &(var), 1024); /* XXX Arbitrary size */ \
+ 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,129 @@
#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 len;
+ sx_slock(&sysctlcharplock);
+ len = *charpp != NULL ? strlen(*charpp) + 1 : 0;
+ sx_sunlock(&sysctlcharplock);
+ if (len == 0) {
+ tmparg = NULL;
+ outlen = 0;
+ break;
+ }
+
+ tmparg = malloc(len, M_KMALLOC, M_WAITOK);
+ sx_slock(&sysctlcharplock);
+ outlen = strlen(*charpp) + 1;
+ if (outlen > len) {
+ sx_sunlock(&sysctlcharplock);
+ free(tmparg, M_KMALLOC);
+ continue; /* Retry a snapshot */
+ }
+ memcpy(tmparg, *charpp, outlen);
+ sx_sunlock(&sysctlcharplock);
+ }
+ } 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 || !req->newptr)
+ 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 *tmp, *p;
+ size_t size;
+
+ MPASS(*d->var == NULL);
+ tmp = malloc(d->size, M_KMALLOC, M_WAITOK | M_ZERO);
+ TUNABLE_STR_FETCH(d->path, tmp, d->size);
+
+ size = strlen(tmp) + 1;
+ if (size == 1) {
+ free(tmp, M_KMALLOC);
+ return;
+ }
+
+ p = malloc(size, M_KMALLOC, M_WAITOK);
+ memcpy(p, tmp, size);
+ free(tmp, M_KMALLOC);
+ *d->var = p;
+}
+
+
+void
+linux_free_charp(void *arg)
+{
+ char *p = *(char **)arg;
+ free(p, M_KMALLOC);
+}
+
static void
linux_compat_init(void *arg)
{
@@ -2778,6 +2901,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
Sun, Feb 16, 6:55 AM (15 h, 5 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16670457
Default Alt Text
D48941.id150847.diff (5 KB)

Event Timeline