aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog41
-rw-r--r--INSTALL5
-rw-r--r--Makeconfig16
-rw-r--r--README.tunables85
-rw-r--r--config.h.in3
-rw-r--r--config.make.in1
-rwxr-xr-xconfigure16
-rw-r--r--configure.ac10
-rw-r--r--csu/init-first.c2
-rw-r--r--csu/libc-start.c8
-rw-r--r--elf/Makefile5
-rw-r--r--elf/Versions3
-rw-r--r--elf/dl-support.c2
-rw-r--r--elf/dl-sysdep.c4
-rw-r--r--elf/dl-tunable-types.h46
-rw-r--r--elf/dl-tunables.c320
-rw-r--r--elf/dl-tunables.h88
-rw-r--r--elf/dl-tunables.list69
-rw-r--r--elf/rtld.c2
-rw-r--r--malloc/Makefile2
-rw-r--r--malloc/arena.c54
-rw-r--r--malloc/tst-malloc-usable-static.c1
-rw-r--r--manual/install.texi5
-rw-r--r--scripts/gen-tunables.awk157
-rw-r--r--sysdeps/mach/hurd/dl-sysdep.c4
25 files changed, 947 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index d219e5432b..85a4ac30df 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,44 @@
+2016-12-31 Siddhesh Poyarekar <siddhesh@sourceware.org>
+
+ * manual/install.texi: Add --enable-tunables option.
+ * INSTALL: Regenerate.
+ * README.tunables: New file.
+ * Makeconfig (CPPFLAGS): Define TOP_NAMESPACE.
+ (before-compile): Generate dl-tunable-list.h early.
+ * config.h.in: Add HAVE_TUNABLES.
+ * config.make.in: Add have-tunables.
+ * configure.ac: Add --enable-tunables option.
+ * configure: Regenerate.
+ * csu/init-first.c (__libc_init_first): Move
+ __libc_init_secure earlier...
+ * csu/init-first.c (LIBC_START_MAIN):... to here.
+ Include dl-tunables.h, libc-internal.h.
+ (LIBC_START_MAIN) [!SHARED]: Initialize tunables for static
+ binaries.
+ * elf/Makefile (dl-routines): Add dl-tunables.
+ * elf/Versions (ld): Add __tunable_set_val to GLIBC_PRIVATE
+ namespace.
+ * elf/dl-support (_dl_nondynamic_init): Unset MALLOC_CHECK_
+ only when !HAVE_TUNABLES.
+ * elf/rtld.c (process_envvars): Likewise.
+ * elf/dl-sysdep.c [HAVE_TUNABLES]: Include dl-tunables.h
+ (_dl_sysdep_start): Call __tunables_init.
+ * elf/dl-tunable-types.h: New file.
+ * elf/dl-tunables.c: New file.
+ * elf/dl-tunables.h: New file.
+ * elf/dl-tunables.list: New file.
+ * malloc/tst-malloc-usable-static.c: New test case.
+ * malloc/Makefile (tests-static): Add it.
+ * malloc/arena.c [HAVE_TUNABLES]: Include dl-tunables.h.
+ Define TUNABLE_NAMESPACE.
+ (DL_TUNABLE_CALLBACK (set_mallopt_check)): New function.
+ (DL_TUNABLE_CALLBACK_FNDECL): New macro. Use it to define
+ callback functions.
+ (ptmalloc_init): Set tunable values.
+ * scripts/gen-tunables.awk: New file.
+ * sysdeps/mach/hurd/dl-sysdep.c: Include dl-tunables.h.
+ (_dl_sysdep_start): Call __tunables_init.
+
2016-12-31 Florian Weimer <fweimer@redhat.com>
* resolv/resolv.h (RES_BLAST): Deprecate.
diff --git a/INSTALL b/INSTALL
index 104f36b0bf..25619fc520 100644
--- a/INSTALL
+++ b/INSTALL
@@ -169,6 +169,11 @@ will be used, and CFLAGS sets optimization options for the compiler.
By default for x86_64, the GNU C Library is built with the vector
math library. Use this option to disable the vector math library.
+'--enable-tunables'
+ Tunables support allows additional library parameters to be
+ customized at runtime. This is an experimental feature and affects
+ startup time and is thus disabled by default.
+
'--build=BUILD-SYSTEM'
'--host=HOST-SYSTEM'
These options are for cross-compiling. If you specify both options
diff --git a/Makeconfig b/Makeconfig
index 0158eaa76e..b173e4cc08 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -934,6 +934,11 @@ CPPFLAGS = $(config-extra-cppflags) $(CPPUNDEFS) $(CPPFLAGS-config) \
$(foreach lib,$(libof-$(basename $(@F))) \
$(libof-$(<F)) $(libof-$(@F)),$(CPPFLAGS-$(lib))) \
$(CPPFLAGS-$(<F)) $(CPPFLAGS-$(@F)) $(CPPFLAGS-$(basename $(@F)))
+
+ifeq (yes,$(have-tunables))
+CPPFLAGS += -DTOP_NAMESPACE=glibc
+endif
+
override CFLAGS = -std=gnu11 -fgnu89-inline $(config-extra-cflags) \
$(filter-out %frame-pointer,$(+cflags)) $(+gccwarn-c) \
$(sysdep-CFLAGS) $(CFLAGS-$(suffix $@)) $(CFLAGS-$(<F)) \
@@ -1108,6 +1113,17 @@ $(common-objpfx)libc-modules.stmp: $(..)scripts/gen-libc-modules.awk \
endif
+# Build the tunables list header early since it could be used by any module in
+# glibc.
+ifeq (yes,$(have-tunables))
+before-compile += $(common-objpfx)dl-tunable-list.h
+
+$(common-objpfx)dl-tunable-list.h: $(..)scripts/gen-tunables.awk \
+ $(..)elf/dl-tunables.list
+ $(AWK) -f $^ > $@.tmp
+ mv $@.tmp $@
+endif
+
common-generated += libc-modules.h libc-modules.stmp
# The name under which the run-time dynamic linker is installed.
diff --git a/README.tunables b/README.tunables
new file mode 100644
index 0000000000..df74f3b24b
--- /dev/null
+++ b/README.tunables
@@ -0,0 +1,85 @@
+ TUNABLE FRAMEWORK
+ =================
+
+Tunables is a feature in the GNU C Library that allows application authors and
+distribution maintainers to alter the runtime library behaviour to match their
+workload.
+
+The tunable framework allows modules within glibc to register variables that
+may be tweaked through an environment variable. It aims to enforce a strict
+namespace rule to bring consistency to naming of these tunable environment
+variables across the project. This document is a guide for glibc developers to
+add tunables to the framework.
+
+ADDING A NEW TUNABLE
+--------------------
+
+The TOP_NAMESPACE macro is defined by default as 'glibc'. If distributions
+intend to add their own tunables, they should do so in a different top
+namespace by overriding the TOP_NAMESPACE macro for that tunable. Downstream
+implementations are discouraged from using the 'glibc' top namespace for
+tunables they don't already have consensus to push upstream.
+
+There are two steps to adding a tunable:
+
+1. Add a tunable ID:
+
+Modules that wish to use the tunables interface must define the
+TUNABLE_NAMESPACE macro. Following this, for each tunable you want to
+add, make an entry in elf/dl-tunables.list. The format of the file is as
+follows:
+
+TOP_NAMESPACE {
+ NAMESPACE1 {
+ TUNABLE1 {
+ # tunable attributes, one per line
+ }
+ # A tunable with default attributes, i.e. string variable.
+ TUNABLE2
+ TUNABLE3 {
+ # its attributes
+ }
+ }
+ NAMESPACE2 {
+ ...
+ }
+}
+
+The list of allowed attributes are:
+
+- type: Data type. Defaults to STRING. Allowed types are:
+ INT_32, SIZE_T and STRING.
+
+- minval: Optional minimum acceptable value. For a string type
+ this is the minimum length of the value.
+
+- maxval: Optional maximum acceptable value. For a string type
+ this is the maximum length of the value.
+
+- env_alias: An alias environment variable
+
+- is_secure: Specify whether the tunable should be read for setuid
+ binaries. True allows the tunable to be read for
+ setuid binaries while false disables it. Note that
+ even if this is set as true and the value is read, it
+ may not be used if it does not validate against the
+ acceptable values or is not considered safe by the
+ module.
+
+2. Call either the TUNABLE_SET_VALUE and pass into it the tunable name and a
+ pointer to the variable that should be set with the tunable value.
+ If additional work needs to be done after setting the value, use the
+ TUNABLE_SET_VALUE_WITH_CALLBACK instead and additionally pass a pointer to
+ the function that should be called if the tunable value has been set.
+
+FUTURE WORK
+-----------
+
+The framework currently only allows a one-time initialization of variables
+through environment variables and in some cases, modification of variables via
+an API call. A future goals for this project include:
+
+- Setting system-wide and user-wide defaults for tunables through some
+ mechanism like a configuration file.
+
+- Allow tweaking of some tunables at runtime
diff --git a/config.h.in b/config.h.in
index 82f95a6dbd..7bfe923c06 100644
--- a/config.h.in
+++ b/config.h.in
@@ -256,4 +256,7 @@
/* PowerPC32 uses fctidz for floating point to long long conversions. */
#define HAVE_PPC_FCTIDZ 0
+/* Build glibc with tunables support. */
+#define HAVE_TUNABLES 0
+
#endif
diff --git a/config.make.in b/config.make.in
index 4422025e59..2f8dae213d 100644
--- a/config.make.in
+++ b/config.make.in
@@ -96,6 +96,7 @@ use-nscd = @use_nscd@
build-hardcoded-path-in-tests= @hardcoded_path_in_tests@
build-pt-chown = @build_pt_chown@
enable-lock-elision = @enable_lock_elision@
+have-tunables = @have_tunables@
# Build tools.
CC = @CC@
diff --git a/configure b/configure
index c88f6fe88c..d80d738fd1 100755
--- a/configure
+++ b/configure
@@ -666,6 +666,7 @@ libc_cv_ssp
base_machine
add_on_subdirs
add_ons
+have_tunables
build_pt_chown
build_nscd
link_obsolete_rpc
@@ -782,6 +783,7 @@ enable_systemtap
enable_build_nscd
enable_nscd
enable_pt_chown
+enable_tunables
enable_mathvec
with_cpu
'
@@ -1452,6 +1454,7 @@ Optional Features:
--disable-build-nscd disable building and installing the nscd daemon
--disable-nscd library functions will not contact the nscd daemon
--enable-pt_chown Enable building and installing pt_chown
+ --enable-tunables Enable tunables support
--enable-mathvec Enable building and installing mathvec [default
depends on architecture]
@@ -3698,6 +3701,19 @@ if test "$build_pt_chown" = yes; then
fi
+# Check whether --enable-tunables was given.
+if test "${enable_tunables+set}" = set; then :
+ enableval=$enable_tunables; have_tunables=$enableval
+else
+ have_tunables=no
+fi
+
+
+if test "$have_tunables" = yes; then
+ $as_echo "#define HAVE_TUNABLES 1" >>confdefs.h
+
+fi
+
# The abi-tags file uses a fairly simplistic model for name recognition that
# can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a
# $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell.
diff --git a/configure.ac b/configure.ac
index 2782bfaf08..22f5cab200 100644
--- a/configure.ac
+++ b/configure.ac
@@ -421,6 +421,16 @@ if test "$build_pt_chown" = yes; then
AC_DEFINE(HAVE_PT_CHOWN)
fi
+AC_ARG_ENABLE([tunables],
+ [AS_HELP_STRING([--enable-tunables],
+ [Enable tunables support])],
+ [have_tunables=$enableval],
+ [have_tunables=no])
+AC_SUBST(have_tunables)
+if test "$have_tunables" = yes; then
+ AC_DEFINE(HAVE_TUNABLES)
+fi
+
# The abi-tags file uses a fairly simplistic model for name recognition that
# can't distinguish i486-pc-linux-gnu fully from i486-pc-gnu. So we mutate a
# $host_os of `gnu*' here to be `gnu-gnu*' just so that it can tell.
diff --git a/csu/init-first.c b/csu/init-first.c
index 77c6e1cb9e..465f25b722 100644
--- a/csu/init-first.c
+++ b/csu/init-first.c
@@ -72,8 +72,6 @@ _init (int argc, char **argv, char **envp)
__environ = envp;
#ifndef SHARED
- __libc_init_secure ();
-
/* First the initialization which normally would be done by the
dynamic linker. */
_dl_non_dynamic_init ();
diff --git a/csu/libc-start.c b/csu/libc-start.c
index cc59073abe..15db9b4684 100644
--- a/csu/libc-start.c
+++ b/csu/libc-start.c
@@ -21,6 +21,9 @@
#include <unistd.h>
#include <ldsodefs.h>
#include <exit-thread.h>
+#include <libc-internal.h>
+
+#include <elf/dl-tunables.h>
extern void __libc_init_first (int argc, char **argv, char **envp);
@@ -174,6 +177,11 @@ LIBC_START_MAIN (int (*main) (int, char **, char ** MAIN_AUXVEC_DECL),
}
}
+ /* Initialize very early so that tunables can use it. */
+ __libc_init_secure ();
+
+ __tunables_init (__environ);
+
/* Perform IREL{,A} relocations. */
apply_irel ();
diff --git a/elf/Makefile b/elf/Makefile
index 8a2ce02cd5..de28d99224 100644
--- a/elf/Makefile
+++ b/elf/Makefile
@@ -35,6 +35,11 @@ dl-routines = $(addprefix dl-,load lookup object reloc deps hwcaps \
ifeq (yes,$(use-ldconfig))
dl-routines += dl-cache
endif
+
+ifeq (yes,$(have-tunables))
+dl-routines += dl-tunables
+endif
+
all-dl-routines = $(dl-routines) $(sysdep-dl-routines)
# But they are absent from the shared libc, because that code is in ld.so.
elide-routines.os = $(all-dl-routines) dl-support enbl-secure dl-origin \
diff --git a/elf/Versions b/elf/Versions
index 3d57e36fd2..6abe9db8bd 100644
--- a/elf/Versions
+++ b/elf/Versions
@@ -70,5 +70,8 @@ ld {
# Internal error handling support. Interposed by libc.so.
_dl_signal_error; _dl_catch_error;
+
+ # Set value of a tunable.
+ __tunable_set_val;
}
}
diff --git a/elf/dl-support.c b/elf/dl-support.c
index c30194c7b7..d350d6d0d0 100644
--- a/elf/dl-support.c
+++ b/elf/dl-support.c
@@ -354,8 +354,10 @@ _dl_non_dynamic_init (void)
cp = (const char *) __rawmemchr (cp, '\0') + 1;
}
+#if !HAVE_TUNABLES
if (__access ("/etc/suid-debug", F_OK) != 0)
__unsetenv ("MALLOC_CHECK_");
+#endif
}
#ifdef DL_PLATFORM_INIT
diff --git a/elf/dl-sysdep.c b/elf/dl-sysdep.c
index eaa71556d2..4283767fe0 100644
--- a/elf/dl-sysdep.c
+++ b/elf/dl-sysdep.c
@@ -44,6 +44,8 @@
#include <hp-timing.h>
#include <tls.h>
+#include <dl-tunables.h>
+
extern char **_environ attribute_hidden;
extern char _end[] attribute_hidden;
@@ -219,6 +221,8 @@ _dl_sysdep_start (void **start_argptr,
}
#endif
+ __tunables_init (_environ);
+
#ifdef DL_SYSDEP_INIT
DL_SYSDEP_INIT;
#endif
diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h
new file mode 100644
index 0000000000..d1591b6efb
--- /dev/null
+++ b/elf/dl-tunable-types.h
@@ -0,0 +1,46 @@
+/* Tunable type information.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _TUNABLE_TYPES_H_
+# define _TUNABLE_TYPES_H_
+#include <stddef.h>
+
+typedef void (*tunable_callback_t) (void *);
+
+typedef enum
+{
+ TUNABLE_TYPE_INT_32,
+ TUNABLE_TYPE_SIZE_T,
+ TUNABLE_TYPE_STRING
+} tunable_type_code_t;
+
+typedef struct
+{
+ tunable_type_code_t type_code;
+ int64_t min;
+ int64_t max;
+} tunable_type_t;
+
+typedef union
+{
+ int64_t numval;
+ const char *strval;
+} tunable_val_t;
+
+#endif
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
new file mode 100644
index 0000000000..472747b3da
--- /dev/null
+++ b/elf/dl-tunables.c
@@ -0,0 +1,320 @@
+/* The tunable framework. See the README.tunables to know how to use the
+ tunable in a glibc module.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <libc-internal.h>
+#include <sysdep.h>
+#include <fcntl.h>
+#include <ldsodefs.h>
+
+#define TUNABLES_INTERNAL 1
+#include "dl-tunables.h"
+
+/* Compare environment names, bounded by the name hardcoded in glibc. */
+static bool
+is_name (const char *orig, const char *envname)
+{
+ for (;*orig != '\0' && *envname != '\0'; envname++, orig++)
+ if (*orig != *envname)
+ break;
+
+ /* The ENVNAME is immediately followed by a value. */
+ if (*orig == '\0' && *envname == '=')
+ return true;
+ else
+ return false;
+}
+
+static char **
+get_next_env (char **envp, char **name, size_t *namelen, char **val)
+{
+ while (envp != NULL && *envp != NULL)
+ {
+ char *envline = *envp;
+ int len = 0;
+
+ while (envline[len] != '\0' && envline[len] != '=')
+ len++;
+
+ /* Just the name and no value, go to the next one. */
+ if (envline[len] == '\0')
+ continue;
+
+ *name = envline;
+ *namelen = len;
+ *val = &envline[len + 1];
+
+ return ++envp;
+ }
+
+ return NULL;
+}
+
+static int
+tunables_unsetenv (char **ep, const char *name)
+{
+ while (*ep != NULL)
+ {
+ size_t cnt = 0;
+
+ while ((*ep)[cnt] == name[cnt] && name[cnt] != '\0')
+ ++cnt;
+
+ if (name[cnt] == '\0' && (*ep)[cnt] == '=')
+ {
+ /* Found it. Remove this pointer by moving later ones to
+ the front. */
+ char **dp = ep;
+
+ do
+ dp[0] = dp[1];
+ while (*dp++);
+ /* Continue the loop in case NAME appears again. */
+ }
+ else
+ ++ep;
+ }
+
+ return 0;
+}
+
+/* A stripped down strtoul-like implementation for very early use. It does not
+ set errno if the result is outside bounds because it gets called before
+ errno may have been set up. */
+static unsigned long int
+tunables_strtoul (const char *nptr)
+{
+ unsigned long int result = 0;
+ long int sign = 1;
+ unsigned max_digit;
+
+ while (*nptr == ' ' || *nptr == '\t')
+ ++nptr;
+
+ if (*nptr == '-')
+ {
+ sign = -1;
+ ++nptr;
+ }
+ else if (*nptr == '+')
+ ++nptr;
+
+ if (*nptr < '0' || *nptr > '9')
+ return 0UL;
+
+ int base = 10;
+