Page MenuHomeFreeBSD

D40127.diff
No OneTemporary

D40127.diff

diff --git a/sys/kern/kern_environment.c b/sys/kern/kern_environment.c
--- a/sys/kern/kern_environment.c
+++ b/sys/kern/kern_environment.c
@@ -38,6 +38,7 @@
#include <sys/cdefs.h>
#include <sys/param.h>
+#include <sys/eventhandler.h>
#include <sys/systm.h>
#include <sys/kenv.h>
#include <sys/kernel.h>
@@ -666,6 +667,7 @@
kenvp[i + 1] = NULL;
mtx_unlock(&kenv_lock);
}
+ EVENTHANDLER_INVOKE(setenv, name);
return (0);
}
@@ -689,6 +691,7 @@
kenvp[i] = NULL;
mtx_unlock(&kenv_lock);
zfree(oldenv, M_KENV);
+ EVENTHANDLER_INVOKE(unsetenv, name);
return (0);
}
mtx_unlock(&kenv_lock);
diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c
--- a/sys/kern/kern_linker.c
+++ b/sys/kern/kern_linker.c
@@ -2351,3 +2351,12 @@
CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, 0,
sysctl_kern_function_list, "",
"kernel function list");
+
+#ifdef VIMAGE
+void
+linker_file_restore_vnet_variable(linker_file_t lf, void *addr, size_t size)
+{
+ sx_assert(&kld_sx, SA_LOCKED);
+ LINKER_RESTORE_VNET_DEFAULT(lf, addr, size);
+}
+#endif
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -54,6 +54,7 @@
#include <sys/priv.h>
#include <sys/proc.h>
#include <sys/jail.h>
+#include <sys/linker.h>
#include <sys/kdb.h>
#include <sys/lock.h>
#include <sys/mutex.h>
@@ -127,6 +128,7 @@
int recurse);
static int sysctl_old_kernel(struct sysctl_req *, const void *, size_t);
static int sysctl_new_kernel(struct sysctl_req *, void *, size_t);
+static int name2oid(char *, int *, int *, struct sysctl_oid **);
static struct sysctl_oid *
sysctl_find_oidname(const char *name, struct sysctl_oid_list *list)
@@ -512,8 +514,12 @@
if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE &&
(oidp->oid_kind & CTLFLAG_TUN) != 0 &&
(oidp->oid_kind & CTLFLAG_NOFETCH) == 0) {
- /* only fetch value once */
- oidp->oid_kind |= CTLFLAG_NOFETCH;
+#ifdef VIMAGE
+ /* can fetch multiple times for VNET loader tunable */
+ if ((oidp->oid_kind & CTLFLAG_VNET) == 0)
+#endif
+ /* only fetch value once */
+ oidp->oid_kind |= CTLFLAG_NOFETCH;
/* try to fetch value from kernel environment */
sysctl_load_tunable_by_oid_locked(oidp);
}
@@ -969,6 +975,129 @@
}
SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_FIRST, sysctl_register_all, NULL);
+#ifdef VIMAGE
+static void
+sysctl_setenv_vnet(void *arg __unused, char *name)
+{
+ struct sysctl_oid *oidp;
+ int oid[CTL_MAXNAME];
+ int error, nlen;
+
+ SYSCTL_WLOCK();
+ error = name2oid(name, oid, &nlen, &oidp);
+ if (error)
+ goto out;
+
+ if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE &&
+ (oidp->oid_kind & CTLFLAG_VNET) != 0 &&
+ (oidp->oid_kind & CTLFLAG_TUN) != 0 &&
+ (oidp->oid_kind & CTLFLAG_NOFETCH) == 0) {
+ /* try to update value from kernel environment */
+ sysctl_load_tunable_by_oid_locked(oidp);
+ }
+
+out:
+ SYSCTL_WUNLOCK();
+}
+
+struct cbargs {
+ struct sysctl_oid *oidp;
+ void *addr;
+ size_t size;
+};
+
+static int
+sysctl_linker_file_cb(linker_file_t lf, void *arg)
+{
+ struct sysctl_oid **start, **stop, **o;
+ struct cbargs *args = arg;
+
+ if (linker_file_lookup_set(lf, "sysctl_set", &start, &stop, NULL) != 0)
+ return (0);
+ for (o = start; o < stop; o++) {
+ if (*o == args->oidp) {
+ linker_file_restore_vnet_variable(lf, args->addr, args->size);
+ return (1);
+ }
+ }
+ return (0);
+}
+
+static void
+sysctl_unsetenv_vnet(void *arg __unused, char *name)
+{
+ struct rm_priotracker tracker;
+ struct sysctl_oid *oidp;
+ int oid[CTL_MAXNAME];
+ int error, nlen;
+
+ SYSCTL_RLOCK(&tracker);
+ error = name2oid(name, oid, &nlen, &oidp);
+ if (error)
+ goto out;
+
+ if ((oidp->oid_kind & CTLTYPE) != CTLTYPE_NODE &&
+ (oidp->oid_kind & CTLFLAG_VNET) != 0 &&
+ (oidp->oid_kind & CTLFLAG_TUN) != 0 &&
+ (oidp->oid_kind & CTLFLAG_NOFETCH) == 0) {
+ void *addr;
+ size_t size;
+
+ switch (oidp->oid_kind & CTLTYPE) {
+ case CTLTYPE_INT:
+ case CTLTYPE_UINT:
+ size = sizeof(int);
+ break;
+ case CTLTYPE_LONG:
+ case CTLTYPE_ULONG:
+ size = sizeof(long);
+ break;
+ case CTLTYPE_S8:
+ case CTLTYPE_U8:
+ size = sizeof(int8_t);
+ break;
+ case CTLTYPE_S16:
+ case CTLTYPE_U16:
+ size = sizeof(int16_t);
+ break;
+ case CTLTYPE_S32:
+ case CTLTYPE_U32:
+ size = sizeof(int32_t);
+ break;
+ case CTLTYPE_S64:
+ case CTLTYPE_U64:
+ size = sizeof(int64_t);
+ break;
+ case CTLTYPE_STRING:
+ MPASS(oidp->oid_arg2 > 0);
+ size = oidp->oid_arg2;
+ break;
+ default:
+ // not supported
+ goto out;
+ }
+ addr = oidp->oid_arg1;
+ SYSCTL_RUNLOCK(&tracker);
+
+ struct cbargs args = {
+ .oidp = oidp,
+ .addr = addr,
+ .size = size
+ };
+ linker_file_foreach(sysctl_linker_file_cb, &args);
+ return;
+ }
+out:
+ SYSCTL_RUNLOCK(&tracker);
+}
+
+/*
+ * Register the kernel's setenv / unsetenv events.
+ */
+EVENTHANDLER_DEFINE(setenv, sysctl_setenv_vnet, NULL, EVENTHANDLER_PRI_ANY);
+EVENTHANDLER_DEFINE(unsetenv, sysctl_unsetenv_vnet, NULL, EVENTHANDLER_PRI_ANY);
+#endif
+
/*
* "Staff-functions"
*
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -162,6 +162,7 @@
static long link_elf_strtab_get(linker_file_t, caddr_t *);
#ifdef VIMAGE
static void link_elf_propagate_vnets(linker_file_t);
+static void link_elf_restore_vnet_default(linker_file_t, void *, size_t);
#endif
static int elf_lookup(linker_file_t, Elf_Size, int, Elf_Addr *);
@@ -183,6 +184,7 @@
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
#ifdef VIMAGE
KOBJMETHOD(linker_propagate_vnets, link_elf_propagate_vnets),
+ KOBJMETHOD(linker_restore_vnet_default, link_elf_restore_vnet_default),
#endif
KOBJMETHOD_END
};
@@ -213,6 +215,7 @@
static struct elf_set_head set_pcpu_list;
#ifdef VIMAGE
static struct elf_set_head set_vnet_list;
+static void * linker_kernel_vnet_default;
#endif
static void
@@ -506,6 +509,8 @@
TAILQ_INIT(&set_pcpu_list);
#ifdef VIMAGE
TAILQ_INIT(&set_vnet_list);
+ linker_kernel_vnet_default = malloc(VNET_STOP - VNET_START, M_LINKER, M_WAITOK);
+ memcpy(linker_kernel_vnet_default, (void *)VNET_START, VNET_STOP - VNET_START);
#endif
}
@@ -1941,6 +1946,25 @@
vnet_data_copy((void *)ef->vnet_base, size);
}
}
+
+static void
+link_elf_restore_vnet_default(linker_file_t lf, void *addr, size_t size)
+{
+ elf_file_t ef = (elf_file_t)lf;
+ uintptr_t *oaddr;
+
+ MPASS(size > 0);
+ if (ef->vnet_base == 0) {
+ MPASS(lf == linker_kernel_file);
+ MPASS(VNET_START <= (uintptr_t)addr && (uintptr_t)addr + size <= VNET_STOP);
+ oaddr = (uintptr_t)linker_kernel_vnet_default + ((uintptr_t)addr - VNET_START);
+ } else {
+ MPASS((uintptr_t)ef->vnet_base <= (uintptr_t)addr &&
+ (uintptr_t)addr + size <= (uintptr_t)ef->vnet_base + (ef->vnet_stop - ef->vnet_start));
+ oaddr = (uintptr_t)ef->vnet_start + ((uintptr_t)addr - (uintptr_t)ef->vnet_base);
+ }
+ memcpy(addr, (void *)oaddr, size);
+}
#endif
#if defined(__i386__) || defined(__amd64__) || defined(__aarch64__) || defined(__powerpc__)
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -75,6 +75,9 @@
int flags; /* Section flags. */
int sec; /* Original section number. */
char *name;
+#ifdef VIMAGE
+ void *oaddr; /* Original addr, for vnet */
+#endif
} Elf_progent;
typedef struct {
@@ -152,6 +155,7 @@
static long link_elf_strtab_get(linker_file_t, caddr_t *);
#ifdef VIMAGE
static void link_elf_propagate_vnets(linker_file_t);
+static void link_elf_restore_vnet_default(linker_file_t, void *, size_t);
#endif
static int elf_obj_lookup(linker_file_t lf, Elf_Size symidx, int deps,
@@ -175,6 +179,7 @@
KOBJMETHOD(linker_strtab_get, link_elf_strtab_get),
#ifdef VIMAGE
KOBJMETHOD(linker_propagate_vnets, link_elf_propagate_vnets),
+ KOBJMETHOD(linker_restore_vnet_default, link_elf_restore_vnet_default),
#endif
KOBJMETHOD_END
};
@@ -546,6 +551,7 @@
}
memcpy(vnet_data, ef->progtab[pb].addr,
ef->progtab[pb].size);
+ ef->progtab[pb].oaddr = ef->progtab[pb].addr;
ef->progtab[pb].addr = vnet_data;
#endif
} else if ((ef->progtab[pb].name != NULL &&
@@ -1070,29 +1076,14 @@
"for %s\n", __func__,
(uintmax_t)shdr[i].sh_size,
filename);
+ error = ENOSPC;
+ goto out;
}
}
-#ifdef VIMAGE
- else if (ef->progtab[pb].name != NULL &&
- !strcmp(ef->progtab[pb].name, VNET_SETNAME)) {
- ef->progtab[pb].addr =
- vnet_data_alloc(shdr[i].sh_size);
- if (ef->progtab[pb].addr == NULL) {
- printf("%s: vnet module space is out "
- "of space; cannot allocate %#jx "
- "for %s\n", __func__,
- (uintmax_t)shdr[i].sh_size,
- filename);
- }
- }
-#endif
else
ef->progtab[pb].addr =
(void *)(uintptr_t)mapbase;
- if (ef->progtab[pb].addr == NULL) {
- error = ENOSPC;
- goto out;
- }
+
ef->progtab[pb].size = shdr[i].sh_size;
ef->progtab[pb].flags = shdr[i].sh_flags;
ef->progtab[pb].sec = i;
@@ -1120,6 +1111,29 @@
} else
bzero(ef->progtab[pb].addr, shdr[i].sh_size);
+#ifdef VIMAGE
+ /* Initialize the vnet area. */
+ if (ef->progtab[pb].name != NULL &&
+ !strcmp(ef->progtab[pb].name, VNET_SETNAME)) {
+ void *vnet_data;
+
+ vnet_data = vnet_data_alloc(shdr[i].sh_size);
+ if (vnet_data == NULL) {
+ printf("%s: vnet module space is out "
+ "of space; cannot allocate %#jx "
+ "for %s\n", __func__,
+ (uintmax_t)shdr[i].sh_size,
+ filename);
+ error = ENOSPC;
+ goto out;
+ }
+ memcpy(vnet_data, ef->progtab[pb].addr,
+ ef->progtab[pb].size);
+ vnet_data_copy(vnet_data, shdr[i].sh_size);
+ ef->progtab[pb].oaddr = ef->progtab[pb].addr;
+ ef->progtab[pb].addr = vnet_data;
+ }
+#endif
/* Update all symbol values with the offset. */
for (j = 0; j < ef->ddbsymcnt; j++) {
es = &ef->ddbsymtab[j];
@@ -1878,4 +1892,32 @@
}
}
}
+
+static void
+link_elf_restore_vnet_default(linker_file_t lf, void *addr, size_t size)
+{
+ elf_file_t ef = (elf_file_t)lf;
+
+ MPASS(size > 0);
+ MPASS(ef->progtab != NULL);
+
+ for (int i = 0; i < ef->nprogtab; i++) {
+ if (ef->progtab[i].size == 0)
+ continue;
+ if (ef->progtab[i].name == NULL)
+ continue;
+ if (strcmp(ef->progtab[i].name, VNET_SETNAME) != 0)
+ continue;
+
+ MPASS(ef->progtab[i].oaddr != NULL);
+ MPASS(ef->progtab[i].addr <= addr &&
+ ((uintptr_t)addr + size) <= ((uintptr_t)ef->progtab[i].addr +
+ ef->progtab[i].size));
+
+ memcpy(addr, (void *)((uintptr_t)ef->progtab[i].oaddr +
+ ((uintptr_t)addr - (uintptr_t)ef->progtab[i].addr)),
+ size);
+ break;
+ }
+}
#endif
diff --git a/sys/kern/linker_if.m b/sys/kern/linker_if.m
--- a/sys/kern/linker_if.m
+++ b/sys/kern/linker_if.m
@@ -162,4 +162,13 @@
METHOD void propagate_vnets {
linker_file_t file;
};
+
+#
+# Restore vnets' default values
+#
+METHOD void restore_vnet_default {
+ linker_file_t file;
+ void * addr;
+ size_t size;
+};
#endif
diff --git a/sys/sys/eventhandler.h b/sys/sys/eventhandler.h
--- a/sys/sys/eventhandler.h
+++ b/sys/sys/eventhandler.h
@@ -326,4 +326,9 @@
typedef void (*rt_addrmsg_fn)(void *, struct ifaddr *, int);
EVENTHANDLER_DECLARE(rt_addrmsg, rt_addrmsg_fn);
+/* Kernel environment variable change event */
+typedef void (*env_change_fn)(void *, const char *);
+EVENTHANDLER_DECLARE(setenv, env_change_fn);
+EVENTHANDLER_DECLARE(unsetenv, env_change_fn);
+
#endif /* _SYS_EVENTHANDLER_H_ */
diff --git a/sys/sys/linker.h b/sys/sys/linker.h
--- a/sys/sys/linker.h
+++ b/sys/sys/linker.h
@@ -205,6 +205,10 @@
int linker_kldload_busy(int flags);
void linker_kldload_unbusy(int flags);
+#ifdef VIMAGE
+void linker_file_restore_vnet_variable(linker_file_t lf, void *addr,
+ size_t size);
+#endif
#endif /* _KERNEL */
/*

File Metadata

Mime Type
text/plain
Expires
Thu, Nov 14, 10:48 PM (8 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14634746
Default Alt Text
D40127.diff (11 KB)

Event Timeline