Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110218873
D48941.id150847.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D48941.id150847.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D48941: LinuxKPI: Rework LINUXKPI_PARAM_charp()
Attached
Detach File
Event Timeline
Log In to Comment