[PATCHv5 23/37] x86/vdso: Add offsets page in vvar

Andy Lutomirski luto at kernel.org
Thu Aug 1 05:22:54 UTC 2019


On Mon, Jul 29, 2019 at 2:58 PM Dmitry Safonov <dima at arista.com> wrote:
>
> From: Andrei Vagin <avagin at openvz.org>
>
> As modern applications fetch time from VDSO without entering the kernel,
> it's needed to provide offsets for userspace code inside time namespace.
>
> A page for timens offsets is allocated on time namespace construction.
> Put that page into VVAR for tasks inside timens and zero page for
> host processes.
>
> As VDSO code is already optimized as much as possible in terms of speed,
> any new if-condition in VDSO code is undesirable; the goal is to provide
> two .so(s), as was originally suggested by Andy and Thomas:
> - for host tasks with optimized-out clk_to_ns() without any penalty
> - for processes inside timens with clk_to_ns()
> For this purpose, define clk_to_ns() under CONFIG_TIME_NS.
>
> To eliminate any performance regression, clk_to_ns() will be called
> under static_branch with follow-up patches, that adds support for
> patching vdso.
>
> VDSO mappings are platform-specific, add Kconfig dependency for arch.
>
> Signed-off-by: Andrei Vagin <avagin at gmail.com>
> Co-developed-by: Dmitry Safonov <dima at arista.com>
> Signed-off-by: Dmitry Safonov <dima at arista.com>
> ---
>  arch/Kconfig                          |  5 +++
>  arch/x86/Kconfig                      |  1 +
>  arch/x86/entry/vdso/vdso-layout.lds.S |  9 ++++-
>  arch/x86/entry/vdso/vdso2c.c          |  3 ++
>  arch/x86/entry/vdso/vma.c             | 12 +++++++
>  arch/x86/include/asm/vdso.h           |  1 +
>  init/Kconfig                          |  1 +
>  lib/vdso/gettimeofday.c               | 47 +++++++++++++++++++++++++++
>  8 files changed, 78 insertions(+), 1 deletion(-)
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index a7b57dd42c26..e43d27f510ec 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -729,6 +729,11 @@ config HAVE_ARCH_NVRAM_OPS
>  config ISA_BUS_API
>         def_bool ISA
>
> +config ARCH_HAS_VDSO_TIME_NS
> +       bool
> +       help
> +        VDSO can add time-ns offsets without entering kernel.
> +
>  #
>  # ABI hall of shame
>  #
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> index 222855cc0158..91615938b470 100644
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -81,6 +81,7 @@ config X86
>         select ARCH_HAS_STRICT_MODULE_RWX
>         select ARCH_HAS_SYNC_CORE_BEFORE_USERMODE
>         select ARCH_HAS_UBSAN_SANITIZE_ALL
> +       select ARCH_HAS_VDSO_TIME_NS
>         select ARCH_HAVE_NMI_SAFE_CMPXCHG
>         select ARCH_MIGHT_HAVE_ACPI_PDC         if ACPI
>         select ARCH_MIGHT_HAVE_PC_PARPORT
> diff --git a/arch/x86/entry/vdso/vdso-layout.lds.S b/arch/x86/entry/vdso/vdso-layout.lds.S
> index 93c6dc7812d0..ba216527e59f 100644
> --- a/arch/x86/entry/vdso/vdso-layout.lds.S
> +++ b/arch/x86/entry/vdso/vdso-layout.lds.S
> @@ -7,6 +7,12 @@
>   * This script controls its layout.
>   */
>
> +#ifdef CONFIG_TIME_NS
> +# define TIMENS_SZ     PAGE_SIZE
> +#else
> +# define TIMENS_SZ     0
> +#endif
> +
>  SECTIONS
>  {
>         /*
> @@ -16,7 +22,7 @@ SECTIONS
>          * segment.
>          */
>
> -       vvar_start = . - 3 * PAGE_SIZE;
> +       vvar_start = . - (3 * PAGE_SIZE + TIMENS_SZ);
>         vvar_page = vvar_start;
>
>         /* Place all vvars at the offsets in asm/vvar.h. */
> @@ -28,6 +34,7 @@ SECTIONS
>
>         pvclock_page = vvar_start + PAGE_SIZE;
>         hvclock_page = vvar_start + 2 * PAGE_SIZE;
> +       timens_page = vvar_start + 3 * PAGE_SIZE;
>
>         . = SIZEOF_HEADERS;
>
> diff --git a/arch/x86/entry/vdso/vdso2c.c b/arch/x86/entry/vdso/vdso2c.c
> index ce67370d14e5..7380908045c7 100644
> --- a/arch/x86/entry/vdso/vdso2c.c
> +++ b/arch/x86/entry/vdso/vdso2c.c
> @@ -75,12 +75,14 @@ enum {
>         sym_vvar_page,
>         sym_pvclock_page,
>         sym_hvclock_page,
> +       sym_timens_page,
>  };
>
>  const int special_pages[] = {
>         sym_vvar_page,
>         sym_pvclock_page,
>         sym_hvclock_page,
> +       sym_timens_page,
>  };
>
>  struct vdso_sym {
> @@ -93,6 +95,7 @@ struct vdso_sym required_syms[] = {
>         [sym_vvar_page] = {"vvar_page", true},
>         [sym_pvclock_page] = {"pvclock_page", true},
>         [sym_hvclock_page] = {"hvclock_page", true},
> +       [sym_timens_page] = {"timens_page", true},
>         {"VDSO32_NOTE_MASK", true},
>         {"__kernel_vsyscall", true},
>         {"__kernel_sigreturn", true},
> diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c
> index 2dc4f0b5481c..9bd66f84db5e 100644
> --- a/arch/x86/entry/vdso/vma.c
> +++ b/arch/x86/entry/vdso/vma.c
> @@ -14,6 +14,7 @@
>  #include <linux/elf.h>
>  #include <linux/cpu.h>
>  #include <linux/ptrace.h>
> +#include <linux/time_namespace.h>
>  #include <asm/pvclock.h>
>  #include <asm/vgtod.h>
>  #include <asm/proto.h>
> @@ -23,6 +24,7 @@
>  #include <asm/desc.h>
>  #include <asm/cpufeature.h>
>  #include <clocksource/hyperv_timer.h>
> +#include <asm/page.h>
>
>  #if defined(CONFIG_X86_64)
>  unsigned int __read_mostly vdso64_enabled = 1;
> @@ -135,6 +137,16 @@ static vm_fault_t vvar_fault(const struct vm_special_mapping *sm,
>                 if (tsc_pg && vclock_was_used(VCLOCK_HVCLOCK))
>                         return vmf_insert_pfn(vma, vmf->address,
>                                         vmalloc_to_pfn(tsc_pg));
> +       } else if (sym_offset == image->sym_timens_page) {
> +               struct time_namespace *ns = current->nsproxy->time_ns;

What, if anything, guarantees that all tasks in the mm share the same timens?

--Andy


More information about the Containers mailing list