linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/4] Ksplice: Rebootless kernel updates
@ 2009-02-25  0:21 Tim Abbott
  2009-02-25  0:21 ` [PATCH v2 1/4] Make section names compatible with -ffunction-sections -fdata-sections Tim Abbott
  0 siblings, 1 reply; 8+ messages in thread
From: Tim Abbott @ 2009-02-25  0:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tim Abbott, Anders Kaseorg, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

This is an updated version of the Ksplice patch series.  It applies to
Linux 2.6.29-rc5 with Rusty Russell's patch series for the module
subsystem from February 7 [0].

[0] http://lkml.org/lkml/2009/2/7/53

This patch series differs from the previous version in a few notable
ways:

(1) The Ksplice changes to the module loader have been removed from
this patch series because versions of them are already in Rusty
Russell's tree.

(2) Some of the data structures were renamed in response to
suggestions from Rusty Russell on the previous version of the patch
series

(3) The patch changing the kernel's magic section names to support
-ffunction-sections fdata-sections patch was rewritten in a cleaner
way.  I believe this new version of the patch eliminates the primary
downside associated with previous iterations of the patch (in
particular, the need to specify section flags for many sections).

A detailed changelog is available below.

==

These patches add support for Ksplice [1], a rebootless update system,
to the kernel.

[1] http://www.ksplice.com/download

Jeff Arnold first mentioned Ksplice to the LKML last April [2], and
submitted patches to the LKML last September [3], November [4], and
December [5].  The basic idea is that Ksplice can apply an update to a
running Linux kernel based only on a source code patch and the
original kernel source.  The Ksplice technical overview document [6]
describes the design of Ksplice and some of the ways that Ksplice has
been evaluated.

[2] http://lkml.org/lkml/2008/4/23/330
[3] http://lkml.org/lkml/2008/9/13/6
[4] http://lkml.org/lkml/2008/11/21/484
[5] http://lkml.org/lkml/2008/12/5/330
[6] http://www.ksplice.com/doc/ksplice.pdf

Specifically, Ksplice has been used to correct every significant Linux
kernel CVE from May 2005 to May 2008 [7].  88% of these CVEs can be
fixed without writing any new code at all; the remaining 12% of CVEs
require a minimal amount of new code (on average, roughly 20 new
semicolon-terminated lines per CVE).

[7] http://www.ksplice.com/cve-evaluation

The interface between the Ksplice kernel component and the userspace
utilities is documented in the last patch of this series.  The current
implementation of the userspace utilities is available from the
Ksplice website and the Ksplice git repository [8].  The Ksplice
userspace utilities transparently support both "integrated" operation
(updating a kernel patched with this patch series) and "standalone"
operation (updating a completely unmodified kernel).

[8] http://www.ksplice.com/git/ksplice.git

We think that merging Ksplice makes sense at this point because (1)
development on the Ksplice kernel code has stabilized and (2) the
system is useful as it currently stands.

	-Tim Abbott

Changes between v1 and v2:
- rewrote the -ffunction-sections -fdata-sections patches in a cleaner way
- rebased on top of Rusty Russell's module.c patch series for 2.6.30.
  - replaced starts_with with strstarts.
  - replaced __module_data_address with __module_address.
- renamed some data structures, as requested by Rusty Russell
  - renamed struct ksplice_pack to struct ksplice_mod_change.
  - created new struct ksplice_code, containing the symbols, relocs,
    and sections for an object file.
  - renamed helper modules to old_code modules, and primary modules to
    new_code modules.
  - renamed ksplice_module_list to ksplice_modules.
  - renamed ksplice_symbol->vals to candidate_vals
  - created new struct ksplice_hooks to organize the Ksplice hooks.
- improved Ksplice's kobject variable names.
- merged apply_patches and reverse_patches.
- added check to prevent reversing an update that has been partially
  cold-applied.
- added support for patching multi-page data structures.
- added more function-level documentation, as requested by Ted Ts'o
- bail out earlier (to give a better error message) when there are
  multiple writers to an update's stage file.

Changes between RFC v3 and v1:
- removed use of init_mm, as requested by Christoph Hellwig

Changes between RFC v2 and RFC v3:
- added taint flag, as requested by Alexey Dobriyan
- various speed optimizations
- support for replacing functions mapped read-only (CONFIG_DEBUG_RODATA)
- run-pre matching extended to bug table, ex_table, exported symbol table
- added hooks for calling custom code during the update process
- struct ksplice_export eliminated (struct ksplice_patch used instead)
- minor sysfs API changes
- added support for ksplice-apply's --partial option
- improved -ffunction-sections patches and added them to this patch series
- dropped ARM support for now, for simplicity

No changes between RFC v1 and RFC v2.

==

Jeff Arnold (1):
  Ksplice: Support updating x86-32 and x86-64

Tim Abbott (2):
  Make section names compatible with -ffunction-sections
    -fdata-sections
  Ksplice: Export symbols needed for Ksplice

Waseem Daher (1):
  x86: Add an option to compile with -ffunction-sections
    -fdata-sections

 Documentation/ksplice.txt                   |  304 +++
 Documentation/mutex-design.txt              |    4 +-
 MAINTAINERS                                 |   10 +
 Makefile                                    |    4 +
 arch/Kconfig                                |   14 +
 arch/alpha/kernel/head.S                    |    2 +-
 arch/alpha/kernel/init_task.c               |    2 +-
 arch/alpha/kernel/vmlinux.lds.S             |   14 +-
 arch/arm/kernel/head-nommu.S                |    2 +-
 arch/arm/kernel/head.S                      |    2 +-
 arch/arm/kernel/init_task.c                 |    2 +-
 arch/arm/kernel/vmlinux.lds.S               |   14 +-
 arch/arm/mm/proc-v6.S                       |    2 +-
 arch/arm/mm/proc-v7.S                       |    2 +-
 arch/arm/mm/tlb-v6.S                        |    2 +-
 arch/arm/mm/tlb-v7.S                        |    2 +-
 arch/avr32/kernel/init_task.c               |    2 +-
 arch/avr32/kernel/vmlinux.lds.S             |    6 +-
 arch/avr32/mm/init.c                        |    2 +-
 arch/blackfin/kernel/vmlinux.lds.S          |    2 +-
 arch/cris/kernel/process.c                  |    2 +-
 arch/cris/kernel/vmlinux.lds.S              |    2 +-
 arch/frv/kernel/break.S                     |    4 +-
 arch/frv/kernel/entry.S                     |    2 +-
 arch/frv/kernel/head-mmu-fr451.S            |    2 +-
 arch/frv/kernel/head-uc-fr401.S             |    2 +-
 arch/frv/kernel/head-uc-fr451.S             |    2 +-
 arch/frv/kernel/head-uc-fr555.S             |    2 +-
 arch/frv/kernel/head.S                      |    4 +-
 arch/frv/kernel/init_task.c                 |    2 +-
 arch/frv/kernel/vmlinux.lds.S               |   18 +-
 arch/frv/mm/tlb-miss.S                      |    2 +-
 arch/h8300/boot/compressed/head.S           |    2 +-
 arch/h8300/boot/compressed/vmlinux.lds      |    2 +-
 arch/h8300/kernel/init_task.c               |    2 +-
 arch/h8300/kernel/vmlinux.lds.S             |    2 +-
 arch/ia64/include/asm/asmmacro.h            |   12 +-
 arch/ia64/include/asm/cache.h               |    2 +-
 arch/ia64/include/asm/percpu.h              |    2 +-
 arch/ia64/kernel/Makefile                   |    2 +-
 arch/ia64/kernel/gate-data.S                |    2 +-
 arch/ia64/kernel/gate.S                     |    8 +-
 arch/ia64/kernel/gate.lds.S                 |   10 +-
 arch/ia64/kernel/head.S                     |    2 +-
 arch/ia64/kernel/init_task.c                |    4 +-
 arch/ia64/kernel/ivt.S                      |    2 +-
 arch/ia64/kernel/minstate.h                 |    4 +-
 arch/ia64/kernel/paravirtentry.S            |    2 +-
 arch/ia64/kernel/vmlinux.lds.S              |   48 +-
 arch/ia64/kvm/vmm_ivt.S                     |    2 +-
 arch/ia64/xen/xensetup.S                    |    2 +-
 arch/m32r/kernel/head.S                     |    2 +-
 arch/m32r/kernel/init_task.c                |    2 +-
 arch/m32r/kernel/vmlinux.lds.S              |    8 +-
 arch/m68k/kernel/head.S                     |    2 +-
 arch/m68k/kernel/process.c                  |    2 +-
 arch/m68k/kernel/sun3-head.S                |    2 +-
 arch/m68k/kernel/vmlinux-std.lds            |    6 +-
 arch/m68k/kernel/vmlinux-sun3.lds           |    4 +-
 arch/m68knommu/kernel/init_task.c           |    2 +-
 arch/m68knommu/kernel/vmlinux.lds.S         |    6 +-
 arch/m68knommu/platform/68360/head-ram.S    |    2 +-
 arch/m68knommu/platform/68360/head-rom.S    |    2 +-
 arch/mips/kernel/init_task.c                |    2 +-
 arch/mips/kernel/vmlinux.lds.S              |    8 +-
 arch/mips/lasat/image/head.S                |    2 +-
 arch/mips/lasat/image/romscript.normal      |    2 +-
 arch/mn10300/kernel/head.S                  |    2 +-
 arch/mn10300/kernel/init_task.c             |    2 +-
 arch/mn10300/kernel/vmlinux.lds.S           |   16 +-
 arch/parisc/include/asm/cache.h             |    2 +-
 arch/parisc/include/asm/system.h            |    2 +-
 arch/parisc/kernel/head.S                   |    2 +-
 arch/parisc/kernel/init_task.c              |    8 +-
 arch/parisc/kernel/vmlinux.lds.S            |   26 +-
 arch/powerpc/include/asm/cache.h            |    2 +-
 arch/powerpc/include/asm/page_64.h          |    2 +-
 arch/powerpc/include/asm/ppc_asm.h          |    4 +-
 arch/powerpc/kernel/head_32.S               |    2 +-
 arch/powerpc/kernel/head_40x.S              |    2 +-
 arch/powerpc/kernel/head_44x.S              |    2 +-
 arch/powerpc/kernel/head_8xx.S              |    2 +-
 arch/powerpc/kernel/head_fsl_booke.S        |    2 +-
 arch/powerpc/kernel/init_task.c             |    2 +-
 arch/powerpc/kernel/machine_kexec_64.c      |    2 +-
 arch/powerpc/kernel/vdso.c                  |    2 +-
 arch/powerpc/kernel/vdso32/vdso32_wrapper.S |    2 +-
 arch/powerpc/kernel/vdso64/vdso64_wrapper.S |    2 +-
 arch/powerpc/kernel/vmlinux.lds.S           |   28 +-
 arch/s390/include/asm/cache.h               |    2 +-
 arch/s390/kernel/head.S                     |    2 +-
 arch/s390/kernel/init_task.c                |    2 +-
 arch/s390/kernel/vdso.c                     |    2 +-
 arch/s390/kernel/vdso32/vdso32_wrapper.S    |    2 +-
 arch/s390/kernel/vdso64/vdso64_wrapper.S    |    2 +-
 arch/s390/kernel/vmlinux.lds.S              |   20 +-
 arch/sh/include/asm/cache.h                 |    2 +-
 arch/sh/kernel/cpu/sh5/entry.S              |    4 +-
 arch/sh/kernel/head_32.S                    |    2 +-
 arch/sh/kernel/head_64.S                    |    2 +-
 arch/sh/kernel/init_task.c                  |    2 +-
 arch/sh/kernel/irq.c                        |    4 +-
 arch/sh/kernel/vmlinux_32.lds.S             |   14 +-
 arch/sh/kernel/vmlinux_64.lds.S             |   14 +-
 arch/sparc/boot/btfixupprep.c               |    4 +-
 arch/sparc/include/asm/cache.h              |    2 +-
 arch/sparc/kernel/head_32.S                 |    4 +-
 arch/sparc/kernel/head_64.S                 |    2 +-
 arch/sparc/kernel/init_task.c               |    2 +-
 arch/sparc/kernel/vmlinux.lds.S             |   14 +-
 arch/um/include/asm/common.lds.S            |    4 +-
 arch/um/kernel/dyn.lds.S                    |    4 +-
 arch/um/kernel/init_task.c                  |    4 +-
 arch/um/kernel/uml.lds.S                    |    4 +-
 arch/x86/Kconfig                            |    2 +
 arch/x86/boot/compressed/head_32.S          |    2 +-
 arch/x86/boot/compressed/head_64.S          |    2 +-
 arch/x86/boot/compressed/relocs.c           |    2 +-
 arch/x86/boot/compressed/vmlinux.scr        |    2 +-
 arch/x86/boot/compressed/vmlinux_32.lds     |   14 +-
 arch/x86/boot/compressed/vmlinux_64.lds     |   10 +-
 arch/x86/include/asm/cache.h                |    4 +-
 arch/x86/kernel/acpi/wakeup_32.S            |    2 +-
 arch/x86/kernel/head_32.S                   |    6 +-
 arch/x86/kernel/head_64.S                   |    4 +-
 arch/x86/kernel/init_task.c                 |    4 +-
 arch/x86/kernel/ksplice-arch.c              |   96 +
 arch/x86/kernel/traps.c                     |    2 +-
 arch/x86/kernel/vmlinux_32.lds.S            |   37 +-
 arch/x86/kernel/vmlinux_64.lds.S            |   27 +-
 arch/xtensa/kernel/head.S                   |    2 +-
 arch/xtensa/kernel/init_task.c              |    2 +-
 arch/xtensa/kernel/vmlinux.lds.S            |    6 +-
 include/asm-frv/init.h                      |    8 +-
 include/asm-generic/vmlinux.lds.h           |   19 +-
 include/linux/cache.h                       |    2 +-
 include/linux/init.h                        |    8 +-
 include/linux/kernel.h                      |    1 +
 include/linux/ksplice.h                     |  224 ++
 include/linux/linkage.h                     |    4 +-
 include/linux/percpu.h                      |   10 +-
 include/linux/spinlock.h                    |    2 +-
 kernel/Makefile                             |    3 +
 kernel/extable.c                            |    3 +
 kernel/ksplice.c                            | 2995 +++++++++++++++++++++++++++
 kernel/module.c                             |    4 +-
 kernel/panic.c                              |    1 +
 kernel/sched.c                              |    1 +
 lib/Kconfig.debug                           |   18 +
 lib/bug.c                                   |    1 +
 scripts/Makefile.modpost                    |    1 +
 scripts/mod/modpost.c                       |   22 +-
 scripts/recordmcount.pl                     |    6 +-
 153 files changed, 4049 insertions(+), 350 deletions(-)
 create mode 100644 Documentation/ksplice.txt
 create mode 100644 arch/x86/kernel/ksplice-arch.c
 create mode 100644 include/linux/ksplice.h
 create mode 100644 kernel/ksplice.c


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH v2 1/4] Make section names compatible with -ffunction-sections -fdata-sections
  2009-02-25  0:21 [PATCH v2 0/4] Ksplice: Rebootless kernel updates Tim Abbott
@ 2009-02-25  0:21 ` Tim Abbott
  2009-02-25  0:21   ` [PATCH v2 2/4] x86: Add an option to compile " Tim Abbott
  0 siblings, 1 reply; 8+ messages in thread
From: Tim Abbott @ 2009-02-25  0:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tim Abbott, Anders Kaseorg, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

The purpose of this patch is to make it possible to build the kernel
with "gcc -ffunction-sections -fdata-sections".  This is a key step
towards being able to compile the kernel using the --gc-sections
linker option, which can be used to decrease the vmlinux size by
garbage collecting unused functions.  Also, Ksplice's 'run-pre
matching' process is much simpler if the original kernel was compiled
with -ffunction-sections and -fdata-sections.

Currently, the kernel uses a number of "magic" section names such as
".data.nosave" and ".text.head".

The problem is that with -ffunction-sections -fdata-sections, gcc
places code like

static void head(...) {...}

in the .text.head section, and code like

static int nosave = 1;

in the .data.nosave section, causing code to be inappropriately placed
in the "magic" sections.  This patch renames all "magic" section names
used by the kernel to use ".." rather than "." as the delimiter
between the section prefix (e.g. ".text") and suffix (e.g. "head"), so
that ".data.nosave" becomes ".data..nosave", etc.  The key property of
these names is that there are no collisions between the kernel's
"magic" sections and the sections generated by gcc's
-ffunction-sections and -fdata-sections options.  One can then
reference the sections generated by -ffunction-sections using a linker
script pattern such as *(.text.[A-Za-z$_]*)

This patch is based on an some earlier patches by Denys Vlasenko.
Those earlier patches used section names like ".kernel.text.head".
Because these names did not begin with e.g. ".text", the assembler did
not automatically use the correct section flags for them, and so one
needed to explicitly declare the sections flags when declaring a
section in assembly files using code such as:

.section .kernel.text.head, "ax", @progbits

These explicit section flags in assembly files turned out to be a
common source of confusion, and so I rewrote the patch with this new
section naming scheme suggested by Anders Kaseorg.

Signed-off-by: Tim Abbott <tabbott@mit.edu>
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 Documentation/mutex-design.txt              |    4 +-
 arch/alpha/kernel/head.S                    |    2 +-
 arch/alpha/kernel/init_task.c               |    2 +-
 arch/alpha/kernel/vmlinux.lds.S             |   14 ++++----
 arch/arm/kernel/head-nommu.S                |    2 +-
 arch/arm/kernel/head.S                      |    2 +-
 arch/arm/kernel/init_task.c                 |    2 +-
 arch/arm/kernel/vmlinux.lds.S               |   14 ++++----
 arch/arm/mm/proc-v6.S                       |    2 +-
 arch/arm/mm/proc-v7.S                       |    2 +-
 arch/arm/mm/tlb-v6.S                        |    2 +-
 arch/arm/mm/tlb-v7.S                        |    2 +-
 arch/avr32/kernel/init_task.c               |    2 +-
 arch/avr32/kernel/vmlinux.lds.S             |    6 ++--
 arch/avr32/mm/init.c                        |    2 +-
 arch/blackfin/kernel/vmlinux.lds.S          |    2 +-
 arch/cris/kernel/process.c                  |    2 +-
 arch/cris/kernel/vmlinux.lds.S              |    2 +-
 arch/frv/kernel/break.S                     |    4 +-
 arch/frv/kernel/entry.S                     |    2 +-
 arch/frv/kernel/head-mmu-fr451.S            |    2 +-
 arch/frv/kernel/head-uc-fr401.S             |    2 +-
 arch/frv/kernel/head-uc-fr451.S             |    2 +-
 arch/frv/kernel/head-uc-fr555.S             |    2 +-
 arch/frv/kernel/head.S                      |    4 +-
 arch/frv/kernel/init_task.c                 |    2 +-
 arch/frv/kernel/vmlinux.lds.S               |   18 +++++-----
 arch/frv/mm/tlb-miss.S                      |    2 +-
 arch/h8300/boot/compressed/head.S           |    2 +-
 arch/h8300/boot/compressed/vmlinux.lds      |    2 +-
 arch/h8300/kernel/init_task.c               |    2 +-
 arch/h8300/kernel/vmlinux.lds.S             |    2 +-
 arch/ia64/include/asm/asmmacro.h            |   12 +++---
 arch/ia64/include/asm/cache.h               |    2 +-
 arch/ia64/include/asm/percpu.h              |    2 +-
 arch/ia64/kernel/Makefile                   |    2 +-
 arch/ia64/kernel/gate-data.S                |    2 +-
 arch/ia64/kernel/gate.S                     |    8 ++--
 arch/ia64/kernel/gate.lds.S                 |   10 +++---
 arch/ia64/kernel/head.S                     |    2 +-
 arch/ia64/kernel/init_task.c                |    4 +-
 arch/ia64/kernel/ivt.S                      |    2 +-
 arch/ia64/kernel/minstate.h                 |    4 +-
 arch/ia64/kernel/paravirtentry.S            |    2 +-
 arch/ia64/kernel/vmlinux.lds.S              |   48 +++++++++++++-------------
 arch/ia64/kvm/vmm_ivt.S                     |    2 +-
 arch/ia64/xen/xensetup.S                    |    2 +-
 arch/m32r/kernel/head.S                     |    2 +-
 arch/m32r/kernel/init_task.c                |    2 +-
 arch/m32r/kernel/vmlinux.lds.S              |    8 ++--
 arch/m68k/kernel/head.S                     |    2 +-
 arch/m68k/kernel/process.c                  |    2 +-
 arch/m68k/kernel/sun3-head.S                |    2 +-
 arch/m68k/kernel/vmlinux-std.lds            |    6 ++--
 arch/m68k/kernel/vmlinux-sun3.lds           |    4 +-
 arch/m68knommu/kernel/init_task.c           |    2 +-
 arch/m68knommu/kernel/vmlinux.lds.S         |    6 ++--
 arch/m68knommu/platform/68360/head-ram.S    |    2 +-
 arch/m68knommu/platform/68360/head-rom.S    |    2 +-
 arch/mips/kernel/init_task.c                |    2 +-
 arch/mips/kernel/vmlinux.lds.S              |    8 ++--
 arch/mips/lasat/image/head.S                |    2 +-
 arch/mips/lasat/image/romscript.normal      |    2 +-
 arch/mn10300/kernel/head.S                  |    2 +-
 arch/mn10300/kernel/init_task.c             |    2 +-
 arch/mn10300/kernel/vmlinux.lds.S           |   16 ++++----
 arch/parisc/include/asm/cache.h             |    2 +-
 arch/parisc/include/asm/system.h            |    2 +-
 arch/parisc/kernel/head.S                   |    2 +-
 arch/parisc/kernel/init_task.c              |    8 ++--
 arch/parisc/kernel/vmlinux.lds.S            |   26 +++++++-------
 arch/powerpc/include/asm/cache.h            |    2 +-
 arch/powerpc/include/asm/page_64.h          |    2 +-
 arch/powerpc/include/asm/ppc_asm.h          |    4 +-
 arch/powerpc/kernel/head_32.S               |    2 +-
 arch/powerpc/kernel/head_40x.S              |    2 +-
 arch/powerpc/kernel/head_44x.S              |    2 +-
 arch/powerpc/kernel/head_8xx.S              |    2 +-
 arch/powerpc/kernel/head_fsl_booke.S        |    2 +-
 arch/powerpc/kernel/init_task.c             |    2 +-
 arch/powerpc/kernel/machine_kexec_64.c      |    2 +-
 arch/powerpc/kernel/vdso.c                  |    2 +-
 arch/powerpc/kernel/vdso32/vdso32_wrapper.S |    2 +-
 arch/powerpc/kernel/vdso64/vdso64_wrapper.S |    2 +-
 arch/powerpc/kernel/vmlinux.lds.S           |   28 ++++++++--------
 arch/s390/include/asm/cache.h               |    2 +-
 arch/s390/kernel/head.S                     |    2 +-
 arch/s390/kernel/init_task.c                |    2 +-
 arch/s390/kernel/vdso.c                     |    2 +-
 arch/s390/kernel/vdso32/vdso32_wrapper.S    |    2 +-
 arch/s390/kernel/vdso64/vdso64_wrapper.S    |    2 +-
 arch/s390/kernel/vmlinux.lds.S              |   20 +++++-----
 arch/sh/include/asm/cache.h                 |    2 +-
 arch/sh/kernel/cpu/sh5/entry.S              |    4 +-
 arch/sh/kernel/head_32.S                    |    2 +-
 arch/sh/kernel/head_64.S                    |    2 +-
 arch/sh/kernel/init_task.c                  |    2 +-
 arch/sh/kernel/irq.c                        |    4 +-
 arch/sh/kernel/vmlinux_32.lds.S             |   14 ++++----
 arch/sh/kernel/vmlinux_64.lds.S             |   14 ++++----
 arch/sparc/boot/btfixupprep.c               |    4 +-
 arch/sparc/include/asm/cache.h              |    2 +-
 arch/sparc/kernel/head_32.S                 |    4 +-
 arch/sparc/kernel/head_64.S                 |    2 +-
 arch/sparc/kernel/init_task.c               |    2 +-
 arch/sparc/kernel/vmlinux.lds.S             |   14 ++++----
 arch/um/include/asm/common.lds.S            |    4 +-
 arch/um/kernel/dyn.lds.S                    |    4 +-
 arch/um/kernel/init_task.c                  |    4 +-
 arch/um/kernel/uml.lds.S                    |    4 +-
 arch/x86/boot/compressed/head_32.S          |    2 +-
 arch/x86/boot/compressed/head_64.S          |    2 +-
 arch/x86/boot/compressed/relocs.c           |    2 +-
 arch/x86/boot/compressed/vmlinux.scr        |    2 +-
 arch/x86/boot/compressed/vmlinux_32.lds     |   14 +++++--
 arch/x86/boot/compressed/vmlinux_64.lds     |   10 +++--
 arch/x86/include/asm/cache.h                |    4 +-
 arch/x86/kernel/acpi/wakeup_32.S            |    2 +-
 arch/x86/kernel/head_32.S                   |    6 ++--
 arch/x86/kernel/head_64.S                   |    4 +-
 arch/x86/kernel/init_task.c                 |    4 +-
 arch/x86/kernel/traps.c                     |    2 +-
 arch/x86/kernel/vmlinux_32.lds.S            |   36 ++++++++++----------
 arch/x86/kernel/vmlinux_64.lds.S            |   26 +++++++-------
 arch/xtensa/kernel/head.S                   |    2 +-
 arch/xtensa/kernel/init_task.c              |    2 +-
 arch/xtensa/kernel/vmlinux.lds.S            |    6 ++--
 include/asm-frv/init.h                      |    8 ++--
 include/asm-generic/vmlinux.lds.h           |   14 ++++----
 include/linux/cache.h                       |    2 +-
 include/linux/init.h                        |    8 ++--
 include/linux/linkage.h                     |    4 +-
 include/linux/percpu.h                      |   10 +++---
 include/linux/spinlock.h                    |    2 +-
 kernel/module.c                             |    2 +-
 scripts/mod/modpost.c                       |   12 +++---
 scripts/recordmcount.pl                     |    6 ++--
 137 files changed, 355 insertions(+), 347 deletions(-)

diff --git a/Documentation/mutex-design.txt b/Documentation/mutex-design.txt
index aa60d1f..c91ccc0 100644
--- a/Documentation/mutex-design.txt
+++ b/Documentation/mutex-design.txt
@@ -66,14 +66,14 @@ of advantages of mutexes:
 
     c0377ccb <mutex_lock>:
     c0377ccb:       f0 ff 08                lock decl (%eax)
-    c0377cce:       78 0e                   js     c0377cde <.text.lock.mutex>
+    c0377cce:       78 0e                   js     c0377cde <.text..lock.mutex>
     c0377cd0:       c3                      ret
 
    the unlocking fastpath is equally tight:
 
     c0377cd1 <mutex_unlock>:
     c0377cd1:       f0 ff 00                lock incl (%eax)
-    c0377cd4:       7e 0f                   jle    c0377ce5 <.text.lock.mutex+0x7>
+    c0377cd4:       7e 0f                   jle    c0377ce5 <.text..lock.mutex+0x7>
     c0377cd6:       c3                      ret
 
  - 'struct mutex' semantics are well-defined and are enforced if
diff --git a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S
index 7ac1f13..16293d4 100644
--- a/arch/alpha/kernel/head.S
+++ b/arch/alpha/kernel/head.S
@@ -10,7 +10,7 @@
 #include <asm/system.h>
 #include <asm/asm-offsets.h>
 
-.section .text.head, "ax"
+.section .text..head, "ax"
 .globl swapper_pg_dir
 .globl _stext
 swapper_pg_dir=SWAPPER_PGD
diff --git a/arch/alpha/kernel/init_task.c b/arch/alpha/kernel/init_task.c
index c2938e5..7929755 100644
--- a/arch/alpha/kernel/init_task.c
+++ b/arch/alpha/kernel/init_task.c
@@ -17,5 +17,5 @@ EXPORT_SYMBOL(init_mm);
 EXPORT_SYMBOL(init_task);
 
 union thread_union init_thread_union
-	__attribute__((section(".data.init_thread")))
+	__attribute__((section(".data..init_thread")))
 	= { INIT_THREAD_INFO(init_task) };
diff --git a/arch/alpha/kernel/vmlinux.lds.S b/arch/alpha/kernel/vmlinux.lds.S
index ef37fc1..511f8ca 100644
--- a/arch/alpha/kernel/vmlinux.lds.S
+++ b/arch/alpha/kernel/vmlinux.lds.S
@@ -16,7 +16,7 @@ SECTIONS
 
 	_text = .;	/* Text and read-only data */
 	.text : {
-	*(.text.head)
+	*(.text..head)
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
@@ -93,18 +93,18 @@ SECTIONS
 	/* Freed after init ends here */
 
 	/* Note 2 page alignment above.  */
-	.data.init_thread : {
-		*(.data.init_thread)
+	.data..init_thread : {
+		*(.data..init_thread)
 	}
 
 	. = ALIGN(PAGE_SIZE);
-	.data.page_aligned : {
-		*(.data.page_aligned)
+	.data..page_aligned : {
+		*(.data..page_aligned)
 	}
 
 	. = ALIGN(64);
-	.data.cacheline_aligned : {
-		*(.data.cacheline_aligned)
+	.data..cacheline_aligned : {
+		*(.data..cacheline_aligned)
 	}
 
 	_data = .;
diff --git a/arch/arm/kernel/head-nommu.S b/arch/arm/kernel/head-nommu.S
index cc87e17..fcd93f5 100644
--- a/arch/arm/kernel/head-nommu.S
+++ b/arch/arm/kernel/head-nommu.S
@@ -32,7 +32,7 @@
  * numbers for r1.
  *
  */
-	.section ".text.head", "ax"
+	.section ".text..head", "ax"
 ENTRY(stext)
 	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
 						@ and irqs disabled
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 21e17dc..705e759 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -74,7 +74,7 @@
  * crap here - that's what the boot loader (or in extreme, well justified
  * circumstances, zImage) is for.
  */
-	.section ".text.head", "ax"
+	.section ".text..head", "ax"
 ENTRY(stext)
 	msr	cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE @ ensure svc mode
 						@ and irqs disabled
diff --git a/arch/arm/kernel/init_task.c b/arch/arm/kernel/init_task.c
index e859af3..0b81b8f 100644
--- a/arch/arm/kernel/init_task.c
+++ b/arch/arm/kernel/init_task.c
@@ -29,7 +29,7 @@ EXPORT_SYMBOL(init_mm);
  * The things we do for performance..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 0021607..4ec9516 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -23,10 +23,10 @@ SECTIONS
 #else
 	. = PAGE_OFFSET + TEXT_OFFSET;
 #endif
-	.text.head : {
+	.text..head : {
 		_stext = .;
 		_sinittext = .;
-		*(.text.head)
+		*(.text..head)
 	}
 
 	.init : {			/* Init code and data		*/
@@ -65,8 +65,8 @@ SECTIONS
 #endif
 		. = ALIGN(4096);
 		__per_cpu_start = .;
-			*(.data.percpu)
-			*(.data.percpu.shared_aligned)
+			*(.data..percpu)
+			*(.data..percpu.shared_aligned)
 		__per_cpu_end = .;
 #ifndef CONFIG_XIP_KERNEL
 		__init_begin = _stext;
@@ -125,7 +125,7 @@ SECTIONS
 		 * first, the init task union, aligned
 		 * to an 8192 byte boundary.
 		 */
-		*(.data.init_task)
+		*(.data..init_task)
 
 #ifdef CONFIG_XIP_KERNEL
 		. = ALIGN(4096);
@@ -137,7 +137,7 @@ SECTIONS
 
 		. = ALIGN(4096);
 		__nosave_begin = .;
-		*(.data.nosave)
+		*(.data..nosave)
 		. = ALIGN(4096);
 		__nosave_end = .;
 
@@ -145,7 +145,7 @@ SECTIONS
 		 * then the cacheline aligned data
 		 */
 		. = ALIGN(32);
-		*(.data.cacheline_aligned)
+		*(.data..cacheline_aligned)
 
 		/*
 		 * The exception fixup table (might need resorting at runtime)
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index f0cc599..39d8dd1 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -132,7 +132,7 @@ cpu_v6_name:
 	.asciz	"ARMv6-compatible processor"
 	.align
 
-	.section ".text.init", #alloc, #execinstr
+	.section ".text..init", #alloc, #execinstr
 
 /*
  *	__v6_setup
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index d1ebec4..f03c14c 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -153,7 +153,7 @@ cpu_v7_name:
 	.ascii	"ARMv7 Processor"
 	.align
 
-	.section ".text.init", #alloc, #execinstr
+	.section ".text..init", #alloc, #execinstr
 
 /*
  *	__v7_setup
diff --git a/arch/arm/mm/tlb-v6.S b/arch/arm/mm/tlb-v6.S
index 20f84bb..7e9a62a 100644
--- a/arch/arm/mm/tlb-v6.S
+++ b/arch/arm/mm/tlb-v6.S
@@ -87,7 +87,7 @@ ENTRY(v6wbi_flush_kern_tlb_range)
 	mcr	p15, 0, r2, c7, c5, 4		@ prefetch flush
 	mov	pc, lr
 
-	.section ".text.init", #alloc, #execinstr
+	.section ".text..init", #alloc, #execinstr
 
 	.type	v6wbi_tlb_fns, #object
 ENTRY(v6wbi_tlb_fns)
diff --git a/arch/arm/mm/tlb-v7.S b/arch/arm/mm/tlb-v7.S
index 24ba510..875a0bd 100644
--- a/arch/arm/mm/tlb-v7.S
+++ b/arch/arm/mm/tlb-v7.S
@@ -80,7 +80,7 @@ ENTRY(v7wbi_flush_kern_tlb_range)
 	mov	pc, lr
 ENDPROC(v7wbi_flush_kern_tlb_range)
 
-	.section ".text.init", #alloc, #execinstr
+	.section ".text..init", #alloc, #execinstr
 
 	.type	v7wbi_tlb_fns, #object
 ENTRY(v7wbi_tlb_fns)
diff --git a/arch/avr32/kernel/init_task.c b/arch/avr32/kernel/init_task.c
index 993d56e..4678bc6 100644
--- a/arch/avr32/kernel/init_task.c
+++ b/arch/avr32/kernel/init_task.c
@@ -23,7 +23,7 @@ EXPORT_SYMBOL(init_mm);
  * Initial thread structure. Must be aligned on an 8192-byte boundary.
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/avr32/kernel/vmlinux.lds.S b/arch/avr32/kernel/vmlinux.lds.S
index 7910d41..5e73a02 100644
--- a/arch/avr32/kernel/vmlinux.lds.S
+++ b/arch/avr32/kernel/vmlinux.lds.S
@@ -95,15 +95,15 @@ SECTIONS
 		/*
 		 * First, the init task union, aligned to an 8K boundary.
 		 */
-		*(.data.init_task)
+		*(.data..init_task)
 
 		/* Then, the page-aligned data */
 		. = ALIGN(PAGE_SIZE);
-		*(.data.page_aligned)
+		*(.data..page_aligned)
 
 		/* Then, the cacheline aligned data */
 		. = ALIGN(L1_CACHE_BYTES);
-		*(.data.cacheline_aligned)
+		*(.data..cacheline_aligned)
 
 		/* And the rest... */
 		*(.data.rel*)
diff --git a/arch/avr32/mm/init.c b/arch/avr32/mm/init.c
index e819fa6..533a011 100644
--- a/arch/avr32/mm/init.c
+++ b/arch/avr32/mm/init.c
@@ -24,7 +24,7 @@
 #include <asm/setup.h>
 #include <asm/sections.h>
 
-#define __page_aligned	__attribute__((section(".data.page_aligned")))
+#define __page_aligned	__attribute__((section(".data..page_aligned")))
 
 DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
 
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S
index 4b4341d..027ff23 100644
--- a/arch/blackfin/kernel/vmlinux.lds.S
+++ b/arch/blackfin/kernel/vmlinux.lds.S
@@ -94,7 +94,7 @@ SECTIONS
 		__sdata = .;
 		/* This gets done first, so the glob doesn't suck it in */
 		. = ALIGN(32);
-		*(.data.cacheline_aligned)
+		*(.data..cacheline_aligned)
 
 #if !L1_DATA_A_LENGTH
 		. = ALIGN(32);
diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c
index 60816e8..d31e27e 100644
--- a/arch/cris/kernel/process.c
+++ b/arch/cris/kernel/process.c
@@ -51,7 +51,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union 
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/cris/kernel/vmlinux.lds.S b/arch/cris/kernel/vmlinux.lds.S
index 0d2adfc..f603bc8 100644
--- a/arch/cris/kernel/vmlinux.lds.S
+++ b/arch/cris/kernel/vmlinux.lds.S
@@ -68,7 +68,7 @@ SECTIONS
 	_edata = . ;
 
 	. = ALIGN(PAGE_SIZE);	/* init_task and stack, must be aligned. */
-	.data.init_task : { *(.data.init_task) }
+	.data..init_task : { *(.data..init_task) }
 
 	. = ALIGN(PAGE_SIZE);		/* Init code and data. */
 	__init_begin = .;
diff --git a/arch/frv/kernel/break.S b/arch/frv/kernel/break.S
index bd0bdf9..cbb6958 100644
--- a/arch/frv/kernel/break.S
+++ b/arch/frv/kernel/break.S
@@ -21,7 +21,7 @@
 #
 # the break handler has its own stack
 #
-	.section	.bss.stack
+	.section	.bss..stack
 	.globl		__break_user_context
 	.balign		THREAD_SIZE
 __break_stack:
@@ -63,7 +63,7 @@ __break_trace_through_exceptions:
 # entry point for Break Exceptions/Interrupts
 #
 ###############################################################################
-	.section	.text.break
+	.section	.text..break
 	.balign		4
 	.globl		__entry_break
 __entry_break:
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index 99060ab..fe5479b 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -38,7 +38,7 @@
 
 #define nr_syscalls ((syscall_table_size)/4)
 
-	.section	.text.entry
+	.section	.text..entry
 	.balign		4
 
 .macro LEDS val
diff --git a/arch/frv/kernel/head-mmu-fr451.S b/arch/frv/kernel/head-mmu-fr451.S
index c8f210d..5900967 100644
--- a/arch/frv/kernel/head-mmu-fr451.S
+++ b/arch/frv/kernel/head-mmu-fr451.S
@@ -31,7 +31,7 @@
 #define __400_LCR	0xfe000100
 #define __400_LSBR	0xfe000c00
 
-	.section	.text.init,"ax"
+	.section	.text..init,"ax"
 	.balign		4
 
 ###############################################################################
diff --git a/arch/frv/kernel/head-uc-fr401.S b/arch/frv/kernel/head-uc-fr401.S
index ee282be..ecba176 100644
--- a/arch/frv/kernel/head-uc-fr401.S
+++ b/arch/frv/kernel/head-uc-fr401.S
@@ -30,7 +30,7 @@
 #define __400_LCR	0xfe000100
 #define __400_LSBR	0xfe000c00
 
-	.section	.text.init,"ax"
+	.section	.text..init,"ax"
 	.balign		4
 
 ###############################################################################
diff --git a/arch/frv/kernel/head-uc-fr451.S b/arch/frv/kernel/head-uc-fr451.S
index b10d9c8..ed9dd17 100644
--- a/arch/frv/kernel/head-uc-fr451.S
+++ b/arch/frv/kernel/head-uc-fr451.S
@@ -30,7 +30,7 @@
 #define __400_LCR	0xfe000100
 #define __400_LSBR	0xfe000c00
 
-	.section	.text.init,"ax"
+	.section	.text..init,"ax"
 	.balign		4
 
 ###############################################################################
diff --git a/arch/frv/kernel/head-uc-fr555.S b/arch/frv/kernel/head-uc-fr555.S
index 39937c1..ee46b0b 100644
--- a/arch/frv/kernel/head-uc-fr555.S
+++ b/arch/frv/kernel/head-uc-fr555.S
@@ -29,7 +29,7 @@
 #define __551_LCR	0xfeff1100
 #define __551_LSBR	0xfeff1c00
 
-	.section	.text.init,"ax"
+	.section	.text..init,"ax"
 	.balign		4
 
 ###############################################################################
diff --git a/arch/frv/kernel/head.S b/arch/frv/kernel/head.S
index fecf751..35e6391 100644
--- a/arch/frv/kernel/head.S
+++ b/arch/frv/kernel/head.S
@@ -27,7 +27,7 @@
 #   command line string
 #
 ###############################################################################
-	.section	.text.head,"ax"
+	.section	.text..head,"ax"
 	.balign		4
 
 	.globl		_boot, __head_reference
@@ -541,7 +541,7 @@ __head_end:
 	.size		_boot, .-_boot
 
 	# provide a point for GDB to place a break
-	.section	.text.start,"ax"
+	.section	.text..start,"ax"
 	.globl		_start
 	.balign		4
 _start:
diff --git a/arch/frv/kernel/init_task.c b/arch/frv/kernel/init_task.c
index 29429a8..f57ec19 100644
--- a/arch/frv/kernel/init_task.c
+++ b/arch/frv/kernel/init_task.c
@@ -24,7 +24,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/frv/kernel/vmlinux.lds.S b/arch/frv/kernel/vmlinux.lds.S
index b95c4ea..a7bcf9b 100644
--- a/arch/frv/kernel/vmlinux.lds.S
+++ b/arch/frv/kernel/vmlinux.lds.S
@@ -26,7 +26,7 @@ SECTIONS
 
   _sinittext = .;
   .init.text : {
-	*(.text.head)
+	*(.text..head)
 #ifndef CONFIG_DEBUG_INFO
 	INIT_TEXT
 	EXIT_TEXT
@@ -71,13 +71,13 @@ SECTIONS
 
   /* put sections together that have massive alignment issues */
   . = ALIGN(THREAD_SIZE);
-  .data.init_task : {
+  .data..init_task : {
 	  /* init task record & stack */
-	  *(.data.init_task)
+	  *(.data..init_task)
   }
 
   . = ALIGN(L1_CACHE_BYTES);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  .data..cacheline_aligned : { *(.data..cacheline_aligned) }
 
   .trap : {
 	/* trap table management - read entry-table.S before modifying */
@@ -94,10 +94,10 @@ SECTIONS
   _text = .;
   _stext = .;
   .text : {
-	*(.text.start)
-	*(.text.entry)
-	*(.text.break)
-	*(.text.tlbmiss)
+	*(.text..start)
+	*(.text..entry)
+	*(.text..break)
+	*(.text..tlbmiss)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
@@ -152,7 +152,7 @@ SECTIONS
 
   .sbss		: { *(.sbss .sbss.*) }
   .bss		: { *(.bss .bss.*) }
-  .bss.stack	: { *(.bss) }
+  .bss..stack	: { *(.bss) }
 
   __bss_stop = .;
   _end = . ;
diff --git a/arch/frv/mm/tlb-miss.S b/arch/frv/mm/tlb-miss.S
index 0764348..0f41b41 100644
--- a/arch/frv/mm/tlb-miss.S
+++ b/arch/frv/mm/tlb-miss.S
@@ -16,7 +16,7 @@
 #include <asm/highmem.h>
 #include <asm/spr-regs.h>
 
-	.section	.text.tlbmiss
+	.section	.text..tlbmiss
 	.balign		4
 
 	.globl		__entry_insn_mmu_miss
diff --git a/arch/h8300/boot/compressed/head.S b/arch/h8300/boot/compressed/head.S
index 985a81a..10e9a2d 100644
--- a/arch/h8300/boot/compressed/head.S
+++ b/arch/h8300/boot/compressed/head.S
@@ -9,7 +9,7 @@
 
 #define SRAM_START 0xff4000
 
-	.section	.text.startup
+	.section	.text..startup
 	.global	startup
 startup:
 	mov.l	#SRAM_START+0x8000, sp
diff --git a/arch/h8300/boot/compressed/vmlinux.lds b/arch/h8300/boot/compressed/vmlinux.lds
index 65e2a0d..a0a3a0e 100644
--- a/arch/h8300/boot/compressed/vmlinux.lds
+++ b/arch/h8300/boot/compressed/vmlinux.lds
@@ -4,7 +4,7 @@ SECTIONS
         {
         __stext = . ;
 	__text = .;
-	       *(.text.startup)
+	       *(.text..startup)
 	       *(.text)
         __etext = . ;
         }
diff --git a/arch/h8300/kernel/init_task.c b/arch/h8300/kernel/init_task.c
index cb5dc55..fb473b1 100644
--- a/arch/h8300/kernel/init_task.c
+++ b/arch/h8300/kernel/init_task.c
@@ -36,6 +36,6 @@ EXPORT_SYMBOL(init_task);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
diff --git a/arch/h8300/kernel/vmlinux.lds.S b/arch/h8300/kernel/vmlinux.lds.S
index 43a87b9..c0e3635 100644
--- a/arch/h8300/kernel/vmlinux.lds.S
+++ b/arch/h8300/kernel/vmlinux.lds.S
@@ -101,7 +101,7 @@ SECTIONS
 	___data_start = . ;
 
 	. = ALIGN(0x2000) ;
-		*(.data.init_task)
+		*(.data..init_task)
 	. = ALIGN(0x4) ;
 		DATA_DATA
 	. = ALIGN(0x4) ;
diff --git a/arch/ia64/include/asm/asmmacro.h b/arch/ia64/include/asm/asmmacro.h
index c1642fd..3ab6d75 100644
--- a/arch/ia64/include/asm/asmmacro.h
+++ b/arch/ia64/include/asm/asmmacro.h
@@ -70,12 +70,12 @@ name:
  * path (ivt.S - TLB miss processing) or in places where it might not be
  * safe to use a "tpa" instruction (mca_asm.S - error recovery).
  */
-	.section ".data.patch.vtop", "a"	// declare section & section attributes
+	.section ".data..patch.vtop", "a"	// declare section & section attributes
 	.previous
 
 #define	LOAD_PHYSICAL(pr, reg, obj)		\
 [1:](pr)movl reg = obj;				\
-	.xdata4 ".data.patch.vtop", 1b-.
+	.xdata4 ".data..patch.vtop", 1b-.
 
 /*
  * For now, we always put in the McKinley E9 workaround.  On CPUs that don't need it,
@@ -84,11 +84,11 @@ name:
 #define DO_MCKINLEY_E9_WORKAROUND
 
 #ifdef DO_MCKINLEY_E9_WORKAROUND
-	.section ".data.patch.mckinley_e9", "a"
+	.section ".data..patch.mckinley_e9", "a"
 	.previous
 /* workaround for Itanium 2 Errata 9: */
 # define FSYS_RETURN					\
-	.xdata4 ".data.patch.mckinley_e9", 1f-.;	\
+	.xdata4 ".data..patch.mckinley_e9", 1f-.;	\
 1:{ .mib;						\
 	nop.m 0;					\
 	mov r16=ar.pfs;					\
@@ -107,11 +107,11 @@ name:
  * If physical stack register size is different from DEF_NUM_STACK_REG,
  * dynamically patch the kernel for correct size.
  */
-	.section ".data.patch.phys_stack_reg", "a"
+	.section ".data..patch.phys_stack_reg", "a"
 	.previous
 #define LOAD_PHYS_STACK_REG_SIZE(reg)			\
 [1:]	adds reg=IA64_NUM_PHYS_STACK_REG*8+8,r0;	\
-	.xdata4 ".data.patch.phys_stack_reg", 1b-.
+	.xdata4 ".data..patch.phys_stack_reg", 1b-.
 
 /*
  * Up until early 2004, use of .align within a function caused bad unwind info.
diff --git a/arch/ia64/include/asm/cache.h b/arch/ia64/include/asm/cache.h
index e7482bd..988254a 100644
--- a/arch/ia64/include/asm/cache.h
+++ b/arch/ia64/include/asm/cache.h
@@ -24,6 +24,6 @@
 # define SMP_CACHE_BYTES	(1 << 3)
 #endif
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #endif /* _ASM_IA64_CACHE_H */
diff --git a/arch/ia64/include/asm/percpu.h b/arch/ia64/include/asm/percpu.h
index 77f30b6..d9ec30b 100644
--- a/arch/ia64/include/asm/percpu.h
+++ b/arch/ia64/include/asm/percpu.h
@@ -27,7 +27,7 @@ extern void *per_cpu_init(void);
 
 #else /* ! SMP */
 
-#define PER_CPU_ATTRIBUTES	__attribute__((__section__(".data.percpu")))
+#define PER_CPU_ATTRIBUTES	__attribute__((__section__(".data..percpu")))
 
 #define per_cpu_init()				(__phys_per_cpu_start)
 
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index c381ea9..61900c7 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -72,7 +72,7 @@ GATECFLAGS_gate-syms.o = -r
 $(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE
 	$(call if_changed,gate)
 
-# gate-data.o contains the gate DSO image as data in section .data.gate.
+# gate-data.o contains the gate DSO image as data in section .data..gate.
 # We must build gate.so before we can assemble it.
 # Note: kbuild does not track this dependency due to usage of .incbin
 $(obj)/gate-data.o: $(obj)/gate.so
diff --git a/arch/ia64/kernel/gate-data.S b/arch/ia64/kernel/gate-data.S
index 258c0a3..b3ef1c7 100644
--- a/arch/ia64/kernel/gate-data.S
+++ b/arch/ia64/kernel/gate-data.S
@@ -1,3 +1,3 @@
-	.section .data.gate, "aw"
+	.section .data..gate, "aw"
 
 	.incbin "arch/ia64/kernel/gate.so"
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index 74b1ccc..8ecaf37 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -20,18 +20,18 @@
  * to targets outside the shared object) and to avoid multi-phase kernel builds, we
  * simply create minimalistic "patch lists" in special ELF sections.
  */
-	.section ".data.patch.fsyscall_table", "a"
+	.section ".data..patch.fsyscall_table", "a"
 	.previous
 #define LOAD_FSYSCALL_TABLE(reg)			\
 [1:]	movl reg=0;					\
-	.xdata4 ".data.patch.fsyscall_table", 1b-.
+	.xdata4 ".data..patch.fsyscall_table", 1b-.
 
-	.section ".data.patch.brl_fsys_bubble_down", "a"
+	.section ".data..patch.brl_fsys_bubble_down", "a"
 	.previous
 #define BRL_COND_FSYS_BUBBLE_DOWN(pr)			\
 [1:](pr)brl.cond.sptk 0;				\
 	;;						\
-	.xdata4 ".data.patch.brl_fsys_bubble_down", 1b-.
+	.xdata4 ".data..patch.brl_fsys_bubble_down", 1b-.
 
 GLOBAL_ENTRY(__kernel_syscall_via_break)
 	.prologue
diff --git a/arch/ia64/kernel/gate.lds.S b/arch/ia64/kernel/gate.lds.S
index 3cb1abc..9ef2444 100644
--- a/arch/ia64/kernel/gate.lds.S
+++ b/arch/ia64/kernel/gate.lds.S
@@ -32,21 +32,21 @@ SECTIONS
 	 */
 	. = GATE_ADDR + 0x600;
 
-	.data.patch		: {
+	.data..patch		: {
 		__start_gate_mckinley_e9_patchlist = .;
-		*(.data.patch.mckinley_e9)
+		*(.data..patch.mckinley_e9)
 		__end_gate_mckinley_e9_patchlist = .;
 
 		__start_gate_vtop_patchlist = .;
-		*(.data.patch.vtop)
+		*(.data..patch.vtop)
 		__end_gate_vtop_patchlist = .;
 
 		__start_gate_fsyscall_patchlist = .;
-		*(.data.patch.fsyscall_table)
+		*(.data..patch.fsyscall_table)
 		__end_gate_fsyscall_patchlist = .;
 
 		__start_gate_brl_fsys_bubble_down_patchlist = .;
-		*(.data.patch.brl_fsys_bubble_down)
+		*(.data..patch.brl_fsys_bubble_down)
 		__end_gate_brl_fsys_bubble_down_patchlist = .;
 	}						:readable
 
diff --git a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
index 59301c4..3617aaf 100644
--- a/arch/ia64/kernel/head.S
+++ b/arch/ia64/kernel/head.S
@@ -181,7 +181,7 @@ swapper_pg_dir:
 halt_msg:
 	stringz "Halting kernel\n"
 
-	.section .text.head,"ax"
+	.section .text..head,"ax"
 
 	.global start_ap
 
diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c
index 5b0e830..8a5028c 100644
--- a/arch/ia64/kernel/init_task.c
+++ b/arch/ia64/kernel/init_task.c
@@ -27,7 +27,7 @@ EXPORT_SYMBOL(init_mm);
  * Initial task structure.
  *
  * We need to make sure that this is properly aligned due to the way process stacks are
- * handled. This is done by having a special ".data.init_task" section...
+ * handled. This is done by having a special ".data..init_task" section...
  */
 #define init_thread_info	init_task_mem.s.thread_info
 
@@ -37,7 +37,7 @@ union {
 		struct thread_info thread_info;
 	} s;
 	unsigned long stack[KERNEL_STACK_SIZE/sizeof (unsigned long)];
-} init_task_mem asm ("init_task") __attribute__((section(".data.init_task"))) = {{
+} init_task_mem asm ("init_task") __attribute__((section(".data..init_task"))) = {{
 	.task =		INIT_TASK(init_task_mem.s.task),
 	.thread_info =	INIT_THREAD_INFO(init_task_mem.s.task)
 }};
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index f675d8e..7214046 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -83,7 +83,7 @@
 	mov r19=n;;			/* prepare to save predicates */		\
 	br.sptk.many dispatch_to_fault_handler
 
-	.section .text.ivt,"ax"
+	.section .text..ivt,"ax"
 
 	.align 32768	// align on 32KB boundary
 	.global ia64_ivt
diff --git a/arch/ia64/kernel/minstate.h b/arch/ia64/kernel/minstate.h
index 292e214..d56753a 100644
--- a/arch/ia64/kernel/minstate.h
+++ b/arch/ia64/kernel/minstate.h
@@ -16,7 +16,7 @@
 #define ACCOUNT_SYS_ENTER
 #endif
 
-.section ".data.patch.rse", "a"
+.section ".data..patch.rse", "a"
 .previous
 
 /*
@@ -215,7 +215,7 @@
 (pUStk) extr.u r17=r18,3,6;			\
 (pUStk)	sub r16=r18,r22;			\
 [1:](pKStk)	br.cond.sptk.many 1f;		\
-	.xdata4 ".data.patch.rse",1b-.		\
+	.xdata4 ".data..patch.rse",1b-.		\
 	;;					\
 	cmp.ge p6,p7 = 33,r17;			\
 	;;					\
diff --git a/arch/ia64/kernel/paravirtentry.S b/arch/ia64/kernel/paravirtentry.S
index 2f42fcb..d778e8b 100644
--- a/arch/ia64/kernel/paravirtentry.S
+++ b/arch/ia64/kernel/paravirtentry.S
@@ -25,7 +25,7 @@
 #include "entry.h"
 
 #define DATA8(sym, init_value)			\
-	.pushsection .data.read_mostly ;	\
+	.pushsection .data..read_mostly ;	\
 	.align 8 ;				\
 	.global sym ;				\
 	sym: ;					\
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index 10a7d47..1596906 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -8,7 +8,7 @@
 
 #define IVT_TEXT							\
 		VMLINUX_SYMBOL(__start_ivt_text) = .;			\
-		*(.text.ivt)						\
+		*(.text..ivt)						\
 		VMLINUX_SYMBOL(__end_ivt_text) = .;
 
 OUTPUT_FORMAT("elf64-ia64-little")
@@ -51,13 +51,13 @@ SECTIONS
 	KPROBES_TEXT
 	*(.gnu.linkonce.t*)
     }
-  .text.head : AT(ADDR(.text.head) - LOAD_OFFSET)
-	{ *(.text.head) }
+  .text..head : AT(ADDR(.text..head) - LOAD_OFFSET)
+	{ *(.text..head) }
   .text2 : AT(ADDR(.text2) - LOAD_OFFSET)
 	{ *(.text2) }
 #ifdef CONFIG_SMP
-  .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET)
-	{ *(.text.lock) }
+  .text..lock : AT(ADDR(.text..lock) - LOAD_OFFSET)
+	{ *(.text..lock) }
 #endif
   _etext = .;
 
@@ -84,10 +84,10 @@ SECTIONS
 	  __stop___mca_table = .;
 	}
 
-  .data.patch.phys_stack_reg : AT(ADDR(.data.patch.phys_stack_reg) - LOAD_OFFSET)
+  .data..patch.phys_stack_reg : AT(ADDR(.data..patch.phys_stack_reg) - LOAD_OFFSET)
 	{
 	  __start___phys_stack_reg_patchlist = .;
-	  *(.data.patch.phys_stack_reg)
+	  *(.data..patch.phys_stack_reg)
 	  __end___phys_stack_reg_patchlist = .;
 	}
 
@@ -148,24 +148,24 @@ SECTIONS
 	  __initcall_end = .;
 	}
 
-  .data.patch.vtop : AT(ADDR(.data.patch.vtop) - LOAD_OFFSET)
+  .data..patch.vtop : AT(ADDR(.data..patch.vtop) - LOAD_OFFSET)
 	{
 	  __start___vtop_patchlist = .;
-	  *(.data.patch.vtop)
+	  *(.data..patch.vtop)
 	  __end___vtop_patchlist = .;
 	}
 
-  .data.patch.rse : AT(ADDR(.data.patch.rse) - LOAD_OFFSET)
+  .data..patch.rse : AT(ADDR(.data..patch.rse) - LOAD_OFFSET)
 	{
 	  __start___rse_patchlist = .;
-	  *(.data.patch.rse)
+	  *(.data..patch.rse)
 	  __end___rse_patchlist = .;
 	}
 
-  .data.patch.mckinley_e9 : AT(ADDR(.data.patch.mckinley_e9) - LOAD_OFFSET)
+  .data..patch.mckinley_e9 : AT(ADDR(.data..patch.mckinley_e9) - LOAD_OFFSET)
 	{
 	  __start___mckinley_e9_bundles = .;
-	  *(.data.patch.mckinley_e9)
+	  *(.data..patch.mckinley_e9)
 	  __end___mckinley_e9_bundles = .;
 	}
 
@@ -193,34 +193,34 @@ SECTIONS
   __init_end = .;
 
   /* The initial task and kernel stack */
-  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET)
-	{ *(.data.init_task) }
+  .data..init_task : AT(ADDR(.data..init_task) - LOAD_OFFSET)
+	{ *(.data..init_task) }
 
-  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET)
+  .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET)
         { *(__special_page_section)
 	  __start_gate_section = .;
-	  *(.data.gate)
+	  *(.data..gate)
 	  __stop_gate_section = .;
 	}
   . = ALIGN(PAGE_SIZE);		/* make sure the gate page doesn't expose
   				 * kernel data
 				 */
 
-  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET)
-        { *(.data.read_mostly) }
+  .data..read_mostly : AT(ADDR(.data..read_mostly) - LOAD_OFFSET)
+        { *(.data..read_mostly) }
 
-  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET)
-        { *(.data.cacheline_aligned) }
+  .data..cacheline_aligned : AT(ADDR(.data..cacheline_aligned) - LOAD_OFFSET)
+        { *(.data..cacheline_aligned) }
 
   /* Per-cpu data: */
   percpu : { } :percpu
   . = ALIGN(PERCPU_PAGE_SIZE);
   __phys_per_cpu_start = .;
-  .data.percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET)
+  .data..percpu PERCPU_ADDR : AT(__phys_per_cpu_start - LOAD_OFFSET)
 	{
 		__per_cpu_start = .;
-		*(.data.percpu)
-		*(.data.percpu.shared_aligned)
+		*(.data..percpu)
+		*(.data..percpu.shared_aligned)
 		__per_cpu_end = .;
 	}
   . = __phys_per_cpu_start + PERCPU_PAGE_SIZE;	/* ensure percpu data fits
diff --git a/arch/ia64/kvm/vmm_ivt.S b/arch/ia64/kvm/vmm_ivt.S
index 3ef1a01..c5ab23b 100644
--- a/arch/ia64/kvm/vmm_ivt.S
+++ b/arch/ia64/kvm/vmm_ivt.S
@@ -104,7 +104,7 @@ GLOBAL_ENTRY(kvm_vmm_panic)
 	br.call.sptk.many b6=vmm_panic_handler;
 END(kvm_vmm_panic)
 
-    .section .text.ivt,"ax"
+    .section .text..ivt,"ax"
 
     .align 32768    // align on 32KB boundary
     .global kvm_ia64_ivt
diff --git a/arch/ia64/xen/xensetup.S b/arch/ia64/xen/xensetup.S
index 28fed1f..28def53 100644
--- a/arch/ia64/xen/xensetup.S
+++ b/arch/ia64/xen/xensetup.S
@@ -14,7 +14,7 @@
 #include <linux/init.h>
 #include <xen/interface/elfnote.h>
 
-	.section .data.read_mostly
+	.section .data..read_mostly
 	.align 8
 	.global xen_domain_type
 xen_domain_type:
diff --git a/arch/m32r/kernel/head.S b/arch/m32r/kernel/head.S
index 9091606..2bac669 100644
--- a/arch/m32r/kernel/head.S
+++ b/arch/m32r/kernel/head.S
@@ -23,7 +23,7 @@ __INITDATA
 /*
  * References to members of the boot_cpu_data structure.
  */
-.section .text.head, "ax"
+.section .text..head, "ax"
 	.global	start_kernel
 	.global __bss_start
 	.global _end
diff --git a/arch/m32r/kernel/init_task.c b/arch/m32r/kernel/init_task.c
index 016885c..7c24cec 100644
--- a/arch/m32r/kernel/init_task.c
+++ b/arch/m32r/kernel/init_task.c
@@ -25,7 +25,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/m32r/kernel/vmlinux.lds.S b/arch/m32r/kernel/vmlinux.lds.S
index 9db05df..2bcc37e 100644
--- a/arch/m32r/kernel/vmlinux.lds.S
+++ b/arch/m32r/kernel/vmlinux.lds.S
@@ -27,7 +27,7 @@ SECTIONS
   _text = .;			/* Text and read-only data */
   .boot : { *(.boot) } = 0
   .text : {
-	*(.text.head)
+	*(.text..head)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
@@ -57,17 +57,17 @@ SECTIONS
 
   . = ALIGN(4096);
   __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
+  .data_nosave : { *(.data..nosave) }
   . = ALIGN(4096);
   __nosave_end = .;
 
   . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  .data..cacheline_aligned : { *(.data..cacheline_aligned) }
 
   _edata = .;			/* End of data section */
 
   . = ALIGN(8192);		/* init_task */
-  .data.init_task : { *(.data.init_task) }
+  .data..init_task : { *(.data..init_task) }
 
   /* will be freed after init */
   . = ALIGN(4096);		/* Init code and data */
diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S
index f513f53..bdb247e 100644
--- a/arch/m68k/kernel/head.S
+++ b/arch/m68k/kernel/head.S
@@ -577,7 +577,7 @@ func_define	putn,1
 #endif
 .endm
 
-.section ".text.head","ax"
+.section ".text..head","ax"
 ENTRY(_stext)
 /*
  * Version numbers of the bootinfo interface
diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c
index 632ce01..b3c78d9 100644
--- a/arch/m68k/kernel/process.c
+++ b/arch/m68k/kernel/process.c
@@ -47,7 +47,7 @@ struct mm_struct init_mm = INIT_MM(init_mm);
 EXPORT_SYMBOL(init_mm);
 
 union thread_union init_thread_union
-__attribute__((section(".data.init_task"), aligned(THREAD_SIZE)))
+__attribute__((section(".data..init_task"), aligned(THREAD_SIZE)))
        = { INIT_THREAD_INFO(init_task) };
 
 /* initial task structure */
diff --git a/arch/m68k/kernel/sun3-head.S b/arch/m68k/kernel/sun3-head.S
index aad0159..5a6714b 100644
--- a/arch/m68k/kernel/sun3-head.S
+++ b/arch/m68k/kernel/sun3-head.S
@@ -29,7 +29,7 @@ kernel_pmd_table:              .skip 0x2000
 .globl kernel_pg_dir
 .equ    kernel_pg_dir,kernel_pmd_table
 
-	.section .text.head
+	.section .text..head
 ENTRY(_stext)
 ENTRY(_start)
 
diff --git a/arch/m68k/kernel/vmlinux-std.lds b/arch/m68k/kernel/vmlinux-std.lds
index f846d4e..35b6da8 100644
--- a/arch/m68k/kernel/vmlinux-std.lds
+++ b/arch/m68k/kernel/vmlinux-std.lds
@@ -12,7 +12,7 @@ SECTIONS
   . = 0x1000;
   _text = .;			/* Text and read-only data */
   .text : {
-	*(.text.head)
+	*(.text..head)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
@@ -35,7 +35,7 @@ SECTIONS
 	}
 
   . = ALIGN(16);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  .data..cacheline_aligned : { *(.data..cacheline_aligned) }
 
   .bss : { *(.bss) }		/* BSS */
 
@@ -78,7 +78,7 @@ SECTIONS
   . = ALIGN(8192);
   __init_end = .;
 
-  .data.init_task : { *(.data.init_task) }	/* The initial task and kernel stack */
+  .data..init_task : { *(.data..init_task) }	/* The initial task and kernel stack */
 
   _end = . ;
 
diff --git a/arch/m68k/kernel/vmlinux-sun3.lds b/arch/m68k/kernel/vmlinux-sun3.lds
index d9368c0..e6ce561 100644
--- a/arch/m68k/kernel/vmlinux-sun3.lds
+++ b/arch/m68k/kernel/vmlinux-sun3.lds
@@ -12,7 +12,7 @@ SECTIONS
   . = 0xE002000;
   _text = .;			/* Text and read-only data */
   .text : {
-	*(.text.head)
+	*(.text..head)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
@@ -70,7 +70,7 @@ __init_begin = .;
 #endif
 	. = ALIGN(PAGE_SIZE);
 	__init_end = .;
-	.data.init.task : { *(.data.init_task) }
+	.data..init.task : { *(.data..init_task) }
 
 
   .bss : { *(.bss) }		/* BSS */
diff --git a/arch/m68knommu/kernel/init_task.c b/arch/m68knommu/kernel/init_task.c
index fe282de..1ea36d6 100644
--- a/arch/m68knommu/kernel/init_task.c
+++ b/arch/m68knommu/kernel/init_task.c
@@ -36,6 +36,6 @@ EXPORT_SYMBOL(init_task);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
diff --git a/arch/m68knommu/kernel/vmlinux.lds.S b/arch/m68knommu/kernel/vmlinux.lds.S
index 69ba9b1..bdf9b1c 100644
--- a/arch/m68knommu/kernel/vmlinux.lds.S
+++ b/arch/m68knommu/kernel/vmlinux.lds.S
@@ -55,7 +55,7 @@ SECTIONS {
 	.romvec : {
 		__rom_start = . ;
 		_romvec = .;
-		*(.data.initvect)
+		*(.data..initvect)
 	} > romvec
 #endif
 
@@ -66,7 +66,7 @@ SECTIONS {
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
-        	*(.text.lock)
+		*(.text..lock)
 
 		. = ALIGN(16);          /* Exception table              */
 		__start___ex_table = .;
@@ -148,7 +148,7 @@ SECTIONS {
 		_sdata = . ;
 		DATA_DATA
 		. = ALIGN(8192) ;
-		*(.data.init_task)
+		*(.data..init_task)
 		_edata = . ;
 	} > DATA
 
diff --git a/arch/m68knommu/platform/68360/head-ram.S b/arch/m68knommu/platform/68360/head-ram.S
index 2ef0624..8eb94fb 100644
--- a/arch/m68knommu/platform/68360/head-ram.S
+++ b/arch/m68knommu/platform/68360/head-ram.S
@@ -280,7 +280,7 @@ _dprbase:
      * and then overwritten as needed.
      */
  
-.section ".data.initvect","awx"
+.section ".data..initvect","awx"
     .long   RAMEND	/* Reset: Initial Stack Pointer                 - 0.  */
     .long   _start      /* Reset: Initial Program Counter               - 1.  */
     .long   buserr      /* Bus Error                                    - 2.  */
diff --git a/arch/m68knommu/platform/68360/head-rom.S b/arch/m68knommu/platform/68360/head-rom.S
index 62ecf41..97510e5 100644
--- a/arch/m68knommu/platform/68360/head-rom.S
+++ b/arch/m68knommu/platform/68360/head-rom.S
@@ -291,7 +291,7 @@ _dprbase:
      * and then overwritten as needed.
      */
  
-.section ".data.initvect","awx"
+.section ".data..initvect","awx"
     .long   RAMEND	/* Reset: Initial Stack Pointer                 - 0.  */
     .long   _start      /* Reset: Initial Program Counter               - 1.  */
     .long   buserr      /* Bus Error                                    - 2.  */
diff --git a/arch/mips/kernel/init_task.c b/arch/mips/kernel/init_task.c
index 149cd91..acb71af 100644
--- a/arch/mips/kernel/init_task.c
+++ b/arch/mips/kernel/init_task.c
@@ -26,7 +26,7 @@ EXPORT_SYMBOL(init_mm);
  * The things we do for performance..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"),
+	__attribute__((__section__(".data..init_task"),
 	               __aligned__(THREAD_SIZE))) =
 		{ INIT_THREAD_INFO(init_task) };
 
diff --git a/arch/mips/kernel/vmlinux.lds.S b/arch/mips/kernel/vmlinux.lds.S
index 58738c8..6b302c7 100644
--- a/arch/mips/kernel/vmlinux.lds.S
+++ b/arch/mips/kernel/vmlinux.lds.S
@@ -77,7 +77,7 @@ SECTIONS
 		 * object file alignment.  Using 32768
 		 */
 		. = ALIGN(_PAGE_SIZE);
-		*(.data.init_task)
+		*(.data..init_task)
 
 		DATA_DATA
 		CONSTRUCTORS
@@ -99,14 +99,14 @@ SECTIONS
 	. = ALIGN(_PAGE_SIZE);
 	.data_nosave : {
 		__nosave_begin = .;
-		*(.data.nosave)
+		*(.data..nosave)
 	}
 	. = ALIGN(_PAGE_SIZE);
 	__nosave_end = .;
 
 	. = ALIGN(1 << CONFIG_MIPS_L1_CACHE_SHIFT);
-	.data.cacheline_aligned : {
-		*(.data.cacheline_aligned)
+	.data..cacheline_aligned : {
+		*(.data..cacheline_aligned)
 	}
 	_edata =  .;			/* End of data section */
 
diff --git a/arch/mips/lasat/image/head.S b/arch/mips/lasat/image/head.S
index efb95f2..e0ecda9 100644
--- a/arch/mips/lasat/image/head.S
+++ b/arch/mips/lasat/image/head.S
@@ -1,7 +1,7 @@
 #include <asm/lasat/head.h>
 
 	.text
-	.section .text.start, "ax"
+	.section .text..start, "ax"
 	.set noreorder
 	.set mips3
 
diff --git a/arch/mips/lasat/image/romscript.normal b/arch/mips/lasat/image/romscript.normal
index 988f8ad..0864c96 100644
--- a/arch/mips/lasat/image/romscript.normal
+++ b/arch/mips/lasat/image/romscript.normal
@@ -4,7 +4,7 @@ SECTIONS
 {
   .text :
   {
-    *(.text.start)
+    *(.text..start)
   }
 
   /* Data in ROM */
diff --git a/arch/mn10300/kernel/head.S b/arch/mn10300/kernel/head.S
index 606bd8c..dd0db5f 100644
--- a/arch/mn10300/kernel/head.S
+++ b/arch/mn10300/kernel/head.S
@@ -19,7 +19,7 @@
 #include <asm/param.h>
 #include <asm/unit/serial.h>
 
-	.section .text.head,"ax"
+	.section .text..head,"ax"
 
 ###############################################################################
 #
diff --git a/arch/mn10300/kernel/init_task.c b/arch/mn10300/kernel/init_task.c
index 5ac3566..599840f 100644
--- a/arch/mn10300/kernel/init_task.c
+++ b/arch/mn10300/kernel/init_task.c
@@ -31,7 +31,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/mn10300/kernel/vmlinux.lds.S b/arch/mn10300/kernel/vmlinux.lds.S
index b825966..938792a 100644
--- a/arch/mn10300/kernel/vmlinux.lds.S
+++ b/arch/mn10300/kernel/vmlinux.lds.S
@@ -28,7 +28,7 @@ SECTIONS
   _text = .;			/* Text and read-only data */
   .text : {
 	*(
-	.text.head
+	.text..head
 	.text
 	)
 	TEXT_TEXT
@@ -58,25 +58,25 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
   __nosave_begin = .;
-  .data_nosave : { *(.data.nosave) }
+  .data_nosave : { *(.data..nosave) }
   . = ALIGN(PAGE_SIZE);
   __nosave_end = .;
 
   . = ALIGN(PAGE_SIZE);
-  .data.page_aligned : { *(.data.idt) }
+  .data..page_aligned : { *(.data..idt) }
 
   . = ALIGN(32);
-  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+  .data..cacheline_aligned : { *(.data..cacheline_aligned) }
 
   /* rarely changed data like cpu maps */
   . = ALIGN(32);
-  .data.read_mostly : AT(ADDR(.data.read_mostly)) {
-	*(.data.read_mostly)
+  .data..read_mostly : AT(ADDR(.data..read_mostly)) {
+	*(.data..read_mostly)
 	_edata = .;		/* End of data section */
   }
 
   . = ALIGN(THREAD_SIZE);	/* init_task */
-  .data.init_task : { *(.data.init_task) }
+  .data..init_task : { *(.data..init_task) }
 
   /* might get freed after init */
   . = ALIGN(PAGE_SIZE);
@@ -134,7 +134,7 @@ SECTIONS
 
   __bss_start = .;		/* BSS */
   .bss : {
-	*(.bss.page_aligned)
+	*(.bss..page_aligned)
 	*(.bss)
   }
   . = ALIGN(4);
diff --git a/arch/parisc/include/asm/cache.h b/arch/parisc/include/asm/cache.h
index 32c2cca..45effe6 100644
--- a/arch/parisc/include/asm/cache.h
+++ b/arch/parisc/include/asm/cache.h
@@ -28,7 +28,7 @@
 
 #define SMP_CACHE_BYTES L1_CACHE_BYTES
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 void parisc_cache_init(void);	/* initializes cache-flushing */
 void disable_sr_hashing_asm(int); /* low level support for above */
diff --git a/arch/parisc/include/asm/system.h b/arch/parisc/include/asm/system.h
index ee80c92..7ccaf29 100644
--- a/arch/parisc/include/asm/system.h
+++ b/arch/parisc/include/asm/system.h
@@ -174,7 +174,7 @@ static inline void set_eiem(unsigned long val)
 })
 
 #ifdef CONFIG_SMP
-# define __lock_aligned __attribute__((__section__(".data.lock_aligned")))
+# define __lock_aligned __attribute__((__section__(".data..lock_aligned")))
 #endif
 
 #define arch_align_stack(x) (x)
diff --git a/arch/parisc/kernel/head.S b/arch/parisc/kernel/head.S
index 0e3d9f9..4dbdf0e 100644
--- a/arch/parisc/kernel/head.S
+++ b/arch/parisc/kernel/head.S
@@ -345,7 +345,7 @@ smp_slave_stext:
 ENDPROC(stext)
 
 #ifndef CONFIG_64BIT
-	.section .data.read_mostly
+	.section .data..read_mostly
 
 	.align	4
 	.export	$global$,data
diff --git a/arch/parisc/kernel/init_task.c b/arch/parisc/kernel/init_task.c
index 1e25a45..14394c0 100644
--- a/arch/parisc/kernel/init_task.c
+++ b/arch/parisc/kernel/init_task.c
@@ -48,7 +48,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((aligned(128))) __attribute__((__section__(".data.init_task"))) =
+	__attribute__((aligned(128))) __attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 #if PT_NLEVELS == 3
@@ -57,11 +57,11 @@ union thread_union init_thread_union
  * guarantee that global objects will be laid out in memory in the same order 
  * as the order of declaration, so put these in different sections and use
  * the linker script to order them. */
-pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data.vm0.pmd"), aligned(PAGE_SIZE)));
+pmd_t pmd0[PTRS_PER_PMD] __attribute__ ((__section__ (".data..vm0.pmd"), aligned(PAGE_SIZE)));
 #endif
 
-pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data.vm0.pgd"), aligned(PAGE_SIZE)));
-pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data.vm0.pte"), aligned(PAGE_SIZE)));
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__ ((__section__ (".data..vm0.pgd"), aligned(PAGE_SIZE)));
+pte_t pg0[PT_INITIAL * PTRS_PER_PTE] __attribute__ ((__section__ (".data..vm0.pte"), aligned(PAGE_SIZE)));
 
 /*
  * Initial task structure.
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S
index 1a3b6cc..b26eb05 100644
--- a/arch/parisc/kernel/vmlinux.lds.S
+++ b/arch/parisc/kernel/vmlinux.lds.S
@@ -94,8 +94,8 @@ SECTIONS
 
 	/* rarely changed data like cpu maps */
 	. = ALIGN(16);
-	.data.read_mostly : {
-		*(.data.read_mostly)
+	.data..read_mostly : {
+		*(.data..read_mostly)
 	}
 
 	. = ALIGN(L1_CACHE_BYTES);
@@ -106,14 +106,14 @@ SECTIONS
 	}
 
 	. = ALIGN(L1_CACHE_BYTES);
-	.data.cacheline_aligned : {
-		*(.data.cacheline_aligned)
+	.data..cacheline_aligned : {
+		*(.data..cacheline_aligned)
 	}
 
 	/* PA-RISC locks requires 16-byte alignment */
 	. = ALIGN(16);
-	.data.lock_aligned : {
-		*(.data.lock_aligned)
+	.data..lock_aligned : {
+		*(.data..lock_aligned)
 	}
 
 	/* nosave data is really only used for software suspend...it's here
@@ -122,7 +122,7 @@ SECTIONS
 	. = ALIGN(PAGE_SIZE);
 	__nosave_begin = .;
 	.data_nosave : {
-		*(.data.nosave)
+		*(.data..nosave)
 	}
 	. = ALIGN(PAGE_SIZE);
 	__nosave_end = .;
@@ -134,10 +134,10 @@ SECTIONS
 	__bss_start = .;
 	/* page table entries need to be PAGE_SIZE aligned */
 	. = ALIGN(PAGE_SIZE);
-	.data.vmpages : {
-		*(.data.vm0.pmd)
-		*(.data.vm0.pgd)
-		*(.data.vm0.pte)
+	.data..vmpages : {
+		*(.data..vm0.pmd)
+		*(.data..vm0.pgd)
+		*(.data..vm0.pte)
 	}
 	.bss : {
 		*(.bss)
@@ -149,8 +149,8 @@ SECTIONS
 	/* assembler code expects init_task to be 16k aligned */
 	. = ALIGN(16384);
 	/* init_task */
-	.data.init_task : {
-		*(.data.init_task)
+	.data..init_task : {
+		*(.data..init_task)
 	}
 
 #ifdef CONFIG_64BIT
diff --git a/arch/powerpc/include/asm/cache.h b/arch/powerpc/include/asm/cache.h
index 81de6eb..3f41ab9 100644
--- a/arch/powerpc/include/asm/cache.h
+++ b/arch/powerpc/include/asm/cache.h
@@ -38,7 +38,7 @@ extern struct ppc64_caches ppc64_caches;
 #endif /* __powerpc64__ && ! __ASSEMBLY__ */
 
 #if !defined(__ASSEMBLY__)
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 #endif
 
 #endif /* __KERNEL__ */
diff --git a/arch/powerpc/include/asm/page_64.h b/arch/powerpc/include/asm/page_64.h
index 043bfdf..2307910 100644
--- a/arch/powerpc/include/asm/page_64.h
+++ b/arch/powerpc/include/asm/page_64.h
@@ -157,7 +157,7 @@ do {						\
 #else
 #define __page_aligned \
 	__attribute__((__aligned__(PAGE_SIZE), \
-		__section__(".data.page_aligned")))
+		__section__(".data..page_aligned")))
 #endif
 
 #define VM_DATA_DEFAULT_FLAGS \
diff --git a/arch/powerpc/include/asm/ppc_asm.h b/arch/powerpc/include/asm/ppc_asm.h
index 1a0d628..c4759df 100644
--- a/arch/powerpc/include/asm/ppc_asm.h
+++ b/arch/powerpc/include/asm/ppc_asm.h
@@ -193,7 +193,7 @@ name: \
 GLUE(.,name):
 
 #define _INIT_GLOBAL(name) \
-	.section ".text.init.refok"; \
+	.section ".text..init.refok"; \
 	.align 2 ; \
 	.globl name; \
 	.globl GLUE(.,name); \
@@ -233,7 +233,7 @@ name: \
 GLUE(.,name):
 
 #define _INIT_STATIC(name) \
-	.section ".text.init.refok"; \
+	.section ".text..init.refok"; \
 	.align 2 ; \
 	.section ".opd","aw"; \
 name: \
diff --git a/arch/powerpc/kernel/head_32.S b/arch/powerpc/kernel/head_32.S
index a1c4cfd..21a625a 100644
--- a/arch/powerpc/kernel/head_32.S
+++ b/arch/powerpc/kernel/head_32.S
@@ -50,7 +50,7 @@
 	mtspr	SPRN_DBAT##n##L,RB;	\
 1:
 
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 	.stabs	"arch/powerpc/kernel/",N_SO,0,0,0f
 	.stabs	"head_32.S",N_SO,0,0,0f
 0:
diff --git a/arch/powerpc/kernel/head_40x.S b/arch/powerpc/kernel/head_40x.S
index 56d8e5d..de69ecd 100644
--- a/arch/powerpc/kernel/head_40x.S
+++ b/arch/powerpc/kernel/head_40x.S
@@ -52,7 +52,7 @@
  *
  * This is all going to change RSN when we add bi_recs.......  -- Dan
  */
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 _ENTRY(_stext);
 _ENTRY(_start);
 
diff --git a/arch/powerpc/kernel/head_44x.S b/arch/powerpc/kernel/head_44x.S
index b56fecc..ab0b339 100644
--- a/arch/powerpc/kernel/head_44x.S
+++ b/arch/powerpc/kernel/head_44x.S
@@ -50,7 +50,7 @@
  *   r7 - End of kernel command line string
  *
  */
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 _ENTRY(_stext);
 _ENTRY(_start);
 	/*
diff --git a/arch/powerpc/kernel/head_8xx.S b/arch/powerpc/kernel/head_8xx.S
index 3c9452d..f6d1e67 100644
--- a/arch/powerpc/kernel/head_8xx.S
+++ b/arch/powerpc/kernel/head_8xx.S
@@ -38,7 +38,7 @@
 #else
 #define DO_8xx_CPU6(val, reg)
 #endif
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 _ENTRY(_stext);
 _ENTRY(_start);
 
diff --git a/arch/powerpc/kernel/head_fsl_booke.S b/arch/powerpc/kernel/head_fsl_booke.S
index 36ffb35..69a93e2 100644
--- a/arch/powerpc/kernel/head_fsl_booke.S
+++ b/arch/powerpc/kernel/head_fsl_booke.S
@@ -53,7 +53,7 @@
  *   r7 - End of kernel command line string
  *
  */
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 _ENTRY(_stext);
 _ENTRY(_start);
 	/*
diff --git a/arch/powerpc/kernel/init_task.c b/arch/powerpc/kernel/init_task.c
index 688b329..1162c3c 100644
--- a/arch/powerpc/kernel/init_task.c
+++ b/arch/powerpc/kernel/init_task.c
@@ -21,7 +21,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union 
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/powerpc/kernel/machine_kexec_64.c b/arch/powerpc/kernel/machine_kexec_64.c
index 49e705f..815a13c 100644
--- a/arch/powerpc/kernel/machine_kexec_64.c
+++ b/arch/powerpc/kernel/machine_kexec_64.c
@@ -250,7 +250,7 @@ static void kexec_prepare_cpus(void)
  * current, but that audit has not been performed.
  */
 static union thread_union kexec_stack
-	__attribute__((__section__(".data.init_task"))) = { };
+	__attribute__((__section__(".data..init_task"))) = { };
 
 /* Our assembly helper, in kexec_stub.S */
 extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
diff --git a/arch/powerpc/kernel/vdso.c b/arch/powerpc/kernel/vdso.c
index ad06d5c..6685af8 100644
--- a/arch/powerpc/kernel/vdso.c
+++ b/arch/powerpc/kernel/vdso.c
@@ -74,7 +74,7 @@ static int vdso_ready;
 static union {
 	struct vdso_data	data;
 	u8			page[PAGE_SIZE];
-} vdso_data_store __attribute__((__section__(".data.page_aligned")));
+} vdso_data_store __attribute__((__section__(".data..page_aligned")));
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
 /* Format of the patch table */
diff --git a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
index 556f0ca..10f61ac 100644
--- a/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
+++ b/arch/powerpc/kernel/vdso32/vdso32_wrapper.S
@@ -1,7 +1,7 @@
 #include <linux/init.h>
 #include <asm/page.h>
 
-	.section ".data.page_aligned"
+	.section ".data..page_aligned"
 
 	.globl vdso32_start, vdso32_end
 	.balign PAGE_SIZE
diff --git a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
index 0529cb9..3c1cc59 100644
--- a/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
+++ b/arch/powerpc/kernel/vdso64/vdso64_wrapper.S
@@ -1,7 +1,7 @@
 #include <linux/init.h>
 #include <asm/page.h>
 
-	.section ".data.page_aligned"
+	.section ".data..page_aligned"
 
 	.globl vdso64_start, vdso64_end
 	.balign PAGE_SIZE
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 161b9b9..f8fa660 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -52,9 +52,9 @@ SECTIONS
 	/* Text and gots */
 	.text : AT(ADDR(.text) - LOAD_OFFSET) {
 		ALIGN_FUNCTION();
-		*(.text.head)
+		*(.text..head)
 		_text = .;
-		*(.text .fixup .text.init.refok .exit.text.refok __ftr_alt_*)
+		*(.text .fixup .text..init.refok .text..exit.refok __ftr_alt_*)
 		SCHED_TEXT
 		LOCK_TEXT
 		KPROBES_TEXT
@@ -182,10 +182,10 @@ SECTIONS
 	}
 #endif
 	. = ALIGN(PAGE_SIZE);
-	.data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
+	.data..percpu  : AT(ADDR(.data..percpu) - LOAD_OFFSET) {
 		__per_cpu_start = .;
-		*(.data.percpu)
-		*(.data.percpu.shared_aligned)
+		*(.data..percpu)
+		*(.data..percpu.shared_aligned)
 		__per_cpu_end = .;
 	}
 
@@ -259,28 +259,28 @@ SECTIONS
 #else
 	. = ALIGN(16384);
 #endif
-	.data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
-		*(.data.init_task)
+	.data..init_task : AT(ADDR(.data..init_task) - LOAD_OFFSET) {
+		*(.data..init_task)
 	}
 
 	. = ALIGN(PAGE_SIZE);
-	.data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-		*(.data.page_aligned)
+	.data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) {
+		*(.data..page_aligned)
 	}
 
-	.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-		*(.data.cacheline_aligned)
+	.data..cacheline_aligned : AT(ADDR(.data..cacheline_aligned) - LOAD_OFFSET) {
+		*(.data..cacheline_aligned)
 	}
 
 	. = ALIGN(L1_CACHE_BYTES);
-	.data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
-		*(.data.read_mostly)
+	.data..read_mostly : AT(ADDR(.data..read_mostly) - LOAD_OFFSET) {
+		*(.data..read_mostly)
 	}
 
 	. = ALIGN(PAGE_SIZE);
 	.data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
 		__nosave_begin = .;
-		*(.data.nosave)
+		*(.data..nosave)
 		. = ALIGN(PAGE_SIZE);
 		__nosave_end = .;
 	}
diff --git a/arch/s390/include/asm/cache.h b/arch/s390/include/asm/cache.h
index 9b86681..24aafa6 100644
--- a/arch/s390/include/asm/cache.h
+++ b/arch/s390/include/asm/cache.h
@@ -14,6 +14,6 @@
 #define L1_CACHE_BYTES     256
 #define L1_CACHE_SHIFT     8
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #endif
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S
index ec7e35f..322b3b2 100644
--- a/arch/s390/kernel/head.S
+++ b/arch/s390/kernel/head.S
@@ -35,7 +35,7 @@
 #define ARCH_OFFSET	0
 #endif
 
-.section ".text.head","ax"
+.section ".text..head","ax"
 #ifndef CONFIG_IPL
 	.org   0
 	.long  0x00080000,0x80000000+startup	# Just a restart PSW
diff --git a/arch/s390/kernel/init_task.c b/arch/s390/kernel/init_task.c
index 7db95c0..7cfd9af 100644
--- a/arch/s390/kernel/init_task.c
+++ b/arch/s390/kernel/init_task.c
@@ -30,7 +30,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union 
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 690e178..2384c7e 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -64,7 +64,7 @@ __setup("vdso=", vdso_setup);
 static union {
 	struct vdso_data	data;
 	u8			page[PAGE_SIZE];
-} vdso_data_store __attribute__((__section__(".data.page_aligned")));
+} vdso_data_store __attribute__((__section__(".data..page_aligned")));
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
 /*
diff --git a/arch/s390/kernel/vdso32/vdso32_wrapper.S b/arch/s390/kernel/vdso32/vdso32_wrapper.S
index 61639a8..025cb77 100644
--- a/arch/s390/kernel/vdso32/vdso32_wrapper.S
+++ b/arch/s390/kernel/vdso32/vdso32_wrapper.S
@@ -1,7 +1,7 @@
 #include <linux/init.h>
 #include <asm/page.h>
 
-	.section ".data.page_aligned"
+	.section ".data..page_aligned"
 
 	.globl vdso32_start, vdso32_end
 	.balign PAGE_SIZE
diff --git a/arch/s390/kernel/vdso64/vdso64_wrapper.S b/arch/s390/kernel/vdso64/vdso64_wrapper.S
index d8e2ac1..d26126d 100644
--- a/arch/s390/kernel/vdso64/vdso64_wrapper.S
+++ b/arch/s390/kernel/vdso64/vdso64_wrapper.S
@@ -1,7 +1,7 @@
 #include <linux/init.h>
 #include <asm/page.h>
 
-	.section ".data.page_aligned"
+	.section ".data..page_aligned"
 
 	.globl vdso64_start, vdso64_end
 	.balign PAGE_SIZE
diff --git a/arch/s390/kernel/vmlinux.lds.S b/arch/s390/kernel/vmlinux.lds.S
index d796d05..41f1d6a 100644
--- a/arch/s390/kernel/vmlinux.lds.S
+++ b/arch/s390/kernel/vmlinux.lds.S
@@ -29,7 +29,7 @@ SECTIONS
 	. = 0x00000000;
 	.text : {
 	_text = .;		/* Text and read-only data */
-		*(.text.head)
+		*(.text..head)
 	TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
@@ -66,30 +66,30 @@ SECTIONS
 	. = ALIGN(PAGE_SIZE);
 	.data_nosave : {
 	__nosave_begin = .;
-		*(.data.nosave)
+		*(.data..nosave)
 	}
 	. = ALIGN(PAGE_SIZE);
 	__nosave_end = .;
 
 	. = ALIGN(PAGE_SIZE);
-	.data.page_aligned : {
-		*(.data.idt)
+	.data..page_aligned : {
+		*(.data..idt)
 	}
 
 	. = ALIGN(0x100);
-	.data.cacheline_aligned : {
-		*(.data.cacheline_aligned)
+	.data..cacheline_aligned : {
+		*(.data..cacheline_aligned)
 	}
 
 	. = ALIGN(0x100);
-	.data.read_mostly : {
-		*(.data.read_mostly)
+	.data..read_mostly : {
+		*(.data..read_mostly)
 	}
 	_edata = .;		/* End of data section */
 
 	. = ALIGN(THREAD_SIZE);	/* init_task */
-	.data.init_task : {
-		*(.data.init_task)
+	.data..init_task : {
+		*(.data..init_task)
 	}
 
 	/* will be freed after init */
diff --git a/arch/sh/include/asm/cache.h b/arch/sh/include/asm/cache.h
index 02df18e..455a9a9 100644
--- a/arch/sh/include/asm/cache.h
+++ b/arch/sh/include/asm/cache.h
@@ -14,7 +14,7 @@
 
 #define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #ifndef __ASSEMBLY__
 struct cache_info {
diff --git a/arch/sh/kernel/cpu/sh5/entry.S b/arch/sh/kernel/cpu/sh5/entry.S
index e640c63..433de32 100644
--- a/arch/sh/kernel/cpu/sh5/entry.S
+++ b/arch/sh/kernel/cpu/sh5/entry.S
@@ -2058,10 +2058,10 @@ asm_uaccess_end:
 
 
 /*
- * --- .text.init Section
+ * --- .text..init Section
  */
 
-	.section	.text.init, "ax"
+	.section	.text..init, "ax"
 
 /*
  * void trap_init (void)
diff --git a/arch/sh/kernel/head_32.S b/arch/sh/kernel/head_32.S
index 788605f..4065946 100644
--- a/arch/sh/kernel/head_32.S
+++ b/arch/sh/kernel/head_32.S
@@ -40,7 +40,7 @@ ENTRY(empty_zero_page)
 1:
 	.skip	PAGE_SIZE - empty_zero_page - 1b
 
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 
 /*
  * Condition at the entry of _stext:
diff --git a/arch/sh/kernel/head_64.S b/arch/sh/kernel/head_64.S
index 7ccfb99..c3543d1 100644
--- a/arch/sh/kernel/head_64.S
+++ b/arch/sh/kernel/head_64.S
@@ -110,7 +110,7 @@ empty_bad_pte_table:
 fpu_in_use:	.quad	0
 
 
-	.section	.text.head, "ax"
+	.section	.text..head, "ax"
 	.balign L1_CACHE_BYTES
 /*
  * Condition at the entry of __stext:
diff --git a/arch/sh/kernel/init_task.c b/arch/sh/kernel/init_task.c
index 80c35ff..af29479 100644
--- a/arch/sh/kernel/init_task.c
+++ b/arch/sh/kernel/init_task.c
@@ -21,7 +21,7 @@ EXPORT_SYMBOL(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c
index 64b7690..acf65fb 100644
--- a/arch/sh/kernel/irq.c
+++ b/arch/sh/kernel/irq.c
@@ -158,10 +158,10 @@ asmlinkage int do_IRQ(unsigned int irq, struct pt_regs *regs)
 
 #ifdef CONFIG_IRQSTACKS
 static char softirq_stack[NR_CPUS * THREAD_SIZE]
-		__attribute__((__section__(".bss.page_aligned")));
+		__attribute__((__section__(".bss..page_aligned")));
 
 static char hardirq_stack[NR_CPUS * THREAD_SIZE]
-		__attribute__((__section__(".bss.page_aligned")));
+		__attribute__((__section__(".bss..page_aligned")));
 
 /*
  * allocate per-cpu stacks for hardirq and for softirq processing
diff --git a/arch/sh/kernel/vmlinux_32.lds.S b/arch/sh/kernel/vmlinux_32.lds.S
index 7b4b82b..5add714 100644
--- a/arch/sh/kernel/vmlinux_32.lds.S
+++ b/arch/sh/kernel/vmlinux_32.lds.S
@@ -28,7 +28,7 @@ SECTIONS
 	} = 0
 
 	.text : {
-		*(.text.head)
+		*(.text..head)
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
@@ -58,19 +58,19 @@ SECTIONS
 
 	. = ALIGN(THREAD_SIZE);
 	.data : {			/* Data */
-		*(.data.init_task)
+		*(.data..init_task)
 
 		. = ALIGN(L1_CACHE_BYTES);
-		*(.data.cacheline_aligned)
+		*(.data..cacheline_aligned)
 
 		. = ALIGN(L1_CACHE_BYTES);
-		*(.data.read_mostly)
+		*(.data..read_mostly)
 
 		. = ALIGN(PAGE_SIZE);
-		*(.data.page_aligned)
+		*(.data..page_aligned)
 
 		__nosave_begin = .;
-		*(.data.nosave)
+		*(.data..nosave)
 		. = ALIGN(PAGE_SIZE);
 		__nosave_end = .;
 
@@ -128,7 +128,7 @@ SECTIONS
 	.bss : {
 		__init_end = .;
 		__bss_start = .;		/* BSS */
-		*(.bss.page_aligned)
+		*(.bss..page_aligned)
 		*(.bss)
 		*(COMMON)
 		. = ALIGN(4);
diff --git a/arch/sh/kernel/vmlinux_64.lds.S b/arch/sh/kernel/vmlinux_64.lds.S
index 33fa464..c7d5f5b 100644
--- a/arch/sh/kernel/vmlinux_64.lds.S
+++ b/arch/sh/kernel/vmlinux_64.lds.S
@@ -42,7 +42,7 @@ SECTIONS
 	} = 0
 
 	.text : C_PHYS(.text) {
-		*(.text.head)
+		*(.text..head)
 		TEXT_TEXT
 		*(.text64)
 		*(.text..SHmedia32)
@@ -70,19 +70,19 @@ SECTIONS
 
 	. = ALIGN(THREAD_SIZE);
 	.data : C_PHYS(.data) {			/* Data */
-		*(.data.init_task)
+		*(.data..init_task)
 
 		. = ALIGN(L1_CACHE_BYTES);
-		*(.data.cacheline_aligned)
+		*(.data..cacheline_aligned)
 
 		. = ALIGN(L1_CACHE_BYTES);
-		*(.data.read_mostly)
+		*(.data..read_mostly)
 
 		. = ALIGN(PAGE_SIZE);
-		*(.data.page_aligned)
+		*(.data..page_aligned)
 
 		__nosave_begin = .;
-		*(.data.nosave)
+		*(.data..nosave)
 		. = ALIGN(PAGE_SIZE);
 		__nosave_end = .;
 
@@ -140,7 +140,7 @@ SECTIONS
 	.bss : C_PHYS(.bss) {
 		__init_end = .;
 		__bss_start = .;		/* BSS */
-		*(.bss.page_aligned)
+		*(.bss..page_aligned)
 		*(.bss)
 		*(COMMON)
 		. = ALIGN(4);
diff --git a/arch/sparc/boot/btfixupprep.c b/arch/sparc/boot/btfixupprep.c
index 52a4208..e899f2a 100644
--- a/arch/sparc/boot/btfixupprep.c
+++ b/arch/sparc/boot/btfixupprep.c
@@ -171,7 +171,7 @@ main1:
 			}
 		} else if (buffer[nbase+4] != '_')
 			continue;
-		if (!strcmp (sect, ".text.exit"))
+		if (!strcmp (sect, ".text..exit"))
 			continue;
 		if (strcmp (sect, ".text") &&
 		    strcmp (sect, ".init.text") &&
@@ -325,7 +325,7 @@ main1:
 		(*rr)->next = NULL;
 	}
 	printf("! Generated by btfixupprep. Do not edit.\n\n");
-	printf("\t.section\t\".data.init\",#alloc,#write\n\t.align\t4\n\n");
+	printf("\t.section\t\".data..init\",#alloc,#write\n\t.align\t4\n\n");
 	printf("\t.global\t___btfixup_start\n___btfixup_start:\n\n");
 	for (i = 0; i < last; i++) {
 		f = array + i;
diff --git a/arch/sparc/include/asm/cache.h b/arch/sparc/include/asm/cache.h
index 41f85ae..2909f0a 100644
--- a/arch/sparc/include/asm/cache.h
+++ b/arch/sparc/include/asm/cache.h
@@ -19,7 +19,7 @@
 
 #define SMP_CACHE_BYTES (1 << SMP_CACHE_BYTES_SHIFT)
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #ifdef CONFIG_SPARC32
 #include <asm/asi.h>
diff --git a/arch/sparc/kernel/head_32.S b/arch/sparc/kernel/head_32.S
index f0b4b51..0ca3dc5 100644
--- a/arch/sparc/kernel/head_32.S
+++ b/arch/sparc/kernel/head_32.S
@@ -72,7 +72,7 @@ sun4e_notsup:
 	.align 4
 
 	/* The Sparc trap table, bootloader gives us control at _start. */
-	.section .text.head,"ax"
+	.section .text..head,"ax"
 	.globl	start, _stext, _start, __stext
 	.globl  trapbase
 _start:   /* danger danger */
@@ -735,7 +735,7 @@ go_to_highmem:
 		 nop
 
 /* The code above should be at beginning and we have to take care about
- * short jumps, as branching to .text.init section from .text is usually
+ * short jumps, as branching to .text..init section from .text is usually
  * impossible */
 		__INIT
 /* Acquire boot time privileged register values, this will help debugging.
diff --git a/arch/sparc/kernel/head_64.S b/arch/sparc/kernel/head_64.S
index a46c3a2..ad713f6 100644
--- a/arch/sparc/kernel/head_64.S
+++ b/arch/sparc/kernel/head_64.S
@@ -467,7 +467,7 @@ jump_to_sun4u_init:
 	jmpl    %g2 + %g0, %g0
 	 nop
 
-	.section	.text.init.refok
+	.section	.text..init.refok
 sun4u_init:
 	BRANCH_IF_SUN4V(g1, sun4v_init)
 
diff --git a/arch/sparc/kernel/init_task.c b/arch/sparc/kernel/init_task.c
index f28cb82..7f7a468 100644
--- a/arch/sparc/kernel/init_task.c
+++ b/arch/sparc/kernel/init_task.c
@@ -22,5 +22,5 @@ EXPORT_SYMBOL(init_task);
  * in etrap.S which assumes it.
  */
 union thread_union init_thread_union
-	__attribute__((section (".data.init_task")))
+	__attribute__((section (".data..init_task")))
 	= { INIT_THREAD_INFO(init_task) };
diff --git a/arch/sparc/kernel/vmlinux.lds.S b/arch/sparc/kernel/vmlinux.lds.S
index 7626708..66eddbe 100644
--- a/arch/sparc/kernel/vmlinux.lds.S
+++ b/arch/sparc/kernel/vmlinux.lds.S
@@ -41,7 +41,7 @@ SECTIONS
 	.text TEXTSTART :
 	{
 		_text = .;
-		*(.text.head)
+		*(.text..head)
 		TEXT_TEXT
 		SCHED_TEXT
 		LOCK_TEXT
@@ -59,20 +59,20 @@ SECTIONS
 		*(.data1)
 	}
 	. = ALIGN(SMP_CACHE_BYTES);
-	.data.cacheline_aligned : {
-		*(.data.cacheline_aligned)
+	.data..cacheline_aligned : {
+		*(.data..cacheline_aligned)
 	}
 	. = ALIGN(SMP_CACHE_BYTES);
-	.data.read_mostly : {
-		*(.data.read_mostly)
+	.data..read_mostly : {
+		*(.data..read_mostly)
 	}
 	/* End of data section */
 	_edata = .;
 
 	/* init_task */
 	. = ALIGN(THREAD_SIZE);
-	.data.init_task : {
-		*(.data.init_task)
+	.data..init_task : {
+		*(.data..init_task)
 	}
 	.fixup : {
 		__start___fixup = .;
diff --git a/arch/um/include/asm/common.lds.S b/arch/um/include/asm/common.lds.S
index cb02486..b623606 100644
--- a/arch/um/include/asm/common.lds.S
+++ b/arch/um/include/asm/common.lds.S
@@ -49,9 +49,9 @@
   }
 
   . = ALIGN(32);
-  .data.percpu : {
+  .data..percpu : {
 	__per_cpu_start = . ;
-	*(.data.percpu)
+	*(.data..percpu)
 	__per_cpu_end = . ;
   }
 	
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 9975e1a..a415658 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -97,9 +97,9 @@ SECTIONS
   .fini_array     : { *(.fini_array) }
   .data           : {
     . = ALIGN(KERNEL_STACK_SIZE);		/* init_task */
-    *(.data.init_task)
+    *(.data..init_task)
     . = ALIGN(KERNEL_STACK_SIZE);
-    *(.data.init_irqstack)
+    *(.data..init_irqstack)
     DATA_DATA
     *(.data.* .gnu.linkonce.d.*)
     SORT(CONSTRUCTORS)
diff --git a/arch/um/kernel/init_task.c b/arch/um/kernel/init_task.c
index 806d381..eed073e 100644
--- a/arch/um/kernel/init_task.c
+++ b/arch/um/kernel/init_task.c
@@ -34,9 +34,9 @@ EXPORT_SYMBOL(init_task);
  */
 
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 union thread_union cpu0_irqstack
-	__attribute__((__section__(".data.init_irqstack"))) =
+	__attribute__((__section__(".data..init_irqstack"))) =
 		{ INIT_THREAD_INFO(init_task) };
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 11b8352..7b03348 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -53,9 +53,9 @@ SECTIONS
   .data    :
   {
     . = ALIGN(KERNEL_STACK_SIZE);		/* init_task */
-    *(.data.init_task)
+    *(.data..init_task)
     . = ALIGN(KERNEL_STACK_SIZE);
-    *(.data.init_irqstack)
+    *(.data..init_irqstack)
     DATA_DATA
     *(.gnu.linkonce.d*)
     CONSTRUCTORS
diff --git a/arch/x86/boot/compressed/head_32.S b/arch/x86/boot/compressed/head_32.S
index 29c5fbf..b085d1f 100644
--- a/arch/x86/boot/compressed/head_32.S
+++ b/arch/x86/boot/compressed/head_32.S
@@ -29,7 +29,7 @@
 #include <asm/boot.h>
 #include <asm/asm-offsets.h>
 
-.section ".text.head","ax",@progbits
+.section ".text..head","ax",@progbits
 	.globl startup_32
 
 startup_32:
diff --git a/arch/x86/boot/compressed/head_64.S b/arch/x86/boot/compressed/head_64.S
index 1d5dff4..e3b4559 100644
--- a/arch/x86/boot/compressed/head_64.S
+++ b/arch/x86/boot/compressed/head_64.S
@@ -33,7 +33,7 @@
 #include <asm/processor-flags.h>
 #include <asm/asm-offsets.h>
 
-.section ".text.head"
+.section ".text..head"
 	.code32
 	.globl startup_32
 
diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c
index 857e492..af8b9c5 100644
--- a/arch/x86/boot/compressed/relocs.c
+++ b/arch/x86/boot/compressed/relocs.c
@@ -559,7 +559,7 @@ static void emit_relocs(int as_text)
 		/* Print the relocations in a form suitable that
 		 * gas will like.
 		 */
-		printf(".section \".data.reloc\",\"a\"\n");
+		printf(".section \".data..reloc\",\"a\"\n");
 		printf(".balign 4\n");
 		for (i = 0; i < reloc_count; i++) {
 			printf("\t .long 0x%08lx\n", relocs[i]);
diff --git a/arch/x86/boot/compressed/vmlinux.scr b/arch/x86/boot/compressed/vmlinux.scr
index f02382a..862d748 100644
--- a/arch/x86/boot/compressed/vmlinux.scr
+++ b/arch/x86/boot/compressed/vmlinux.scr
@@ -1,6 +1,6 @@
 SECTIONS
 {
-  .rodata.compressed : {
+  .rodata..compressed : {
 	input_len = .;
 	LONG(input_data_end - input_data) input_data = .;
 	*(.data)
diff --git a/arch/x86/boot/compressed/vmlinux_32.lds b/arch/x86/boot/compressed/vmlinux_32.lds
index bb3c483..d70318a 100644
--- a/arch/x86/boot/compressed/vmlinux_32.lds
+++ b/arch/x86/boot/compressed/vmlinux_32.lds
@@ -7,13 +7,13 @@ SECTIONS
 	 * address 0.
 	 */
 	. = 0;
-	.text.head : {
+	.text..head : {
 		_head = . ;
-		*(.text.head)
+		*(.text..head)
 		_ehead = . ;
 	}
-	.rodata.compressed : {
-		*(.rodata.compressed)
+	.rodata..compressed : {
+		*(.rodata..compressed)
 	}
 	.text :	{
 		_text = .; 	/* Text */
@@ -21,6 +21,10 @@ SECTIONS
 		*(.text.*)
 		_etext = . ;
 	}
+	.got : {
+		*(.got)
+		*(.got.*)
+	}
 	.rodata : {
 		_rodata = . ;
 		*(.rodata)	 /* read-only data */
@@ -40,4 +44,6 @@ SECTIONS
 		*(COMMON)
 		_end = . ;
 	}
+	/* Be bold, and discard everything not explicitly mentioned */
+	/DISCARD/ : { *(*) }
 }
diff --git a/arch/x86/boot/compressed/vmlinux_64.lds b/arch/x86/boot/compressed/vmlinux_64.lds
index bef1ac8..d3d1468 100644
--- a/arch/x86/boot/compressed/vmlinux_64.lds
+++ b/arch/x86/boot/compressed/vmlinux_64.lds
@@ -7,13 +7,13 @@ SECTIONS
 	 * address 0.
 	 */
 	. = 0;
-	.text.head : {
+	.text..head : {
 		_head = . ;
-		*(.text.head)
+		*(.text..head)
 		_ehead = . ;
 	}
-	.rodata.compressed : {
-		*(.rodata.compressed)
+	.rodata..compressed : {
+		*(.rodata..compressed)
 	}
 	.text :	{
 		_text = .; 	/* Text */
@@ -45,4 +45,6 @@ SECTIONS
 		. = . + 4096 * 6;
 		_ebss = .;
 	}
+	/* Be bold, and discard everything not explicitly mentioned */
+	/DISCARD/ : { *(*) }
 }
diff --git a/arch/x86/include/asm/cache.h b/arch/x86/include/asm/cache.h
index 5d367ca..6b94d49 100644
--- a/arch/x86/include/asm/cache.h
+++ b/arch/x86/include/asm/cache.h
@@ -5,7 +5,7 @@
 #define L1_CACHE_SHIFT	(CONFIG_X86_L1_CACHE_SHIFT)
 #define L1_CACHE_BYTES	(1 << L1_CACHE_SHIFT)
 
-#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #ifdef CONFIG_X86_VSMP
 /* vSMP Internode cacheline shift */
@@ -13,7 +13,7 @@
 #ifdef CONFIG_SMP
 #define __cacheline_aligned_in_smp					\
 	__attribute__((__aligned__(1 << (INTERNODE_CACHE_SHIFT))))	\
-	__attribute__((__section__(".data.page_aligned")))
+	__attribute__((__section__(".data..page_aligned")))
 #endif
 #endif
 
diff --git a/arch/x86/kernel/acpi/wakeup_32.S b/arch/x86/kernel/acpi/wakeup_32.S
index a12e6a9..b3f6fbf 100644
--- a/arch/x86/kernel/acpi/wakeup_32.S
+++ b/arch/x86/kernel/acpi/wakeup_32.S
@@ -1,4 +1,4 @@
-	.section .text.page_aligned
+	.section .text..page_aligned
 #include <linux/linkage.h>
 #include <asm/segment.h>
 #include <asm/page.h>
diff --git a/arch/x86/kernel/head_32.S b/arch/x86/kernel/head_32.S
index e835b4e..65b23f8 100644
--- a/arch/x86/kernel/head_32.S
+++ b/arch/x86/kernel/head_32.S
@@ -81,7 +81,7 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_
  * any particular GDT layout, because we load our own as soon as we
  * can.
  */
-.section .text.head,"ax",@progbits
+.section .text..head,"ax",@progbits
 ENTRY(startup_32)
 	/* test KEEP_SEGMENTS flag to see if the bootloader is asking
 		us to not reload segments */
@@ -609,7 +609,7 @@ ENTRY(_stext)
 /*
  * BSS section
  */
-.section ".bss.page_aligned","wa"
+.section ".bss..page_aligned","wa"
 	.align PAGE_SIZE_asm
 #ifdef CONFIG_X86_PAE
 swapper_pg_pmd:
@@ -626,7 +626,7 @@ ENTRY(empty_zero_page)
  * This starts the data section.
  */
 #ifdef CONFIG_X86_PAE
-.section ".data.page_aligned","wa"
+.section ".data..page_aligned","wa"
 	/* Page-aligned for the benefit of paravirt? */
 	.align PAGE_SIZE_asm
 ENTRY(swapper_pg_dir)
diff --git a/arch/x86/kernel/head_64.S b/arch/x86/kernel/head_64.S
index 0e275d4..643d5d3 100644
--- a/arch/x86/kernel/head_64.S
+++ b/arch/x86/kernel/head_64.S
@@ -40,7 +40,7 @@ L4_START_KERNEL = pgd_index(__START_KERNEL_map)
 L3_START_KERNEL = pud_index(__START_KERNEL_map)
 
 	.text
-	.section .text.head
+	.section .text..head
 	.code64
 	.globl startup_64
 startup_64:
@@ -414,7 +414,7 @@ ENTRY(phys_base)
 ENTRY(idt_table)
 	.skip 256 * 16
 
-	.section .bss.page_aligned, "aw", @nobits
+	.section .bss..page_aligned, "aw", @nobits
 	.align PAGE_SIZE
 ENTRY(empty_zero_page)
 	.skip PAGE_SIZE
diff --git a/arch/x86/kernel/init_task.c b/arch/x86/kernel/init_task.c
index df3bf26..103b1c5 100644
--- a/arch/x86/kernel/init_task.c
+++ b/arch/x86/kernel/init_task.c
@@ -22,7 +22,7 @@ struct mm_struct init_mm = INIT_MM(init_mm);
  * "init_task" linker map entry..
  */
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 		{ INIT_THREAD_INFO(init_task) };
 
 /*
@@ -36,7 +36,7 @@ EXPORT_SYMBOL(init_task);
 /*
  * per-CPU TSS segments. Threads are completely 'soft' on Linux,
  * no more per-task TSS's. The TSS size is kept cacheline-aligned
- * so they are allowed to end up in the .data.cacheline_aligned
+ * so they are allowed to end up in the .data..cacheline_aligned
  * section. Since TSS's are completely CPU-local, we want them
  * on exact cacheline boundaries, to eliminate cacheline ping-pong.
  */
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 7932338..fc8ff15 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -78,7 +78,7 @@ char ignore_fpu_irq;
  * for this.
  */
 gate_desc idt_table[256]
-	__attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, };
+	__attribute__((__section__(".data..idt"))) = { { { { 0, 0 } } }, };
 #endif
 
 DECLARE_BITMAP(used_vectors, NR_VECTORS);
diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S
index 82c6755..31c131a 100644
--- a/arch/x86/kernel/vmlinux_32.lds.S
+++ b/arch/x86/kernel/vmlinux_32.lds.S
@@ -31,15 +31,15 @@ SECTIONS
   . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR;
   phys_startup_32 = startup_32 - LOAD_OFFSET;
 
-  .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) {
+  .text..head : AT(ADDR(.text..head) - LOAD_OFFSET) {
   	_text = .;			/* Text and read-only data */
-	*(.text.head)
+	*(.text..head)
   } :text = 0x9090
 
   /* read-only */
   .text : AT(ADDR(.text) - LOAD_OFFSET) {
 	. = ALIGN(PAGE_SIZE); /* not really needed, already page aligned */
-	*(.text.page_aligned)
+	*(.text..page_aligned)
 	TEXT_TEXT
 	SCHED_TEXT
 	LOCK_TEXT
@@ -71,32 +71,32 @@ SECTIONS
   . = ALIGN(PAGE_SIZE);
   .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) {
   	__nosave_begin = .;
-	*(.data.nosave)
+	*(.data..nosave)
   	. = ALIGN(PAGE_SIZE);
   	__nosave_end = .;
   }
 
   . = ALIGN(PAGE_SIZE);
-  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-	*(.data.page_aligned)
-	*(.data.idt)
+  .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) {
+	*(.data..page_aligned)
+	*(.data..idt)
   }
 
   . = ALIGN(32);
-  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-	*(.data.cacheline_aligned)
+  .data..cacheline_aligned : AT(ADDR(.data..cacheline_aligned) - LOAD_OFFSET) {
+	*(.data..cacheline_aligned)
   }
 
   /* rarely changed data like cpu maps */
   . = ALIGN(32);
-  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
-	*(.data.read_mostly)
+  .data..read_mostly : AT(ADDR(.data..read_mostly) - LOAD_OFFSET) {
+	*(.data..read_mostly)
 	_edata = .;		/* End of data section */
   }
 
   . = ALIGN(THREAD_SIZE);	/* init_task */
-  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
-	*(.data.init_task)
+  .data..init_task : AT(ADDR(.data..init_task) - LOAD_OFFSET) {
+	*(.data..init_task)
   }
 
   /* might get freed after init */
@@ -179,11 +179,11 @@ SECTIONS
   }
 #endif
   . = ALIGN(PAGE_SIZE);
-  .data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {
+  .data..percpu  : AT(ADDR(.data..percpu) - LOAD_OFFSET) {
 	__per_cpu_start = .;
-	*(.data.percpu.page_aligned)
-	*(.data.percpu)
-	*(.data.percpu.shared_aligned)
+	*(.data..percpu.page_aligned)
+	*(.data..percpu)
+	*(.data..percpu.shared_aligned)
 	__per_cpu_end = .;
   }
   . = ALIGN(PAGE_SIZE);
@@ -192,7 +192,7 @@ SECTIONS
   .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
 	__init_end = .;
 	__bss_start = .;		/* BSS */
-	*(.bss.page_aligned)
+	*(.bss..page_aligned)
 	*(.bss)
 	. = ALIGN(4);
 	__bss_stop = .;
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index 1a614c0..56ed592 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -28,7 +28,7 @@ SECTIONS
   _text = .;			/* Text and read-only data */
   .text :  AT(ADDR(.text) - LOAD_OFFSET) {
 	/* First the code that has to be first for bootstrapping */
-	*(.text.head)
+	*(.text..head)
 	_stext = .;
 	/* Then the rest */
 	TEXT_TEXT
@@ -63,17 +63,17 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
   . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
-  .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
-	*(.data.cacheline_aligned)
+  .data..cacheline_aligned : AT(ADDR(.data..cacheline_aligned) - LOAD_OFFSET) {
+	*(.data..cacheline_aligned)
   }
   . = ALIGN(CONFIG_X86_INTERNODE_CACHE_BYTES);
-  .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
-  	*(.data.read_mostly)
+  .data..read_mostly : AT(ADDR(.data..read_mostly) - LOAD_OFFSET) {
+	*(.data..read_mostly)
   }
 
 #define VSYSCALL_ADDR (-10*1024*1024)
-#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
-#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data..read_mostly) + SIZEOF(.data..read_mostly) + 4095) & ~(4095))
+#define VSYSCALL_VIRT_ADDR ((ADDR(.data..read_mostly) + SIZEOF(.data..read_mostly) + 4095) & ~(4095))
 
 #define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR)
 #define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
@@ -122,13 +122,13 @@ SECTIONS
 #undef VVIRT
 
   . = ALIGN(THREAD_SIZE);	/* init_task */
-  .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
-	*(.data.init_task)
+  .data..init_task : AT(ADDR(.data..init_task) - LOAD_OFFSET) {
+	*(.data..init_task)
   }:data.init
 
   . = ALIGN(PAGE_SIZE);
-  .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
-	*(.data.page_aligned)
+  .data..page_aligned : AT(ADDR(.data..page_aligned) - LOAD_OFFSET) {
+	*(.data..page_aligned)
   }
 
   /* might get freed after init */
@@ -215,13 +215,13 @@ SECTIONS
 
   . = ALIGN(PAGE_SIZE);
   __nosave_begin = .;
-  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
+  .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data..nosave) }
   . = ALIGN(PAGE_SIZE);
   __nosave_end = .;
 
   __bss_start = .;		/* BSS */
   .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
-	*(.bss.page_aligned)
+	*(.bss..page_aligned)
 	*(.bss)
 	}
   __bss_stop = .;
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
index 67e6913..b515e04 100644
--- a/arch/xtensa/kernel/head.S
+++ b/arch/xtensa/kernel/head.S
@@ -234,7 +234,7 @@ should_never_return:
  * BSS section
  */
 	
-.section ".bss.page_aligned", "w"
+.section ".bss..page_aligned", "w"
 ENTRY(swapper_pg_dir)
 	.fill	PAGE_SIZE, 1, 0
 ENTRY(empty_zero_page)
diff --git a/arch/xtensa/kernel/init_task.c b/arch/xtensa/kernel/init_task.c
index e07f5c9..d07db9b 100644
--- a/arch/xtensa/kernel/init_task.c
+++ b/arch/xtensa/kernel/init_task.c
@@ -28,7 +28,7 @@ struct mm_struct init_mm = INIT_MM(init_mm);
 EXPORT_SYMBOL(init_mm);
 
 union thread_union init_thread_union
-	__attribute__((__section__(".data.init_task"))) =
+	__attribute__((__section__(".data..init_task"))) =
 { INIT_THREAD_INFO(init_task) };
 
 struct task_struct init_task = INIT_TASK(init_task);
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
index d506774..06aa28b 100644
--- a/arch/xtensa/kernel/vmlinux.lds.S
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -121,14 +121,14 @@ SECTIONS
     DATA_DATA
     CONSTRUCTORS
     . = ALIGN(XCHAL_ICACHE_LINESIZE);
-    *(.data.cacheline_aligned)
+    *(.data..cacheline_aligned)
   }
 
   _edata = .;
 
   /* The initial task */
   . = ALIGN(8192);
-  .data.init_task : { *(.data.init_task) }
+  .data..init_task : { *(.data..init_task) }
 
   /* Initialization code and data: */
 
@@ -259,7 +259,7 @@ SECTIONS
 
   /* BSS section */
   _bss_start = .;
-  .bss : { *(.bss.page_aligned) *(.bss) }
+  .bss : { *(.bss..page_aligned) *(.bss) }
   _bss_end = .;
 
   _end = .;
diff --git a/include/asm-frv/init.h b/include/asm-frv/init.h
index 8b15838..4d21473 100644
--- a/include/asm-frv/init.h
+++ b/include/asm-frv/init.h
@@ -1,12 +1,12 @@
 #ifndef _ASM_INIT_H
 #define _ASM_INIT_H
 
-#define __init __attribute__ ((__section__ (".text.init")))
-#define __initdata __attribute__ ((__section__ (".data.init")))
+#define __init __attribute__ ((__section__ (".text..init")))
+#define __initdata __attribute__ ((__section__ (".data..init")))
 /* For assembly routines */
-#define __INIT		.section	".text.init",#alloc,#execinstr
+#define __INIT		.section	".text..init",#alloc,#execinstr
 #define __FINIT		.previous
-#define __INITDATA	.section	".data.init",#alloc,#write
+#define __INITDATA	.section	".data..init",#alloc,#write
 
 #endif
 
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index c61fab1..0485f0b 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -64,7 +64,7 @@
 /* .data section */
 #define DATA_DATA							\
 	*(.data)							\
-	*(.data.init.refok)						\
+	*(.data..init.refok)						\
 	*(.ref.data)							\
 	DEV_KEEP(init.data)						\
 	DEV_KEEP(exit.data)						\
@@ -255,8 +255,8 @@
 		*(.text.hot)						\
 		*(.text)						\
 		*(.ref.text)						\
-		*(.text.init.refok)					\
-		*(.exit.text.refok)					\
+		*(.text..init.refok)					\
+		*(.text..exit.refok)					\
 	DEV_KEEP(init.text)						\
 	DEV_KEEP(exit.text)						\
 	CPU_KEEP(init.text)						\
@@ -433,9 +433,9 @@
 #define PERCPU(align)							\
 	. = ALIGN(align);						\
 	VMLINUX_SYMBOL(__per_cpu_start) = .;				\
-	.data.percpu  : AT(ADDR(.data.percpu) - LOAD_OFFSET) {		\
-		*(.data.percpu.page_aligned)				\
-		*(.data.percpu)						\
-		*(.data.percpu.shared_aligned)				\
+	.data..percpu  : AT(ADDR(.data..percpu) - LOAD_OFFSET) {	\
+		*(.data..percpu.page_aligned)				\
+		*(.data..percpu)					\
+		*(.data..percpu.shared_aligned)				\
 	}								\
 	VMLINUX_SYMBOL(__per_cpu_end) = .;
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 97e2488..4c57065 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -31,7 +31,7 @@
 #ifndef __cacheline_aligned
 #define __cacheline_aligned					\
   __attribute__((__aligned__(SMP_CACHE_BYTES),			\
-		 __section__(".data.cacheline_aligned")))
+		 __section__(".data..cacheline_aligned")))
 #endif /* __cacheline_aligned */
 
 #ifndef __cacheline_aligned_in_smp
diff --git a/include/linux/init.h b/include/linux/init.h
index 68cb026..f87423d 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -62,9 +62,9 @@
 
 /* backward compatibility note
  *  A few places hardcode the old section names:
- *  .text.init.refok
- *  .data.init.refok
- *  .exit.text.refok
+ *  .text..init.refok
+ *  .data..init.refok
+ *  .text..exit.refok
  *  They should be converted to use the defines from this file
  */
 
@@ -301,7 +301,7 @@ void __init parse_early_param(void);
 #endif
 
 /* Data marked not to be saved by software suspend */
-#define __nosavedata __section(.data.nosave)
+#define __nosavedata __section(.data..nosave)
 
 /* This means "can be init if no module support, otherwise module load
    may call it." */
diff --git a/include/linux/linkage.h b/include/linux/linkage.h
index fee9e59..bddaee6 100644
--- a/include/linux/linkage.h
+++ b/include/linux/linkage.h
@@ -18,8 +18,8 @@
 # define asmregparm
 #endif
 
-#define __page_aligned_data	__section(.data.page_aligned) __aligned(PAGE_SIZE)
-#define __page_aligned_bss	__section(.bss.page_aligned) __aligned(PAGE_SIZE)
+#define __page_aligned_data	__section(.data..page_aligned) __aligned(PAGE_SIZE)
+#define __page_aligned_bss	__section(.bss..page_aligned) __aligned(PAGE_SIZE)
 
 /*
  * This is used by architectures to keep arguments on the stack
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index 9f2a375..c89a214 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -10,13 +10,13 @@
 
 #ifdef CONFIG_SMP
 #define DEFINE_PER_CPU(type, name)					\
-	__attribute__((__section__(".data.percpu")))			\
+	__attribute__((__section__(".data..percpu")))			\
 	PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
 
 #ifdef MODULE
-#define SHARED_ALIGNED_SECTION ".data.percpu"
+#define SHARED_ALIGNED_SECTION ".data..percpu"
 #else
-#define SHARED_ALIGNED_SECTION ".data.percpu.shared_aligned"
+#define SHARED_ALIGNED_SECTION ".data..percpu.shared_aligned"
 #endif
 
 #define DEFINE_PER_CPU_SHARED_ALIGNED(type, name)			\
@@ -24,8 +24,8 @@
 	PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name		\
 	____cacheline_aligned_in_smp
 
-#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)			\
-	__attribute__((__section__(".data.percpu.page_aligned")))	\
+#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name)				\
+	__attribute__((__section__(".data..percpu.page_aligned")))	\
 	PER_CPU_ATTRIBUTES __typeof__(type) per_cpu__##name
 #else
 #define DEFINE_PER_CPU(type, name)					\
diff --git a/include/linux/spinlock.h b/include/linux/spinlock.h
index a0c66a2..710c825 100644
--- a/include/linux/spinlock.h
+++ b/include/linux/spinlock.h
@@ -60,7 +60,7 @@
 /*
  * Must define these before including other files, inline functions need them
  */
-#define LOCK_SECTION_NAME ".text.lock."KBUILD_BASENAME
+#define LOCK_SECTION_NAME ".text..lock."KBUILD_BASENAME
 
 #define LOCK_SECTION_START(extra)               \
         ".subsection 1\n\t"                     \
diff --git a/kernel/module.c b/kernel/module.c
index fe723e0..77fbf38 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -475,7 +475,7 @@ static unsigned int find_pcpusec(Elf_Ehdr *hdr,
 				 Elf_Shdr *sechdrs,
 				 const char *secstrings)
 {
-	return find_sec(hdr, sechdrs, secstrings, ".data.percpu");
+	return find_sec(hdr, sechdrs, secstrings, ".data..percpu");
 }
 
 static void percpu_modcopy(void *pcpudest, const void *from, unsigned long size)
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8892161..a7e282e 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -794,9 +794,9 @@ static const char *data_sections[] = { DATA_SECTIONS, NULL };
 /* sections that may refer to an init/exit section with no warning */
 static const char *initref_sections[] =
 {
-	".text.init.refok*",
-	".exit.text.refok*",
-	".data.init.refok*",
+	".text..init.refok*",
+	".text..exit.refok*",
+	".data..init.refok*",
 	NULL
 };
 
@@ -915,7 +915,7 @@ static int section_mismatch(const char *fromsec, const char *tosec)
  * Pattern 0:
  *   Do not warn if funtion/data are marked with __init_refok/__initdata_refok.
  *   The pattern is identified by:
- *   fromsec = .text.init.refok* | .data.init.refok*
+ *   fromsec = .text..init.refok* | .data..init.refok*
  *
  * Pattern 1:
  *   If a module parameter is declared __initdata and permissions=0
@@ -939,8 +939,8 @@ static int section_mismatch(const char *fromsec, const char *tosec)
  *           *probe_one, *_console, *_timer
  *
  * Pattern 3:
- *   Whitelist all refereces from .text.head to .init.data
- *   Whitelist all refereces from .text.head to .init.text
+ *   Whitelist all references from .text..head to .init.data
+ *   Whitelist all references from .text..head to .init.text
  *
  * Pattern 4:
  *   Some symbols belong to init section but still it is ok to reference
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl
index fe83141..da33ef9 100755
--- a/scripts/recordmcount.pl
+++ b/scripts/recordmcount.pl
@@ -26,7 +26,7 @@
 # which will also be the location of that section after final link.
 # e.g.
 #
-#  .section ".text.sched"
+#  .section ".text..sched"
 #  .globl my_func
 #  my_func:
 #        [...]
@@ -39,7 +39,7 @@
 #        [...]
 #
 # Both relocation offsets for the mcounts in the above example will be
-# offset from .text.sched. If we make another file called tmp.s with:
+# offset from .text..sched. If we make another file called tmp.s with:
 #
 #  .section __mcount_loc
 #  .quad  my_func + 0x5
@@ -51,7 +51,7 @@
 # But this gets hard if my_func is not globl (a static function).
 # In such a case we have:
 #
-#  .section ".text.sched"
+#  .section ".text..sched"
 #  my_func:
 #        [...]
 #        call mcount  (offset: 0x5)
-- 
1.6.1.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/4] x86: Add an option to compile with -ffunction-sections -fdata-sections
  2009-02-25  0:21 ` [PATCH v2 1/4] Make section names compatible with -ffunction-sections -fdata-sections Tim Abbott
@ 2009-02-25  0:21   ` Tim Abbott
  2009-02-25  0:21     ` [PATCH v2 3/4] Ksplice: Export symbols needed for Ksplice Tim Abbott
  2009-02-25  1:21     ` [PATCH v2 2/4] x86: Add an option to compile with -ffunction-sections -fdata-sections H. Peter Anvin
  0 siblings, 2 replies; 8+ messages in thread
From: Tim Abbott @ 2009-02-25  0:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tim Abbott, Anders Kaseorg, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

From: Waseem Daher <wdaher@mit.edu>

This patch makes it possible to link and boot an x86 kernel with
-ffunction-sections and -fdata-sections enabled.

Modpost currently warns whenever it sees a section with a name
matching [.][0-9]+$ because they are often caused by section flag
mismatch errors.  When compiling with -ffunction-sections
-fdata-sections, gcc places various classes of local symbols in
sections with names such as .rodata.__func__.12345, causing these
warnings to be printed spuriously.  The simplest fix is to disable the
warning when CONFIG_FUNCTION_DATA_SECTIONS is enabled.

Signed-off-by: Waseem Daher <wdaher@mit.edu>
[tabbott@mit.edu: modpost support]
Signed-off-by: Tim Abbott <tabbott@mit.edu>
[andersk@mit.edu: depend on x86, update CONFIG_FUNCTION_TRACER conflict]
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 Makefile                          |    4 ++++
 arch/x86/Kconfig                  |    1 +
 arch/x86/kernel/vmlinux_32.lds.S  |    1 +
 arch/x86/kernel/vmlinux_64.lds.S  |    1 +
 include/asm-generic/vmlinux.lds.h |    5 ++++-
 lib/Kconfig.debug                 |   18 ++++++++++++++++++
 scripts/Makefile.modpost          |    1 +
 scripts/mod/modpost.c             |   10 ++++++++--
 8 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 22d7584..b95cf67 100644
--- a/Makefile
+++ b/Makefile
@@ -550,6 +550,10 @@ ifdef CONFIG_FUNCTION_TRACER
 KBUILD_CFLAGS	+= -pg
 endif
 
+ifdef CONFIG_FUNCTION_DATA_SECTIONS
+KBUILD_CFLAGS	+= -ffunction-sections -fdata-sections
+endif
+
 # We trigger additional mismatches with less inlining
 ifdef CONFIG_DEBUG_SECTION_MISMATCH
 KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 9c39095..d3a991c 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -28,6 +28,7 @@ config X86
 	select HAVE_KPROBES
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARCH_WANT_FRAME_POINTERS
+	select HAVE_FUNCTION_DATA_SECTIONS
 	select HAVE_KRETPROBES
 	select HAVE_FTRACE_MCOUNT_RECORD
 	select HAVE_DYNAMIC_FTRACE
diff --git a/arch/x86/kernel/vmlinux_32.lds.S b/arch/x86/kernel/vmlinux_32.lds.S
index 31c131a..fbc5c3f 100644
--- a/arch/x86/kernel/vmlinux_32.lds.S
+++ b/arch/x86/kernel/vmlinux_32.lds.S
@@ -194,6 +194,7 @@ SECTIONS
 	__bss_start = .;		/* BSS */
 	*(.bss..page_aligned)
 	*(.bss)
+	*(.bss.[A-Za-z$_]*)		/* handle -fdata-sections */
 	. = ALIGN(4);
 	__bss_stop = .;
   	_end = . ;
diff --git a/arch/x86/kernel/vmlinux_64.lds.S b/arch/x86/kernel/vmlinux_64.lds.S
index 56ed592..6e03cb2 100644
--- a/arch/x86/kernel/vmlinux_64.lds.S
+++ b/arch/x86/kernel/vmlinux_64.lds.S
@@ -223,6 +223,7 @@ SECTIONS
   .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
 	*(.bss..page_aligned)
 	*(.bss)
+	*(.bss.[A-Za-z$_]*)	/* handle -fdata-sections */
 	}
   __bss_stop = .;
 
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 0485f0b..2b31598 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -64,6 +64,7 @@
 /* .data section */
 #define DATA_DATA							\
 	*(.data)							\
+	*(.data.[A-Za-z$_]*)	/* handle -fdata-sections */		\
 	*(.data..init.refok)						\
 	*(.ref.data)							\
 	DEV_KEEP(init.data)						\
@@ -87,7 +88,8 @@
 	. = ALIGN((align));						\
 	.rodata           : AT(ADDR(.rodata) - LOAD_OFFSET) {		\
 		VMLINUX_SYMBOL(__start_rodata) = .;			\
-		*(.rodata) *(.rodata.*)					\
+		*(.rodata)						\
+		*(.rodata.[A-Za-z$_]*)	/* handle -fdata-sections */	\
 		*(__vermagic)		/* Kernel version magic */	\
 		*(__markers_strings)	/* Markers: strings */		\
 		*(__tracepoints_strings)/* Tracepoints: strings */	\
@@ -254,6 +256,7 @@
 		ALIGN_FUNCTION();					\
 		*(.text.hot)						\
 		*(.text)						\
+		*(.text.[A-Za-z$_]*)	/* handle -ffunction-sections */\
 		*(.ref.text)						\
 		*(.text..init.refok)					\
 		*(.text..exit.refok)					\
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 29044f5..3412706 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -591,6 +591,24 @@ config FRAME_POINTER
 	  larger and slower, but it gives very useful debugging information
 	  in case of kernel bugs. (precise oopses/stacktraces/warnings)
 
+config HAVE_FUNCTION_DATA_SECTIONS
+	bool
+
+config FUNCTION_DATA_SECTIONS
+	bool "Compile with -ffunction-sections -fdata-sections"
+	depends on HAVE_FUNCTION_DATA_SECTIONS
+	depends on !FUNCTION_TRACER
+	help
+	  If you say Y here the compiler will give each function
+	  and data structure its own ELF section.
+
+	  This option conflicts with CONFIG_FUNCTION_TRACER, which
+	  enables profiling code generation, because current GCC does
+	  not support compiling with -ffunction-sections -pg (see
+	  <http://gcc.gnu.org/ml/gcc-help/2008-11/msg00128.html>).
+
+	  If unsure, say N.
+
 config BOOT_PRINTK_DELAY
 	bool "Delay each boot printk message by N milliseconds"
 	depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY
diff --git a/scripts/Makefile.modpost b/scripts/Makefile.modpost
index f4053dc..a712bb2 100644
--- a/scripts/Makefile.modpost
+++ b/scripts/Makefile.modpost
@@ -87,6 +87,7 @@ modpost = scripts/mod/modpost                    \
  $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S)      \
  $(if $(CONFIG_MARKERS),-K $(kernelmarkersfile)) \
  $(if $(CONFIG_MARKERS),-M $(markersfile))	 \
+ $(if $(filter -ffunction-sections -fdata-sections,$(KBUILD_CFLAGS) $(CFLAGS_KERNEL)),-F) \
  $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) \
  $(if $(cross_build),-c)
 
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index a7e282e..8a99299 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -32,6 +32,8 @@ static int warn_unresolved = 0;
 /* How a symbol is exported */
 static int sec_mismatch_count = 0;
 static int sec_mismatch_verbose = 1;
+/* Are we using -ffunction-sections or -fdata-sections? */
+static int function_data_sections = 0;
 
 enum export {
 	export_plain,      export_unused,     export_gpl,
@@ -736,7 +738,8 @@ static int check_section(const char *modname, const char *sec)
 		/* consume all digits */
 		while (*e && e != sec && isdigit(*e))
 			e--;
-		if (*e == '.' && !strstr(sec, ".linkonce")) {
+		if (*e == '.' && !strstr(sec, ".linkonce") &&
+		    !function_data_sections) {
 			warn("%s (%s): unexpected section name.\n"
 			     "The (.[number]+) following section name are "
 			     "ld generated and not expected.\n"
@@ -2063,7 +2066,7 @@ int main(int argc, char **argv)
 	struct ext_sym_list *extsym_iter;
 	struct ext_sym_list *extsym_start = NULL;
 
-	while ((opt = getopt(argc, argv, "i:I:e:cmsSo:awM:K:")) != -1) {
+	while ((opt = getopt(argc, argv, "i:I:e:cFmsSo:awM:K:")) != -1) {
 		switch (opt) {
 		case 'i':
 			kernel_read = optarg;
@@ -2083,6 +2086,9 @@ int main(int argc, char **argv)
 			extsym_iter->file = optarg;
 			extsym_start = extsym_iter;
 			break;
+		case 'F':
+			function_data_sections = 1;
+			break;
 		case 'm':
 			modversions = 1;
 			break;
-- 
1.6.1.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/4] Ksplice: Export symbols needed for Ksplice
  2009-02-25  0:21   ` [PATCH v2 2/4] x86: Add an option to compile " Tim Abbott
@ 2009-02-25  0:21     ` Tim Abbott
  2009-02-25  0:21       ` [PATCH v2 4/4] Ksplice: Support updating x86-32 and x86-64 Tim Abbott
  2009-02-25  1:21     ` [PATCH v2 2/4] x86: Add an option to compile with -ffunction-sections -fdata-sections H. Peter Anvin
  1 sibling, 1 reply; 8+ messages in thread
From: Tim Abbott @ 2009-02-25  0:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tim Abbott, Anders Kaseorg, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

Ksplice uses __module_address and __module_text_address to determine
which module contains various addresses.

Ksplice uses __kernel_text_address to limit its check for trampolines
(jump instructions inserted by Ksplice) to only text addresses.

Ksplice uses task_curr in order to confirm that no other tasks are
executing during Ksplice's kernel stack check.

Ksplice uses find_bug and search_exception_tables as part of its
conservative check that the user provided the correct source code for
the running kernel.

Signed-off-by: Tim Abbott <tabbott@mit.edu>
---
 kernel/extable.c |    3 +++
 kernel/module.c  |    2 ++
 kernel/sched.c   |    1 +
 lib/bug.c        |    1 +
 4 files changed, 7 insertions(+), 0 deletions(-)

diff --git a/kernel/extable.c b/kernel/extable.c
index 384f0da..ce08fe8 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -40,6 +40,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr)
 		e = search_module_extables(addr);
 	return e;
 }
+EXPORT_SYMBOL_GPL(search_exception_tables);
 
 __notrace_funcgraph int core_kernel_text(unsigned long addr)
 {
@@ -60,6 +61,7 @@ __notrace_funcgraph int __kernel_text_address(unsigned long addr)
 		return 1;
 	return is_module_text_address(addr);
 }
+EXPORT_SYMBOL_GPL(__kernel_text_address);
 
 int kernel_text_address(unsigned long addr)
 {
@@ -83,3 +85,4 @@ int func_ptr_is_kernel_text(void *ptr)
 		return 1;
 	return is_module_text_address(addr);
 }
+EXPORT_SYMBOL_GPL(kernel_text_address);
diff --git a/kernel/module.c b/kernel/module.c
index 77fbf38..b3135db 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2760,6 +2760,7 @@ __notrace_funcgraph struct module *__module_address(unsigned long addr)
 			return mod;
 	return NULL;
 }
+EXPORT_SYMBOL_GPL(__module_address);
 
 /*
  * is_module_text_address - is this address inside module code?
@@ -2798,6 +2799,7 @@ struct module *__module_text_address(unsigned long addr)
 	}
 	return mod;
 }
+EXPORT_SYMBOL_GPL(__module_text_address);
 
 /* Don't grab lock, we're oopsing. */
 void print_modules(void)
diff --git a/kernel/sched.c b/kernel/sched.c
index c1d0ed3..a35f940 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -1801,6 +1801,7 @@ inline int task_curr(const struct task_struct *p)
 {
 	return cpu_curr(task_cpu(p)) == p;
 }
+EXPORT_SYMBOL_GPL(task_curr);
 
 static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu)
 {
diff --git a/lib/bug.c b/lib/bug.c
index 300e41a..c8491f9 100644
--- a/lib/bug.c
+++ b/lib/bug.c
@@ -124,6 +124,7 @@ const struct bug_entry *find_bug(unsigned long bugaddr)
 
 	return module_find_bug(bugaddr);
 }
+EXPORT_SYMBOL_GPL(find_bug);
 
 enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
 {
-- 
1.6.1.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 4/4] Ksplice: Support updating x86-32 and x86-64
  2009-02-25  0:21     ` [PATCH v2 3/4] Ksplice: Export symbols needed for Ksplice Tim Abbott
@ 2009-02-25  0:21       ` Tim Abbott
  0 siblings, 0 replies; 8+ messages in thread
From: Tim Abbott @ 2009-02-25  0:21 UTC (permalink / raw)
  To: linux-kernel
  Cc: Tim Abbott, Anders Kaseorg, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

From: Jeff Arnold <jbarnold@mit.edu>

Ksplice makes it possible to apply patches to the kernel without rebooting.

Signed-off-by: Jeff Arnold <jbarnold@mit.edu>
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
Signed-off-by: Tim Abbott <tabbott@mit.edu>
Tested-by: Waseem Daher <wdaher@mit.edu>
---
 Documentation/ksplice.txt      |  304 ++++
 MAINTAINERS                    |   10 +
 arch/Kconfig                   |   14 +
 arch/x86/Kconfig               |    1 +
 arch/x86/kernel/ksplice-arch.c |   96 ++
 include/linux/kernel.h         |    1 +
 include/linux/ksplice.h        |  224 +++
 kernel/Makefile                |    3 +
 kernel/ksplice.c               | 2995 ++++++++++++++++++++++++++++++++++++++++
 kernel/panic.c                 |    1 +
 10 files changed, 3649 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/ksplice.txt
 create mode 100644 arch/x86/kernel/ksplice-arch.c
 create mode 100644 include/linux/ksplice.h
 create mode 100644 kernel/ksplice.c

diff --git a/Documentation/ksplice.txt b/Documentation/ksplice.txt
new file mode 100644
index 0000000..648d015
--- /dev/null
+++ b/Documentation/ksplice.txt
@@ -0,0 +1,304 @@
+Ksplice
+-------
+
+CONTENTS:
+
+1. Concepts: updates, module changes, target modules
+2. What changes can Ksplice handle?
+3. Dependency model
+4. Locking model
+5. altinstructions, smplocks, and parainstructions
+6. sysfs interface
+7. debugfs interface
+8. Hooks for running custom code during the update process
+
+0. Design Description
+---------------------
+
+For a description of the Ksplice design, please see the Ksplice
+technical overview document: <http://www.ksplice.com/doc/ksplice.pdf>.
+For usage examples and the Ksplice man pages, please see
+<http://www.ksplice.com>.
+
+The document below assumes familiarity with the Ksplice design and
+describes notable implementation details and the interface between the
+Ksplice kernel component and the Ksplice user space component.
+
+1. Concepts: updates, module changes, target modules
+----------------------------------------------------
+
+A Ksplice update (struct update) contains one or more Ksplice module
+changes (struct ksplice_mod_change), one for each target kernel module
+that should be changed by the update.  ksplice_mod_changes are grouped
+together into a Ksplice update in order to allow multiple modules to
+be changed atomically.
+
+The contents of a Ksplice module change are documented via kernel-doc
+in include/linux/ksplice.h.  To construct a new Ksplice update to be
+performed atomically, one needs to:
+  1. Populate the fields of one or more ksplice_mod_change structures.
+  2. Call the Ksplice function init_ksplice_mod_change() on each
+     ksplice_mod_change to register them with the Ksplice kernel
+     component.  When init_ksplice_mod_change() is called on a
+     ksplice_mod_change, that ksplice_mod_change will be associated
+     with the other ksplice_mod_changes that share the same Ksplice
+     identifier (KID) field.
+  3. After all of the mod_changes intended for a particular Ksplice
+     update have been loaded, that update can be applied via the sysfs
+     interface (described in Section 7 below).
+
+Each ksplice_mod_change has a two modules associated with it: an
+old_code module and a new_code module.
+
+A ksplice_mod_change's "old_code" module contains materials needed
+only for preparing the update.  Specifically, the old_code module
+contains a copy of the pre-patch version of each of the compilation
+units changed by the ksplice_mod_change.  The old_code module can be
+unloaded after the update has been applied in order to save memory.
+
+The ksplice_mod_change's "new_code" module contains the new sections
+to be inserted by the update; it needs to remain loaded for as long as
+the update is applied.
+
+Here's an example:
+
+Let's say that the Ksplice user space component wants to update the
+core kernel and the isdn module.  The user space component will select
+a KID for this update (let's say 123abc) and generate four modules:
+
+ksplice_123abc_vmlinux_new (the new_code module for the vmlinux module change)
+ksplice_123abc_vmlinux_old (the old_code module for the vmlinux module change)
+ksplice_123abc_isdn_new (the new_code module for the isdn module change)
+ksplice_123abc_isdn_old (the old_code module for the isdn module change)
+
+Once both of the vmlinux modules have been loaded, one of the modules
+calls init_ksplice_mod_change on a ksplice_mod_change corresponding to
+the desired vmlinux changes.
+
+Similarly, once both of the isdn modules have been loaded, one of the
+modules calls init_ksplice_mod_change on a ksplice_mod_change
+corresponding to the desired isdn changes.
+
+Once all modules are loaded (in this example, four modules), the
+update can be applied atomically using the Ksplice sysfs interface.
+
+2. What changes can Ksplice handle?
+-----------------------------------
+
+The Ksplice user space component takes a source code patch and uses it
+to construct appropriate ksplice_mod_changes for an update.  Ksplice
+can handle source code patches that add new functions, modify the text
+or arguments of existing functions, delete functions, move functions
+between compilation units, change functions from local to global (or
+vice versa), add exported symbols, rename exported symbols, and delete
+exported symbols.  Ksplice can handle patches that modify either C
+code or assembly code.
+
+As described in the Ksplice technical overview document, a programmer
+needs to write some new code in order for Ksplice to apply a patch
+that makes semantic changes to kernel data structures.  Some other
+limitations also apply:
+
+Ksplice does not support changes to __init functions that been
+unloaded from kernel memory.  Ksplice also does not support changes to
+functions in .exit.text sections since Ksplice currently requires that
+all Ksplice updates affecting a module be reversed before that module
+can be unloaded.
+
+The Ksplice user space implementation does not currently support
+changes to weak symbols and changes to global read-only data
+structures (changes to read-only data structures that are local to a
+compilation unit are fine).
+
+Exported symbols:
+
+Ksplice can handle arbitrary changes to exported symbols in the source
+code patch.
+
+Ksplice deletes exported symbols by looking up the relevant struct
+kernel_symbol in the kernel's exported symbol table and replacing the
+name field with a pointer to a string that begins with DISABLED.
+
+Ksplice adds new exported symbols through the same mechanism; the
+relevant new_code module will have a ksymtab entry containing a symbol
+with a name beginning with DISABLED, and Ksplice will replace that
+with the name of the symbol to be exported when the update is
+atomically applied.
+
+Because the struct kernel_symbol for a newly exported symbol is
+contained in the Ksplice new_Code module, if a module using one of the
+newly exported symbols is loaded, that module will correctly depend on
+the Ksplice new_code module that exported the symbol.
+
+3. Dependency model
+-------------------
+
+Because Ksplice resolves symbols used in the post code using Ksplice
+relocations, Ksplice must enforce additional dependencies.  Ksplice
+uses the use_module function to directly add dependencies on all the
+modules that the post code references.
+
+4. Locking model
+----------------
+
+From a locking perspective, Ksplice treats applying or removing a
+Ksplice update as analogous to loading or unloading a new version of
+the kernel modules patched by the update.  Ksplice uses module_mutex
+to protect against a variety of race conditions related to modules
+being loaded or unloaded while Ksplice is applying or reversing an
+update; this approach also protects against race conditions involving
+multiple Ksplice updates being loaded or unloaded simultaneously as
+well.
+
+5. altinstructions, smplocks, and parainstructions
+--------------------------------------------------
+
+There are currently several mechanisms through which the Linux kernel
+will modify executable code at runtime.
+
+These mechanisms sometimes overwrite the storage unit of a relocation,
+which would cause problems if not handled properly by Ksplice.
+
+Ksplice solves this problem by writing "canary" bytes (e.g.,
+0x77777777) in the storage unit of the relocation in user space.
+Ksplice then checks whether the canary has been overwritten before
+using a Ksplice relocation to detect symbol values or to write a value
+to the storage unit of a Ksplice relocation.
+
+6. sysfs interface
+------------------
+
+Ksplice exports four sysfs files per Ksplice update in order to
+communicate with user space.  For each update, these four files are
+located in a directory of the form /sys/kernel/ksplice/$kid, with $kid
+replaced by the KID of the Ksplice update.
+
+A.  /sys/kernel/ksplice/$kid/stage (mode 0600)
+
+This file contains one of three strings:
+preparing: Indicates that this update has not yet been applied
+applied:   Indicates that this update has been applied and has not been reversed
+reversed:  Indicates that this update has been reversed
+
+When the stage is "preparing", the superuser can write "applied" to
+the stage file in order to instruct Ksplice to apply the update.  When
+the stage is "applied", the superuser can write "reversed" to the
+stage file in order to instruct Ksplice to reverse the update.
+Afterwards, the superuser can write "cleanup" to the stage file in
+order to instruct Ksplice to clean up the debugging information and
+sysfs directory associated with the reversed update.  Once an update
+is reversed, it cannot be re-applied without first cleaning up the
+update.
+
+B.  /sys/kernel/ksplice/$kid/debug (mode 0600)
+
+The file contains a single number: 1 if debugging is enabled for this
+Ksplice update and 0 otherwise.
+
+The superuser can write a new value to this file to enable or disable
+debugging.
+
+C.  /sys/kernel/ksplice/$kid/partial (mode 0600)
+
+The file contains a single number: 1 if the update should be applied
+even if some of the target modules are not loaded and 0 otherwise.
+
+D.  /sys/kernel/ksplice/$kid/abort_cause (mode 0400)
+
+This file contains a value indicating either 1) that Ksplice
+successfully completed the most recently requested stage transition or
+2) why Ksplice aborted the most recently requested stage transition.
+
+Each abort_code string is described below, along with the stage
+transitions that might potentially trigger each possible abort code.
+The stage transitions are abbreviated as follows: preparing->applied
+(P->A), applied->reversed (A->R).
+
+ok (P->A, A->R): The most recent stage transition succeeded.
+
+no_match (P->A): Ksplice aborted the update because Ksplice was unable
+to match the old_code module's object code against the running
+kernel's object code.
+
+failed_to_find (P->A): Ksplice aborted the update because Ksplice was
+unable to resolve some of the symbols used in the update.
+
+missing_export (P->A): Ksplice aborted the update because the symbols
+exported by the kernel did not match Ksplice's expectations.
+
+already_reversed (P->A): Ksplice aborted the update because once an
+update has been reversed, it cannot be applied again (without first
+being cleaned up and reinitialized).
+
+module_busy (A->R): Ksplice aborted the undo operation because the
+target Ksplice update is in use by another kernel module;
+specifically, either the target Ksplice update exports a symbol that
+is in use by another module or another Ksplice update depends on this
+Ksplice update.
+
+out_of_memory (P->A, A->R): Ksplice aborted the operation because a call to
+kmalloc or vmalloc failed.
+
+code_busy (P->A, A->R): Ksplice aborted the operation because Ksplice
+was unable to find a moment when one or more of the to-be-patched
+functions was not a thread's kernel stack.
+
+target_not_loaded (P->A): Ksplice aborted the update because one of
+the target modules is not loaded and the partial option
+(/sys/kernel/ksplice/$kid/partial) is not enabled.
+
+call_failed (P->A, A->R): One of the calls included as part of this
+update returned nonzero exit status.
+
+unexpected_running_task (P->A, A->R): Ksplice aborted the operation
+because Ksplice observed a running task during the kernel stack check,
+at a time when Ksplice expected all tasks to be stopped by
+stop_machine.
+
+unexpected (P->A, A->R): Ksplice aborted the operation because it
+encountered an unspecified internal error.  This condition can only be
+caused by an invalid input to Ksplice or a bug in Ksplice.
+
+E.  /sys/kernel/ksplice/$kid/conflicts (mode 0400)
+
+This file is empty until Ksplice aborts an operation because of a
+code_busy condition (see "abort_code" above).  This conflicts file
+then contains information about the process(es) that caused the stack
+check failure.
+
+Specifically, each line of this file consists of three space-separated
+values, describing a single conflict:
+
+$program_name $program_pid $conflict_label
+
+$program_name is the name of the program with the conflict.
+$program_pid is the pid of the program with the conflict.
+$conflict_label is the Ksplice label of the function with the conflict.
+
+7. debugfs interface
+--------------------
+
+Ksplice exports a single file to debugfs for each Ksplice update.  The
+file has a name of the form ksplice_KID, where KID is the unique
+identifier of the Ksplice update.  It contains debugging information
+in a human-readable format.
+
+8. Hooks for running custom code during the update process
+----------------------------------------------------------
+
+Ksplice allows a programmer to write custom code to be called from
+within the kernel during the update process.  The kernel component
+allows custom code to be executed at the following times:
+
+- pre_apply: Called before the update has been applied and before the
+machine has been stopped.  Allowed to fail.
+- check_apply: Called before the update has been applied but after the
+machine has been stopped.  Allowed to fail.
+- apply: Called when the update is definitely going to be applied and
+when the machine is stopped.  Not allowed to fail.
+- post_apply: Called when the update has been applied and the machine
+is no longer stopped.  Not allowed to fail.
+- fail_apply: Called when the update failed to apply and the machine
+is no longer stopped.  Not allowed to fail.
+
+Ksplice also provides analagous xxx_reverse hooks.
diff --git a/MAINTAINERS b/MAINTAINERS
index db65b4e..6b52212 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2636,6 +2636,16 @@ W:	http://miguelojeda.es/auxdisplay.htm
 W:	http://jair.lab.fi.uva.es/~migojed/auxdisplay.htm
 S:	Maintained
 
+KSPLICE
+P:	Jeff Arnold
+M:	jbarnold@ksplice.com
+P:	Anders Kaseorg
+M:	andersk@ksplice.com
+P:	Tim Abbott
+M:	tabbott@ksplice.com
+W:	http://www.ksplice.com
+S:	Supported
+
 LAPB module
 L:	linux-x25@vger.kernel.org
 S:	Orphan
diff --git a/arch/Kconfig b/arch/Kconfig
index 550dab2..d84326b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -43,6 +43,17 @@ config KPROBES
 	  for kernel debugging, non-intrusive instrumentation and testing.
 	  If in doubt, say "N".
 
+config KSPLICE
+	tristate "Ksplice rebootless kernel updates"
+	depends on KALLSYMS_ALL && MODULE_UNLOAD && SYSFS && \
+		   FUNCTION_DATA_SECTIONS
+	depends on HAVE_KSPLICE
+	help
+          Say Y here if you want to be able to apply certain kinds of
+          patches to your running kernel, without rebooting.
+
+          If unsure, say N.
+
 config HAVE_EFFICIENT_UNALIGNED_ACCESS
 	bool
 	help
@@ -75,6 +86,9 @@ config HAVE_IOREMAP_PROT
 config HAVE_KPROBES
 	bool
 
+config HAVE_KSPLICE
+	def_bool n
+
 config HAVE_KRETPROBES
 	bool
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index d3a991c..bc3e68a 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -26,6 +26,7 @@ config X86
 	select HAVE_OPROFILE
 	select HAVE_IOREMAP_PROT
 	select HAVE_KPROBES
+	select HAVE_KSPLICE
 	select ARCH_WANT_OPTIONAL_GPIOLIB
 	select ARCH_WANT_FRAME_POINTERS
 	select HAVE_FUNCTION_DATA_SECTIONS
diff --git a/arch/x86/kernel/ksplice-arch.c b/arch/x86/kernel/ksplice-arch.c
new file mode 100644
index 0000000..c60bf79
--- /dev/null
+++ b/arch/x86/kernel/ksplice-arch.c
@@ -0,0 +1,96 @@
+/*  Copyright (C) 2007-2009  Ksplice, Inc.
+ *  Authors: Jeff Arnold, Anders Kaseorg, Tim Abbott
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#define KSPLICE_IP(x) ((x)->thread.ip)
+#define KSPLICE_SP(x) ((x)->thread.sp)
+
+static struct ksplice_symbol trampoline_symbol = {
+	.name = NULL,
+	.label = "<trampoline>",
+};
+
+static const struct ksplice_reloc_howto trampoline_howto = {
+	.type = KSPLICE_HOWTO_RELOC,
+	.pcrel = 1,
+	.size = 4,
+	.dst_mask = 0xffffffffL,
+	.rightshift = 0,
+	.signed_addend = 1,
+};
+
+static const struct ksplice_reloc trampoline_reloc = {
+	.symbol = &trampoline_symbol,
+	.insn_addend = -4,
+	.target_addend = 0,
+	.howto = &trampoline_howto,
+};
+
+static abort_t trampoline_target(struct ksplice_mod_change *change,
+				 unsigned long addr, unsigned long *new_addr)
+{
+	abort_t ret;
+	unsigned char byte;
+
+	if (probe_kernel_read(&byte, (void *)addr, sizeof(byte)) == -EFAULT)
+		return NO_MATCH;
+
+	if (byte != 0xe9)
+		return NO_MATCH;
+
+	ret = read_reloc_value(change, &trampoline_reloc, addr + 1, new_addr);
+	if (ret != OK)
+		return ret;
+
+	*new_addr += addr + 1;
+	return OK;
+}
+
+static abort_t prepare_trampoline(struct ksplice_mod_change *change,
+				  struct ksplice_patch *p)
+{
+	p->size = 5;
+	((unsigned char *)p->contents)[0] = 0xe9;
+	return write_reloc_value(change, &trampoline_reloc,
+				 (unsigned long)p->contents + 1,
+				 p->repladdr - (p->oldaddr + 1));
+}
+
+static abort_t handle_paravirt(struct ksplice_mod_change *change,
+			       unsigned long pre_addr, unsigned long run_addr,
+			       int *matched)
+{
+	unsigned char run[5], pre[5];
+	*matched = 0;
+
+	if (probe_kernel_read(&run, (void *)run_addr, sizeof(run)) == -EFAULT ||
+	    probe_kernel_read(&pre, (void *)pre_addr, sizeof(pre)) == -EFAULT)
+		return OK;
+
+	if ((run[0] == 0xe8 && pre[0] == 0xe8) ||
+	    (run[0] == 0xe9 && pre[0] == 0xe9))
+		if (run_addr + 1 + *(int32_t *)&run[1] ==
+		    pre_addr + 1 + *(int32_t *)&pre[1])
+			*matched = 5;
+	return OK;
+}
+
+static bool valid_stack_ptr(const struct thread_info *tinfo, const void *p)
+{
+	return p > (const void *)tinfo
+	    && p <= (const void *)tinfo + THREAD_SIZE - sizeof(long);
+}
+
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 7fa3718..95990e1 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -307,6 +307,7 @@ extern enum system_states {
 #define TAINT_OVERRIDDEN_ACPI_TABLE	8
 #define TAINT_WARN			9
 #define TAINT_CRAP			10
+#define TAINT_KSPLICE			11
 
 extern void dump_stack(void) __cold;
 
diff --git a/include/linux/ksplice.h b/include/linux/ksplice.h
new file mode 100644
index 0000000..fbedd25
--- /dev/null
+++ b/include/linux/ksplice.h
@@ -0,0 +1,224 @@
+#include <linux/types.h>
+
+/**
+ * struct ksplice_symbol - Ksplice's analogue of an ELF symbol
+ * @name:		The ELF name of the symbol
+ * @label:		A unique Ksplice name for the symbol
+ * @candidate_vals:	A linked list of possible values for the symbol, or NULL
+ * @value:		The value of the symbol (valid when vals is NULL)
+ **/
+struct ksplice_symbol {
+	const char *name;
+	const char *label;
+/* private: */
+	struct list_head *candidate_vals;
+	unsigned long value;
+};
+
+/**
+ * struct ksplice_reloc - Ksplice's analogue of an ELF relocation
+ * @blank_addr:		The address of the relocation's storage unit
+ * @symbol:		The ksplice_symbol associated with this relocation
+ * @howto:		The information regarding the relocation type
+ * @addend:		The ELF addend of the relocation
+ **/
+struct ksplice_reloc {
+	unsigned long blank_addr;
+	struct ksplice_symbol *symbol;
+	const struct ksplice_reloc_howto *howto;
+	long insn_addend;
+	long target_addend;
+};
+
+enum ksplice_reloc_howto_type {
+	KSPLICE_HOWTO_RELOC,
+	KSPLICE_HOWTO_RELOC_PATCH,
+	KSPLICE_HOWTO_DATE,
+	KSPLICE_HOWTO_TIME,
+	KSPLICE_HOWTO_BUG,
+	KSPLICE_HOWTO_EXTABLE,
+};
+
+/**
+ * struct ksplice_reloc_howto - Ksplice's relocation type information
+ * @type:		The type of the relocation
+ * @pcrel:		Is the relocation PC relative?
+ * @size:		The size, in bytes, of the item to be relocated
+ * @dst_mask:		Bitmask for which parts of the instruction or data are
+ * 			replaced with the relocated value
+ * 			(based on dst_mask from GNU BFD's reloc_howto_struct)
+ * @rightshift:		The value the final relocation is shifted right by;
+ * 			used to drop unwanted data from the relocation
+ * 			(based on rightshift from GNU BFD's reloc_howto_struct)
+ * @signed_addend:	Should the addend be interpreted as a signed value?
+ **/
+struct ksplice_reloc_howto {
+	enum ksplice_reloc_howto_type type;
+	int pcrel;
+	int size;
+	long dst_mask;
+	unsigned int rightshift;
+	int signed_addend;
+};
+
+#if BITS_PER_LONG == 32
+#define KSPLICE_CANARY 0x77777777UL
+#elif BITS_PER_LONG == 64
+#define KSPLICE_CANARY 0x7777777777777777UL
+#endif /* BITS_PER_LONG */
+
+/**
+ * struct ksplice_section - Ksplice's analogue of an ELF section
+ * @symbol:		The ksplice_symbol associated with this section
+ * @size:		The length, in bytes, of this section
+ * @address:		The address of the section
+ * @flags:		Flags indicating the type of the section, whether or
+ *			not it has been matched, etc.
+ **/
+struct ksplice_section {
+	struct ksplice_symbol *symbol;
+	unsigned long address;
+	unsigned long size;
+	unsigned int flags;
+	const unsigned char **match_map;
+};
+#define KSPLICE_SECTION_TEXT 0x00000001
+#define KSPLICE_SECTION_RODATA 0x00000002
+#define KSPLICE_SECTION_DATA 0x00000004
+#define KSPLICE_SECTION_STRING 0x00000008
+#define KSPLICE_SECTION_MATCHED 0x10000000
+
+#define MAX_TRAMPOLINE_SIZE 5
+
+enum ksplice_patch_type {
+	KSPLICE_PATCH_TEXT,
+	KSPLICE_PATCH_BUGLINE,
+	KSPLICE_PATCH_DATA,
+	KSPLICE_PATCH_EXPORT,
+};
+
+/**
+ * struct ksplice_patch - A replacement that Ksplice should perform
+ * @oldaddr:		The address of the obsolete function or structure
+ * @repladdr:		The address of the replacement function
+ * @type:		The type of the ksplice patch
+ * @size:		The size of the patch
+ * @contents:		The bytes to be installed at oldaddr
+ * @vaddr		The address of the page mapping used to write at oldaddr
+ * @saved:		The bytes originally at oldaddr which were
+ * 			overwritten by the patch
+ **/
+struct ksplice_patch {
+	unsigned long oldaddr;
+	unsigned long repladdr;
+	enum ksplice_patch_type type;
+	unsigned int size;
+	void *contents;
+/* private: */
+	void *vaddr;
+	void *saved;
+};
+
+#ifdef __KERNEL__
+#include <linux/module.h>
+#include <linux/stringify.h>
+
+#define _PASTE(x, y) x##y
+#define PASTE(x, y) _PASTE(x, y)
+#define KSPLICE_UNIQ(s) PASTE(s##_, KSPLICE_MID)
+#define KSPLICE_KID_UNIQ(s) PASTE(s##_, KSPLICE_KID)
+
+/**
+ * struct ksplice_module_list_entry - A record of a ksplice_mod_change's target
+ * @target_mod_name:	The name of the ksplice_mod_change's target module
+ * @new_code_mod_name:	The name of the ksplice_mod_change's new_code module
+ * @applied:		Whether the ksplice_mod_change was applied or not (this
+ *			will be false for ksplice_mod_changes patching targets
+ *			that are not loaded when the partial flag is set)
+ **/
+struct ksplice_module_list_entry {
+	const char *target_mod_name;
+	const char *new_code_mod_name;
+	const char *kid;
+	bool applied;
+/* private: */
+	struct list_head update_list;	/* list head for this is per-update */
+	struct list_head list;	/* list head for this is global */
+};
+
+/* List of all ksplice modules and the module they patch */
+extern struct list_head ksplice_modules;
+
+/* There are two actions, apply and reverse */
+#define KS_ACTIONS 2
+enum ksplice_action {
+	KS_APPLY,
+	KS_REVERSE,
+};
+
+/**
+ * struct ksplice_hooks - Hooks to be run during an action (apply or reverse)
+ * @pre:			Runs before the action;
+ * 				may return nonzero to abort the action
+ * @check:			Runs inside stop_machine before the action;
+ * 				may return nonzero to abort the action
+ * @intra:			Runs inside stop_machine during the action
+ * @post:			Runs after the action is successfully performed
+ * @fail:			Runs if the action is aborted for any reason
+ */
+struct ksplice_hooks {
+	const typeof(int (*)(void)) *pre, *pre_end, *check, *check_end;
+	const typeof(void (*)(void)) *intra, *intra_end, *post, *post_end,
+	    *fail, *fail_end;
+};
+
+/**
+ * struct ksplice_code - Ksplice metadata for an object
+ * @relocs:		The Ksplice relocations for the object
+ * @symbols:		The Ksplice symbols for the object
+ * @sections:		The Ksplice sections for the object
+ **/
+struct ksplice_code {
+	struct ksplice_reloc *relocs, *relocs_end;
+	struct ksplice_section *sections, *sections_end;
+	struct ksplice_symbol *symbols, *symbols_end;
+};
+
+/**
+ * struct ksplice_mod_change - Data for one module modified by a Ksplice update
+ * @name:			The name of the new_code module for the change
+ * @kid:			The Ksplice unique identifier for the change
+ * @target_name:		The name of the module modified by the change
+ * @new_code_mod:		The new_code module for the change
+ * @old_code:			The old code for run-pre matching
+ * @new_code:			The new code to switch to
+ * @patches:			The function replacements in the change
+ * @patches_end:		The end pointer for patches array
+ * @hooks:			Hooks to be run during apply and reverse
+ * @update:			The atomic update the change is part of
+ * @target:			The module modified by the change
+ * @safety_records:		The ranges of addresses that must not be on a
+ *				kernel stack for the patch to apply safely
+ **/
+struct ksplice_mod_change {
+	const char *name;
+	const char *kid;
+	const char *target_name;
+	struct module *new_code_mod;
+	struct ksplice_code old_code, new_code;
+	struct ksplice_patch *patches, *patches_end;
+	struct ksplice_hooks hooks[KS_ACTIONS];
+/* private: */
+	struct update *update;
+	struct module *target;
+	struct list_head temp_labelvals;
+	struct list_head safety_records;
+	struct list_head list;
+};
+
+
+int init_ksplice_mod_change(struct ksplice_mod_change *change);
+
+void cleanup_ksplice_mod_change(struct ksplice_mod_change *change);
+
+#endif /* __KERNEL__ */
diff --git a/kernel/Makefile b/kernel/Makefile
index 170a921..1a95df9 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -12,6 +12,8 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
 	    async.o
 
+CFLAGS_ksplice.o += -Iarch/$(SRCARCH)/kernel
+
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
 CFLAGS_REMOVE_lockdep.o = -pg
@@ -71,6 +73,7 @@ obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
 obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
 obj-$(CONFIG_AUDIT_TREE) += audit_tree.o
 obj-$(CONFIG_KPROBES) += kprobes.o
+obj-$(CONFIG_KSPLICE) += ksplice.o
 obj-$(CONFIG_KGDB) += kgdb.o
 obj-$(CONFIG_DETECT_SOFTLOCKUP) += softlockup.o
 obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
diff --git a/kernel/ksplice.c b/kernel/ksplice.c
new file mode 100644
index 0000000..f6528e0
--- /dev/null
+++ b/kernel/ksplice.c
@@ -0,0 +1,2995 @@
+/*  Copyright (C) 2007-2009  Ksplice, Inc.
+ *  Authors: Jeff Arnold, Anders Kaseorg, Tim Abbott
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/bug.h>
+#include <linux/ctype.h>
+#include <linux/debugfs.h>
+#include <linux/errno.h>
+#include <linux/kallsyms.h>
+#include <linux/kobject.h>
+#include <linux/kthread.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/sort.h>
+#include <linux/stop_machine.h>
+#include <linux/sysfs.h>
+#include <linux/time.h>
+#include <linux/uaccess.h>
+#include <linux/vmalloc.h>
+#include <linux/ksplice.h>
+
+enum stage {
+	STAGE_PREPARING,	/* the update is not yet applied */
+	STAGE_APPLIED,		/* the update is applied */
+	STAGE_REVERSED,		/* the update has been applied and reversed */
+};
+
+/* parameter to modify run-pre matching */
+enum run_pre_mode {
+	RUN_PRE_INITIAL,	/* dry run (only change temp_labelvals) */
+	RUN_PRE_DEBUG,		/* dry run with byte-by-byte debugging */
+	RUN_PRE_FINAL,		/* finalizes the matching */
+};
+
+enum { NOVAL, TEMP, VAL };
+
+typedef int __bitwise__ abort_t;
+
+#define OK ((__force abort_t) 0)
+#define NO_MATCH ((__force abort_t) 1)
+#define CODE_BUSY ((__force abort_t) 2)
+#define MODULE_BUSY ((__force abort_t) 3)
+#define OUT_OF_MEMORY ((__force abort_t) 4)
+#define FAILED_TO_FIND ((__force abort_t) 5)
+#define ALREADY_REVERSED ((__force abort_t) 6)
+#define MISSING_EXPORT ((__force abort_t) 7)
+#define UNEXPECTED_RUNNING_TASK ((__force abort_t) 8)
+#define UNEXPECTED ((__force abort_t) 9)
+#define TARGET_NOT_LOADED ((__force abort_t) 10)
+#define CALL_FAILED ((__force abort_t) 11)
+#define COLD_UPDATE_LOADED ((__force abort_t) 12)
+
+struct update {
+	const char *kid;
+	const char *name;
+	struct kobject kobj;
+	enum stage stage;
+	abort_t abort_cause;
+	int debug;
+#ifdef CONFIG_DEBUG_FS
+	struct debugfs_blob_wrapper debug_blob;
+	struct dentry *debugfs_dentry;
+#else /* !CONFIG_DEBUG_FS */
+	bool debug_continue_line;
+#endif /* CONFIG_DEBUG_FS */
+	bool partial;		/* is it OK if some target mods aren't loaded */
+	struct list_head changes,	/* changes for loaded target mods */
+	    unused_changes;		/* changes for non-loaded target mods */
+	struct list_head conflicts;
+	struct list_head list;
+	struct list_head ksplice_module_list;
+};
+
+/* a process conflicting with an update */
+struct conflict {
+	const char *process_name;
+	pid_t pid;
+	struct list_head stack;
+	struct list_head list;
+};
+
+/* an address on the stack of a conflict */
+struct conflict_addr {
+	unsigned long addr;	/* the address on the stack */
+	bool has_conflict;	/* does this address in particular conflict? */
+	const char *label;	/* the label of the conflicting safety_record */
+	struct list_head list;
+};
+
+struct labelval {
+	struct list_head list;
+	struct ksplice_symbol *symbol;
+	struct list_head *saved_vals;
+};
+
+/* region to be checked for conflicts in the stack check */
+struct safety_record {
+	struct list_head list;
+	const char *label;
+	unsigned long addr;	/* the address to be checked for conflicts
+				 * (e.g. an obsolete function's starting addr)
+				 */
+	unsigned long size;	/* the size of the region to be checked */
+};
+
+/* possible value for a symbol */
+struct candidate_val {
+	struct list_head list;
+	unsigned long val;
+};
+
+/* private struct used by init_symbol_array */
+struct ksplice_lookup {
+/* input */
+	struct ksplice_mod_change *change;
+	struct ksplice_symbol **arr;
+	size_t size;
+/* output */
+	abort_t ret;
+};
+
+static LIST_HEAD(updates);
+LIST_HEAD(ksplice_modules);
+EXPORT_SYMBOL_GPL(ksplice_modules);
+static struct kobject *ksplice_kobj;
+
+static struct kobj_type update_ktype;
+
+static struct update *init_ksplice_update(const char *kid);
+static void cleanup_ksplice_update(struct update *update);
+static void maybe_cleanup_ksplice_update(struct update *update);
+static void add_to_update(struct ksplice_mod_change *change,
+			  struct update *update);
+static int ksplice_sysfs_init(struct update *update);
+
+/* Preparing the relocations and patches for application */
+static abort_t apply_update(struct update *update);
+static abort_t reverse_update(struct update *update);
+static abort_t prepare_change(struct ksplice_mod_change *change);
+static abort_t finalize_change(struct ksplice_mod_change *change);
+static abort_t finalize_patches(struct ksplice_mod_change *change);
+static abort_t add_dependency_on_address(struct ksplice_mod_change *change,
+					 unsigned long addr);
+static abort_t map_trampoline_pages(struct update *update);
+static void unmap_trampoline_pages(struct update *update);
+static void *map_writable(void *addr, size_t len);
+static abort_t apply_relocs(struct ksplice_mod_change *change,
+			    const struct ksplice_reloc *relocs,
+			    const struct ksplice_reloc *relocs_end);
+static abort_t apply_reloc(struct ksplice_mod_change *change,
+			   const struct ksplice_reloc *r);
+static abort_t apply_howto_reloc(struct ksplice_mod_change *change,
+				 const struct ksplice_reloc *r);
+static abort_t apply_howto_date(struct ksplice_mod_change *change,
+				const struct ksplice_reloc *r);
+static abort_t read_reloc_value(struct ksplice_mod_change *change,
+				const struct ksplice_reloc *r,
+				unsigned long addr, unsigned long *valp);
+static abort_t write_reloc_value(struct ksplice_mod_change *change,
+				 const struct ksplice_reloc *r,
+				 unsigned long addr, unsigned long sym_addr);
+static abort_t create_module_list_entry(struct ksplice_mod_change *change,
+					bool to_be_applied);
+static void cleanup_module_list_entries(struct update *update);
+static void __attribute__((noreturn)) ksplice_deleted(void);
+
+/* run-pre matching */
+static abort_t match_change_sections(struct ksplice_mod_change *change,
+				   bool consider_data_sections);
+static abort_t find_section(struct ksplice_mod_change *change,
+			    struct ksplice_section *sect);
+static abort_t try_addr(struct ksplice_mod_change *change,
+			struct ksplice_section *sect,
+			unsigned long run_addr,
+			struct list_head *safety_records,
+			enum run_pre_mode mode);
+static abort_t run_pre_cmp(struct ksplice_mod_change *change,
+			   const struct ksplice_section *sect,
+			   unsigned long run_addr,
+			   struct list_head *safety_records,
+			   enum run_pre_mode mode);
+static void print_bytes(struct ksplice_mod_change *change,
+			const unsigned char *run, int runc,
+			const unsigned char *pre, int prec);
+static const struct ksplice_reloc *
+init_reloc_search(struct ksplice_mod_change *change,
+		  const struct ksplice_section *sect);
+static const struct ksplice_reloc *find_reloc(const struct ksplice_reloc *start,
+					      const struct ksplice_reloc *end,
+					      unsigned long address,
+					      unsigned long size);
+static abort_t lookup_reloc(struct ksplice_mod_change *change,
+			    const struct ksplice_reloc **fingerp,
+			    unsigned long addr,
+			    const struct ksplice_reloc **relocp);
+static abort_t handle_reloc(struct ksplice_mod_change *change,
+			    const struct ksplice_section *sect,
+			    const struct ksplice_reloc *r,
+			    unsigned long run_addr, enum run_pre_mode mode);
+static abort_t handle_howto_date(struct ksplice_mod_change *change,
+				 const struct ksplice_section *sect,
+				 const struct ksplice_reloc *r,
+				 unsigned long run_addr,
+				 enum run_pre_mode mode);
+static abort_t handle_howto_reloc(struct ksplice_mod_change *change,
+				  const struct ksplice_section *sect,
+				  const struct ksplice_reloc *r,
+				  unsigned long run_addr,
+				  enum run_pre_mode mode);
+#ifdef CONFIG_BUG
+static abort_t handle_bug(struct ksplice_mod_change *change,
+			  const struct ksplice_reloc *r,
+			  unsigned long run_addr);
+#endif /* CONFIG_BUG */
+static abort_t handle_extable(struct ksplice_mod_change *change,
+			      const struct ksplice_reloc *r,
+			      unsigned long run_addr);
+static struct ksplice_section *symbol_section(struct ksplice_mod_change *change,
+					      const struct ksplice_symbol *sym);
+static int compare_section_labels(const void *va, const void *vb);
+static int symbol_section_bsearch_compare(const void *a, const void *b);
+static const struct ksplice_reloc *
+patch_reloc(struct ksplice_mod_change *change,
+	    const struct ksplice_patch *p);
+
+/* Computing possible addresses for symbols */
+static abort_t lookup_symbol(struct ksplice_mod_change *change,
+			     const struct ksplice_symbol *ksym,
+			     struct list_head *vals);
+static void cleanup_symbol_arrays(struct ksplice_mod_change *change);
+static abort_t init_symbol_arrays(struct ksplice_mod_change *change);
+static abort_t init_symbol_array(struct ksplice_mod_change *change,
+				 struct ksplice_symbol *start,
+				 struct ksplice_symbol *end);
+static abort_t uniquify_symbols(struct ksplice_mod_change *change);
+static abort_t add_matching_values(struct ksplice_lookup *lookup,
+				   const char *sym_name, unsigned long sym_val);
+static bool add_export_values(const struct symsearch *syms,
+			      struct module *owner,
+			      unsigned int symnum, void *data);
+static int symbolp_bsearch_compare(const void *key, const void *elt);
+static int compare_symbolp_names(const void *a, const void *b);
+static int compare_symbolp_labels(const void *a, const void *b);
+static int add_kallsyms_values(void *data, const char *name,
+			       struct module *owner, unsigned long val);
+static abort_t new_export_lookup(struct ksplice_mod_change *ichange,
+				 const char *name, struct list_head *vals);
+
+/* Atomic update trampoline insertion and removal */
+static abort_t patch_action(struct update *update, enum ksplice_action action);
+static int __apply_patches(void *update);
+static int __reverse_patches(void *update);
+static abort_t check_each_task(struct update *update);
+static abort_t check_task(struct update *update,
+			  const struct task_struct *t, bool rerun);
+static abort_t check_stack(struct update *update, struct conflict *conf,
+			   const struct thread_info *tinfo,
+			   const unsigned long *stack);
+static abort_t check_address(struct update *update,
+			     struct conflict *conf, unsigned long addr);
+static abort_t check_record(struct conflict_addr *ca,
+			    const struct safety_record *rec,
+			    unsigned long addr);
+static bool is_stop_machine(const struct task_struct *t);
+static void cleanup_conflicts(struct update *update);
+static void print_conflicts(struct update *update);
+static void insert_trampoline(struct ksplice_patch *p);
+static abort_t verify_trampoline(struct ksplice_mod_change *change,
+				 const struct ksplice_patch *p);
+static void remove_trampoline(const struct ksplice_patch *p);
+
+static abort_t create_labelval(struct ksplice_mod_change *change,
+			       struct ksplice_symbol *ksym,
+			       unsigned long val, int status);
+static abort_t create_safety_record(struct ksplice_mod_change *change,
+				    const struct ksplice_section *sect,
+				    struct list_head *record_list,
+				    unsigned long run_addr,
+				    unsigned long run_size);
+static abort_t add_candidate_val(struct ksplice_mod_change *change,
+				 struct list_head *vals, unsigned long val);
+static void release_vals(struct list_head *vals);
+static void set_temp_labelvals(struct ksplice_mod_change *change, int status);
+
+static int contains_canary(struct ksplice_mod_change *change,
+			   unsigned long blank_addr,
+			   const struct ksplice_reloc_howto *howto);
+static unsigned long follow_trampolines(struct ksplice_mod_change *change,
+					unsigned long addr);
+static bool patches_module(const struct module *a, const struct module *b);
+static bool strstarts(const char *str, const char *prefix);
+static bool singular(struct list_head *list);
+static void *bsearch(const void *key, const void *base, size_t n,
+		     size_t size, int (*cmp)(const void *key, const void *elt));
+static int compare_relocs(const void *a, const void *b);
+static int reloc_bsearch_compare(const void *key, const void *elt);
+
+/* Debugging */
+static abort_t init_debug_buf(struct update *update);
+static void clear_debug_buf(struct update *update);
+static int __attribute__((format(printf, 2, 3)))
+_ksdebug(struct update *update, const char *fmt, ...);
+#define ksdebug(change, fmt, ...) \
+	_ksdebug(change->update, fmt, ## __VA_ARGS__)
+
+/* Architecture-specific functions defined in arch/ARCH/kernel/ksplice-arch.c */
+
+/* Prepare a trampoline for the given patch */
+static abort_t prepare_trampoline(struct ksplice_mod_change *change,
+				  struct ksplice_patch *p);
+/* What address does the trampoline at addr jump to? */
+static abort_t trampoline_target(struct ksplice_mod_change *change,
+				 unsigned long addr, unsigned long *new_addr);
+/* Hook to handle pc-relative jumps inserted by parainstructions */
+static abort_t handle_paravirt(struct ksplice_mod_change *change,
+			       unsigned long pre, unsigned long run,
+			       int *matched);
+/* Is address p on the stack of the given thread? */
+static bool valid_stack_ptr(const struct thread_info *tinfo, const void *p);
+
+#include "ksplice-arch.c"
+
+#define clear_list(head, type, member)				\
+	do {							\
+		struct list_head *_pos, *_n;			\
+		list_for_each_safe(_pos, _n, head) {		\
+			list_del(_pos);				\
+			kfree(list_entry(_pos, type, member));	\
+		}						\
+	} while (0)
+
+/**
+ * init_ksplice_mod_change() - Initializes a ksplice change
+ * @change:	The change to be initialized.  All of the public fields of the
+ * 		change and its associated data structures should be populated
+ * 		before this function is called.  The values of the private
+ * 		fields will be ignored.
+ **/
+int init_ksplice_mod_change(struct ksplice_mod_change *change)
+{
+	struct update *update;
+	struct ksplice_patch *p;
+	struct ksplice_section *s;
+	int ret = 0;
+
+	INIT_LIST_HEAD(&change->temp_labelvals);
+	INIT_LIST_HEAD(&change->safety_records);
+
+	sort(change->old_code.relocs,
+	     change->old_code.relocs_end - change->old_code.relocs,
+	     sizeof(*change->old_code.relocs), compare_relocs, NULL);
+	sort(change->new_code.relocs,
+	     change->new_code.relocs_end - change->new_code.relocs,
+	     sizeof(*change->new_code.relocs), compare_relocs, NULL);
+	sort(change->old_code.sections,
+	     change->old_code.sections_end - change->old_code.sections,
+	     sizeof(*change->old_code.sections), compare_section_labels, NULL);
+
+	for (p = change->patches; p < change->patches_end; p++)
+		p->vaddr = NULL;
+	for (s = change->old_code.sections; s < change->old_code.sections_end;
+	     s++)
+		s->match_map = NULL;
+	for (p = change->patches; p < change->patches_end; p++) {
+		const struct ksplice_reloc *r = patch_reloc(change, p);
+		if (r == NULL)
+			return -ENOENT;
+		if (p->type == KSPLICE_PATCH_DATA) {
+			s = symbol_section(change, r->symbol);
+			if (s == NULL)
+				return -ENOENT;
+			/* Ksplice creates KSPLICE_PATCH_DATA patches in order
+			 * to modify rodata sections that have been explicitly
+			 * marked for patching using the ksplice-patch.h macro
+			 * ksplice_assume_rodata.  Here we modify the section
+			 * flags appropriately.
+			 */
+			if (s->flags & KSPLICE_SECTION_DATA)
+				s->flags = (s->flags & ~KSPLICE_SECTION_DATA) |
+				    KSPLICE_SECTION_RODATA;
+		}
+	}
+
+	mutex_lock(&module_mutex);
+	list_for_each_entry(update, &updates, list) {
+		if (strcmp(change->kid, update->kid) == 0) {
+			if (update->stage != STAGE_PREPARING) {
+				ret = -EPERM;
+				goto out;
+			}
+			add_to_update(change, update);
+			ret = 0;
+			goto out;
+		}
+	}
+	update = init_ksplice_update(change->kid);
+	if (update == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	ret = ksplice_sysfs_init(update);
+	if (ret != 0) {
+		cleanup_ksplice_update(update);
+		goto out;
+	}
+	add_to_update(change, update);
+out:
+	mutex_unlock(&module_mutex);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(init_ksplice_mod_change);
+
+/**
+ * cleanup_ksplice_mod_change() - Cleans up a change if appropriate
+ * @change:	The change to be cleaned up
+ *
+ * cleanup_ksplice_mod_change is currently called twice for each
+ * Ksplice update; once when the old_code module is unloaded, and once
+ * when the new_code module is unloaded.  The extra call is used to
+ * avoid leaks if you unload the old_code without applying the update.
+ */
+void cleanup_ksplice_mod_change(struct ksplice_mod_change *change)
+{
+	if (change->update == NULL)
+		return;
+
+	mutex_lock(&module_mutex);
+	if (change->update->stage == STAGE_APPLIED) {
+		/* If the change wasn't actually applied (because we
+		 * only applied this update to loaded modules and this
+		 * target was not loaded), then unregister the change
+		 * from the list of unused changes.
+		 */
+		struct ksplice_mod_change *c;
+		bool found = false;
+
+		list_for_each_entry(c, &change->update->unused_changes, list) {
+			if (c == change)
+				found = true;
+		}
+		if (found)
+			list_del(&change->list);
+		mutex_unlock(&module_mutex);
+		return;
+	}
+	list_del(&change->list);
+	if (change->update->stage == STAGE_PREPARING)
+		maybe_cleanup_ksplice_update(change->update);
+	change->update = NULL;
+	mutex_unlock(&module_mutex);
+}
+EXPORT_SYMBOL_GPL(cleanup_ksplice_mod_change);
+
+static struct update *init_ksplice_update(const char *kid)
+{
+	struct update *update;
+	update = kcalloc(1, sizeof(struct update), GFP_KERNEL);
+	if (update == NULL)
+		return NULL;
+	update->name = kasprintf(GFP_KERNEL, "ksplice_%s", kid);
+	if (update->name == NULL) {
+		kfree(update);
+		return NULL;
+	}
+	update->kid = kstrdup(kid, GFP_KERNEL);
+	if (update->kid == NULL) {
+		kfree(update->name);
+		kfree(update);
+		return NULL;
+	}
+	if (try_module_get(THIS_MODULE) != 1) {
+		kfree(update->kid);
+		kfree(update->name);
+		kfree(update);
+		return NULL;
+	}
+	INIT_LIST_HEAD(&update->changes);
+	INIT_LIST_HEAD(&update->unused_changes);
+	INIT_LIST_HEAD(&update->ksplice_module_list);
+	if (init_debug_buf(update) != OK) {
+		module_put(THIS_MODULE);
+		kfree(update->kid);
+		kfree(update->name);
+		kfree(update);
+		return NULL;
+	}
+	list_add(&update->list, &updates);
+	update->stage = STAGE_PREPARING;
+	update->abort_cause = OK;
+	update->partial = 0;
+	INIT_LIST_HEAD(&update->conflicts);
+	return update;
+}
+
+static void cleanup_ksplice_update(struct update *update)
+{
+	list_del(&update->list);
+	cleanup_conflicts(update);
+	clear_debug_buf(update);
+	cleanup_module_list_entries(update);
+	kfree(update->kid);
+	kfree(update->name);
+	kfree(update);
+	module_put(THIS_MODULE);
+}
+
+/* Clean up the update if it no longer has any changes */
+static void maybe_cleanup_ksplice_update(struct update *update)
+{
+	if (list_empty(&update->changes) && list_empty(&update->unused_changes))
+		kobject_put(&update->kobj);
+}
+
+static void add_to_update(struct ksplice_mod_change *change,
+			  struct update *update)
+{
+	change->update = update;
+	list_add(&change->list, &update->unused_changes);
+}
+
+static int ksplice_sysfs_init(struct update *update)
+{
+	int ret = 0;
+	memset(&update->kobj, 0, sizeof(update->kobj));
+	ret = kobject_init_and_add(&update->kobj, &update_ktype,
+				   ksplice_kobj, "%s", update->kid);
+	if (ret != 0)
+		return ret;
+	kobject_uevent(&update->kobj, KOBJ_ADD);
+	return 0;
+}
+
+static abort_t apply_update(struct update *update)
+{
+	struct ksplice_mod_change *change, *n;
+	abort_t ret;
+	int retval;
+
+	list_for_each_entry(change, &update->changes, list) {
+		ret = create_module_list_entry(change, true);
+		if (ret != OK)
+			goto out;
+	}
+
+	list_for_each_entry_safe(change, n, &update->unused_changes, list) {
+		if (strcmp(change->target_name, "vmlinux") == 0) {
+			change->target = NULL;
+		} else if (change->target == NULL) {
+			change->target = find_module(change->target_name);
+			if (change->target == NULL ||
+			    !module_is_live(change->target)) {
+				if (!update->partial) {
+					ret = TARGET_NOT_LOADED;
+					goto out;
+				}
+				ret = create_module_list_entry(change, false);
+				if (ret != OK)
+					goto out;
+				continue;
+			}
+			retval = use_module(change->new_code_mod,
+					    change->target);
+			if (retval != 1) {
+				ret = UNEXPECTED;
+				goto out;
+			}
+		}
+		ret = create_module_list_entry(change, true);
+		if (ret != OK)
+			goto out;
+		list_del(&change->list);
+		list_add_tail(&change->list, &update->changes);
+
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		const struct ksplice_section *sect;
+		for (sect = change->new_code.sections;
+		     sect < change->new_code.sections_end; sect++) {
+			struct safety_record *rec = kmalloc(sizeof(*rec),
+							    GFP_KERNEL);
+			if (rec == NULL) {
+				ret = OUT_OF_MEMORY;
+				goto out;
+			}
+			rec->addr = sect->address;
+			rec->size = sect->size;
+			rec->label = sect->symbol->label;
+			list_add(&rec->list, &change->safety_records);
+		}
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		ret = init_symbol_arrays(change);
+		if (ret != OK) {
+			cleanup_symbol_arrays(change);
+			goto out;
+		}
+		ret = prepare_change(change);
+		cleanup_symbol_arrays(change);
+		if (ret != OK)
+			goto out;
+	}
+	ret = patch_action(update, KS_APPLY);
+out:
+	list_for_each_entry(change, &update->changes, list) {
+		struct ksplice_section *s;
+		if (update->stage == STAGE_PREPARING)
+			clear_list(&change->safety_records,
+				   struct safety_record, list);
+		for (s = change->old_code.sections;
+		     s < change->old_code.sections_end; s++) {
+			if (s->match_map != NULL) {
+				vfree(s->match_map);
+				s->match_map = NULL;
+			}
+		}
+	}
+	if (update->stage == STAGE_PREPARING)
+		cleanup_module_list_entries(update);
+
+	if (ret == OK)
+		printk(KERN_INFO "ksplice: Update %s applied successfully\n",
+		       update->kid);
+	return ret;
+}
+
+static abort_t reverse_update(struct update *update)
+{
+	abort_t ret;
+	struct ksplice_mod_change *change;
+
+	clear_debug_buf(update);
+	ret = init_debug_buf(update);
+	if (ret != OK)
+		return ret;
+
+	_ksdebug(update, "Preparing to reverse %s\n", update->kid);
+
+	ret = patch_action(update, KS_REVERSE);
+	if (ret != OK)
+		return ret;
+
+	list_for_each_entry(change, &update->changes, list)
+		clear_list(&change->safety_records, struct safety_record, list);
+
+	printk(KERN_INFO "ksplice: Update %s reversed successfully\n",
+	       update->kid);
+	return OK;
+}
+
+static int compare_symbolp_names(const void *a, const void *b)
+{
+	const struct ksplice_symbol *const *sympa = a, *const *sympb = b;
+	if ((*sympa)->name == NULL && (*sympb)->name == NULL)
+		return 0;
+	if ((*sympa)->name == NULL)
+		return -1;
+	if ((*sympb)->name == NULL)
+		return 1;
+	return strcmp((*sympa)->name, (*sympb)->name);
+}
+
+static int compare_symbolp_labels(const void *a, const void *b)
+{
+	const struct ksplice_symbol *const *sympa = a, *const *sympb = b;
+	return strcmp((*sympa)->label, (*sympb)->label);
+}
+
+static int symbolp_bsearch_compare(const void *key, const void *elt)
+{
+	const char *name = key;
+	const struct ksplice_symbol *const *symp = elt;
+	const struct ksplice_symbol *sym = *symp;
+	if (sym->name == NULL)
+		return 1;
+	return strcmp(name, sym->name);
+}
+
+static abort_t add_matching_values(struct ksplice_lookup *lookup,
+				   const char *sym_name, unsigned long sym_val)
+{
+	struct ksplice_symbol **symp;
+	abort_t ret;
+
+	symp = bsearch(sym_name, lookup->arr, lookup->size,
+		       sizeof(*lookup->arr), symbolp_bsearch_compare);
+	if (symp == NULL)
+		return OK;
+
+	while (symp > lookup->arr &&
+	       symbolp_bsearch_compare(sym_name, symp - 1) == 0)
+		symp--;
+
+	for (; symp < lookup->arr + lookup->size; symp++) {
+		struct ksplice_symbol *sym = *symp;
+		if (sym->name == NULL || strcmp(sym_name, sym->name) != 0)
+			break;
+		ret = add_candidate_val(lookup->change,
+					sym->candidate_vals, sym_val);
+		if (ret != OK)
+			return ret;
+	}
+	return OK;
+}
+
+static int add_kallsyms_values(void *data, const char *name,
+			       struct module *owner, unsigned long val)
+{
+	struct ksplice_lookup *lookup = data;
+	if (owner == lookup->change->new_code_mod ||
+	    !patches_module(owner, lookup->change->target))
+		return (__force int)OK;
+	return (__force int)add_matching_values(lookup, name, val);
+}
+
+static bool add_export_values(const struct symsearch *syms,
+			      struct module *owner,
+			      unsigned int symnum, void *data)
+{
+	struct ksplice_lookup *lookup = data;
+	abort_t ret;
+
+	ret = add_matching_values(lookup, syms->start[symnum].name,
+				  syms->start[symnum].value);
+	if (ret != OK) {
+		lookup->ret = ret;
+		return true;
+	}
+	return false;
+}
+
+static void cleanup_symbol_arrays(struct ksplice_mod_change *change)
+{
+	struct ksplice_symbol *sym;
+	for (sym = change->new_code.symbols; sym < change->new_code.symbols_end;
+	     sym++) {
+		if (sym->candidate_vals != NULL) {
+			clear_list(sym->candidate_vals, struct candidate_val,
+				   list);
+			kfree(sym->candidate_vals);
+			sym->candidate_vals = NULL;
+		}
+	}
+	for (sym = change->old_code.symbols; sym < change->old_code.symbols_end;
+	     sym++) {
+		if (sym->candidate_vals != NULL) {
+			clear_list(sym->candidate_vals, struct candidate_val,
+				   list);
+			kfree(sym->candidate_vals);
+			sym->candidate_vals = NULL;
+		}
+	}
+}
+
+/*
+ * The new_code and old_code modules each have their own independent
+ * ksplice_symbol structures.  uniquify_symbols unifies these separate
+ * pieces of kernel symbol information by replacing all references to
+ * the old_code copy of symbols with references to the new_code copy.
+ */
+static abort_t uniquify_symbols(struct ksplice_mod_change *change)
+{
+	struct ksplice_reloc *r;
+	struct ksplice_section *s;
+	struct ksplice_symbol *sym, **sym_arr, **symp;
+	size_t size = change->new_code.symbols_end - change->new_code.symbols;
+
+	if (size == 0)
+		return OK;
+
+	sym_arr = vmalloc(sizeof(*sym_arr) * size);
+	if (sym_arr == NULL)
+		return OUT_OF_MEMORY;
+
+	for (symp = sym_arr, sym = change->new_code.symbols;
+	     symp < sym_arr + size && sym < change->new_code.symbols_end;
+	     sym++, symp++)
+		*symp = sym;
+
+	sort(sym_arr, size, sizeof(*sym_arr), compare_symbolp_labels, NULL);
+
+	for (r = change->old_code.relocs; r < change->old_code.relocs_end;
+	     r++) {
+		symp = bsearch(&r->symbol, sym_arr, size, sizeof(*sym_arr),
+			       compare_symbolp_labels);
+		if (symp != NULL) {
+			if ((*symp)->name == NULL)
+				(*symp)->name = r->symbol->name;
+			r->symbol = *symp;
+		}
+	}
+
+	for (s = change->old_code.sections; s < change->old_code.sections_end;
+	     s++) {
+		symp = bsearch(&s->symbol, sym_arr, size, sizeof(*sym_arr),
+			       compare_symbolp_labels);
+		if (symp != NULL) {
+			if ((*symp)->name == NULL)
+				(*symp)->name = s->symbol->name;
+			s->symbol = *symp;
+		}
+	}
+
+	vfree(sym_arr);
+	return OK;
+}
+
+/*
+ * Initialize the ksplice_symbol structures in the given array using
+ * the kallsyms and exported symbol tables.
+ */
+static abort_t init_symbol_array(struct ksplice_mod_change *change,
+				 struct ksplice_symbol *start,
+				 struct ksplice_symbol *end)
+{
+	struct ksplice_symbol *sym, **sym_arr, **symp;
+	struct ksplice_lookup lookup;
+	size_t size = end - start;
+	abort_t ret;
+
+	if (size == 0)
+		return OK;
+
+	for (sym = start; sym < end; sym++) {
+		if (strstarts(sym->label, "__ksymtab")) {
+			const struct kernel_symbol *ksym;
+			const char *colon = strchr(sym->label, ':');
+			const char *name = colon + 1;
+			if (colon == NULL)
+				continue;
+			ksym = find_symbol(name, NULL, NULL, true, false);
+			if (ksym == NULL) {
+				ksdebug(change, "Could not find kernel_symbol "
+					"structure for %s\n", name);
+				continue;
+			}
+			sym->value = (unsigned long)ksym;
+			sym->candidate_vals = NULL;
+			continue;
+		}
+
+		sym->candidate_vals = kmalloc(sizeof(*sym->candidate_vals),
+					      GFP_KERNEL);
+		if (sym->candidate_vals == NULL)
+			return OUT_OF_MEMORY;
+		INIT_LIST_HEAD(sym->candidate_vals);
+		sym->value = 0;
+	}
+
+	sym_arr = vmalloc(sizeof(*sym_arr) * size);
+	if (sym_arr == NULL)
+		return OUT_OF_MEMORY;
+
+	for (symp = sym_arr, sym = start; symp < sym_arr + size && sym < end;
+	     sym++, symp++)
+		*symp = sym;
+
+	sort(sym_arr, size, sizeof(*sym_arr), compare_symbolp_names, NULL);
+
+	lookup.change = change;
+	lookup.arr = sym_arr;
+	lookup.size = size;
+	lookup.ret = OK;
+
+	each_symbol(add_export_values, &lookup);
+	ret = lookup.ret;
+	if (ret == OK)
+		ret = (__force abort_t)
+		    kallsyms_on_each_symbol(add_kallsyms_values, &lookup);
+	vfree(sym_arr);
+	return ret;
+}
+
+/* Prepare the change's ksplice_symbol structures for run-pre matching */
+static abort_t init_symbol_arrays(struct ksplice_mod_change *change)
+{
+	abort_t ret;
+
+	ret = uniquify_symbols(change);
+	if (ret != OK)
+		return ret;
+
+	ret = init_symbol_array(change, change->old_code.symbols,
+				change->old_code.symbols_end);
+	if (ret != OK)
+		return ret;
+
+	ret = init_symbol_array(change, change->new_code.symbols,
+				change->new_code.symbols_end);
+	if (ret != OK)
+		return ret;
+
+	return OK;
+}
+
+static abort_t prepare_change(struct ksplice_mod_change *change)
+{
+	abort_t ret;
+
+	ksdebug(change, "Preparing and checking %s\n", change->name);
+	ret = match_change_sections(change, false);
+	if (ret == NO_MATCH) {
+		/* It is possible that by using relocations from .data sections
+		 * we can successfully run-pre match the rest of the sections.
+		 * To avoid using any symbols obtained from .data sections
+		 * (which may be unreliable) in the post code, we first prepare
+		 * the post code and then try to run-pre match the remaining
+		 * sections with the help of .data sections.
+		 */
+		ksdebug(change, "Continuing without some sections; we might "
+			"find them later.\n");
+		ret = finalize_change(change);
+		if (ret != OK) {
+			ksdebug(change, "Aborted.  Unable to continue without "
+				"the unmatched sections.\n");
+			return ret;
+		}
+
+		ksdebug(change, "run-pre: Considering .data sections to find "
+			"the unmatched sections\n");
+		ret = match_change_sections(change, true);
+		if (ret != OK)
+			return ret;
+
+		ksdebug(change, "run-pre: Found all previously unmatched "
+			"sections\n");
+		return OK;
+	} else if (ret != OK) {
+		return ret;
+	}
+
+	return finalize_change(change);
+}
+
+/*
+ * Finish preparing the change for insertion into the kernel.
+ * Afterwards, the replacement code should be ready to run and the
+ * ksplice_patches should all be ready for trampoline insertion.
+ */
+static abort_t finalize_change(struct ksplice_mod_change *change)
+{
+	abort_t ret;
+	ret = apply_relocs(change, change->new_code.relocs,
+			   change->new_code.relocs_end);
+	if (ret != OK)
+		return ret;
+
+	ret = finalize_patches(change);
+	if (ret != OK)
+		return ret;
+
+	return OK;
+}
+
+static abort_t finalize_patches(struct ksplice_mod_change *change)
+{
+	struct ksplice_patch *p;
+	struct safety_record *rec;
+	abort_t ret;
+
+	for (p = change->patches; p < change->patches_end; p++) {
+		bool found = false;
+		list_for_each_entry(rec, &change->safety_records, list) {
+			if (rec->addr <= p->oldaddr &&
+			    p->oldaddr < rec->addr + rec->size) {
+				found = true;
+				break;
+			}
+		}
+		if (!found && p->type != KSPLICE_PATCH_EXPORT) {
+			const struct ksplice_reloc *r = patch_reloc(change, p);
+			if (r == NULL) {
+				ksdebug(change, "A patch with no reloc at its "
+					"oldaddr has no safety record\n");
+				return NO_MATCH;
+			}
+			ksdebug(change, "No safety record for patch with"
+				"oldaddr %s+%lx\n", r->symbol->label,
+				r->target_addend);
+			return NO_MATCH;
+		}
+
+		if (p->type == KSPLICE_PATCH_TEXT) {
+			ret = prepare_trampoline(change, p);
+			if (ret != OK)
+				return ret;
+		}
+
+		if (found && rec->addr + rec->size < p->oldaddr + p->size) {
+			ksdebug(change, "Safety record %s is too short for "
+				"patch\n", rec->label);
+			return UNEXPECTED;
+		}
+
+		if (p->type == KSPLICE_PATCH_TEXT) {
+			if (p->repladdr == 0)
+				p->repladdr = (unsigned long)ksplice_deleted;
+		}
+	}
+	return OK;
+}
+
+/* noinline to prevent garbage on the stack from confusing check_stack */
+static noinline abort_t map_trampoline_pages(struct update *update)
+{
+	struct ksplice_mod_change *change;
+	list_for_each_entry(change, &update->changes, list) {
+		struct ksplice_patch *p;
+		for (p = change->patches; p < change->patches_end; p++) {
+			p->vaddr = map_writable((void *)p->oldaddr, p->size);
+			if (p->vaddr == NULL) {
+				ksdebug(change,
+					"Unable to map oldaddr read/write\n");
+				unmap_trampoline_pages(update);
+				return UNEXPECTED;
+			}
+		}
+	}
+	return OK;
+}
+
+static void unmap_trampoline_pages(struct update *update)
+{
+	struct ksplice_mod_change *change;
+	list_for_each_entry(change, &update->changes, list) {
+		struct ksplice_patch *p;
+		for (p = change->patches; p < change->patches_end; p++) {
+			vunmap((void *)((unsigned long)p->vaddr & PAGE_MASK));
+			p->vaddr = NULL;
+		}
+	}
+}
+
+/*
+ * map_writable creates a shadow page mapping of the range
+ * [addr, addr + len) so that we can write to code mapped read-only.
+ *
+ * It is similar to a generalized version of x86's text_poke.  But
+ * because one cannot use vmalloc/vfree() inside stop_machine, we use
+ * map_writable to map the pages before stop_machine, then use the
+ * mapping inside stop_machine, and unmap the pages afterwards.
+ */
+static void *map_writable(void *addr, size_t len)
+{
+	void *vaddr;
+	int nr_pages = DIV_ROUND_UP(offset_in_page(addr) + len, PAGE_SIZE);
+	struct page **pages = kmalloc(nr_pages * sizeof(*pages), GFP_KERNEL);
+	void *page_addr = (void *)((unsigned long)addr & PAGE_MASK);
+	int i;
+
+	if (pages == NULL)
+		return NULL;
+
+	for (i = 0; i < nr_pages; i++) {
+		if (__module_address((unsigned long)page_addr) == NULL) {
+			pages[i] = virt_to_page(page_addr);
+			WARN_ON(!PageReserved(pages[i]));
+		} else {
+			pages[i] = vmalloc_to_page(addr);
+		}
+		if (pages[i] == NULL) {
+			kfree(pages);
+			return NULL;
+		}
+		page_addr += PAGE_SIZE;
+	}
+	vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
+	kfree(pages);
+	if (vaddr == NULL)
+		return NULL;
+	return vaddr + offset_in_page(addr);
+}
+
+/*
+ * Ksplice adds a dependency on any symbol address used to resolve
+ * relocations in the new_code module.
+ *
+ * Be careful to follow_trampolines so that we always depend on the
+ * latest version of the target function, since that's the code that
+ * will run if we call addr.
+ */
+static abort_t add_dependency_on_address(struct ksplice_mod_change *change,
+					 unsigned long addr)
+{
+	struct ksplice_mod_change *c;
+	struct module *m =
+	    __module_text_address(follow_trampolines(change, addr));
+	if (m == NULL)
+		return OK;
+	list_for_each_entry(c, &change->update->changes, list) {
+		if (m == c->new_code_mod)
+			return OK;
+	}
+	if (use_module(change->new_code_mod, m) != 1)
+		return MODULE_BUSY;
+	return OK;
+}
+
+static abort_t apply_relocs(struct ksplice_mod_change *change,
+			    const struct ksplice_reloc *relocs,
+			    const struct ksplice_reloc *relocs_end)
+{
+	const struct ksplice_reloc *r;
+	for (r = relocs; r < relocs_end; r++) {
+		abort_t ret = apply_reloc(change, r);
+		if (ret != OK)
+			return ret;
+	}
+	return OK;
+}
+
+static abort_t apply_reloc(struct ksplice_mod_change *change,
+			   const struct ksplice_reloc *r)
+{
+	switch (r->howto->type) {
+	case KSPLICE_HOWTO_RELOC:
+	case KSPLICE_HOWTO_RELOC_PATCH:
+		return apply_howto_reloc(change, r);
+	case KSPLICE_HOWTO_DATE:
+	case KSPLICE_HOWTO_TIME:
+		return apply_howto_date(change, r);
+	default:
+		ksdebug(change, "Unexpected howto type %d\n", r->howto->type);
+		return UNEXPECTED;
+	}
+}
+
+/*
+ * Applies a relocation.  Aborts if the symbol referenced in it has
+ * not been uniquely resolved.
+ */
+static abort_t apply_howto_reloc(struct ksplice_mod_change *change,
+				 const struct ksplice_reloc *r)
+{
+	abort_t ret;
+	int canary_ret;
+	unsigned long sym_addr;
+	LIST_HEAD(vals);
+
+	canary_ret = contains_canary(change, r->blank_addr, r->howto);
+	if (canary_ret < 0)
+		return UNEXPECTED;
+	if (canary_ret == 0) {
+		ksdebug(change, "reloc: skipped %lx to %s+%lx (altinstr)\n",
+			r->blank_addr, r->symbol->label, r->target_addend);
+		return OK;
+	}
+
+	ret = lookup_symbol(change, r->symbol, &vals);
+	if (ret != OK) {
+		release_vals(&vals);
+		return ret;
+	}
+	/*
+	 * Relocations for the oldaddr fields of patches must have
+	 * been resolved via run-pre matching.
+	 */
+	if (!singular(&vals) || (r->symbol->candidate_vals != NULL &&
+				 r->howto->type == KSPLICE_HOWTO_RELOC_PATCH)) {
+		release_vals(&vals);
+		ksdebug(change, "Failed to find %s for reloc\n",
+			r->symbol->label);
+		return FAILED_TO_FIND;
+	}
+	sym_addr = list_entry(vals.next, struct candidate_val, list)->val;
+	release_vals(&vals);
+
+	ret = write_reloc_value(change, r, r->blank_addr,
+				r->howto->pcrel ? sym_addr - r->blank_addr :
+				sym_addr);
+	if (ret != OK)
+		return ret;
+
+	ksdebug(change, "reloc: %lx to %s+%lx (S=%lx ", r->blank_addr,
+		r->symbol->label, r->target_addend, sym_addr);
+	switch (r->howto->size) {
+	case 1:
+		ksdebug(change, "aft=%02x)\n", *(uint8_t *)r->blank_addr);
+		break;
+	case 2:
+		ksdebug(change, "aft=%04x)\n", *(uint16_t *)r->blank_addr);
+		break;
+	case 4:
+		ksdebug(change, "aft=%08x)\n", *(uint32_t *)r->blank_addr);
+		break;
+#if BITS_PER_LONG >= 64
+	case 8:
+		ksdebug(change, "aft=%016llx)\n", *(uint64_t *)r->blank_addr);
+		break;
+#endif /* BITS_PER_LONG */
+	default:
+		ksdebug(change, "Aborted.  Invalid relocation size.\n");
+		return UNEXPECTED;
+	}
+
+	/*
+	 * Create labelvals so that we can verify our choices in the
+	 * second round of run-pre matching that considers data sections.
+	 */
+	ret = create_labelval(change, r->symbol, sym_addr, VAL);
+	if (ret != OK)
+		return ret;
+
+	return add_dependency_on_address(change, sym_addr);
+}
+
+/*
+ * Date relocations are created wherever __DATE__ or __TIME__ is used
+ * in the kernel; we resolve them by simply copying in the date/time
+ * obtained from run-pre matching the relevant compilation unit.
+ */
+static abort_t apply_howto_date(struct ksplice_mod_change *change,
+				const struct ksplice_reloc *r)
+{
+	if (r->symbol->candidate_vals != NULL) {
+		ksdebug(change, "Failed to find %s for date\n",
+			r->symbol->label);
+		return FAILED_TO_FIND;
+	}
+	memcpy((unsigned char *)r->blank_addr,
+	       (const unsigned char *)r->symbol->value, r->howto->size);
+	return OK;
+}
+
+/*
+ * Given a relocation and its run address, compute the address of the
+ * symbol the relocation referenced, and store it in *valp.
+ */
+static abort_t read_reloc_value(struct ksplice_mod_change *change,
+				const struct ksplice_reloc *r,
+				unsigned long addr, unsigned long *valp)
+{
+	unsigned char bytes[sizeof(long)];
+	unsigned long val;
+	const struct ksplice_reloc_howto *howto = r->howto;
+
+	if (howto->size <= 0 || howto->size > sizeof(long)) {
+		ksdebug(change, "Aborted.  Invalid relocation size.\n");
+		return UNEXPECTED;
+	}
+
+	if (probe_kernel_read(bytes, (void *)addr, howto->size) == -EFAULT)
+		return NO_MATCH;
+
+	switch (howto->size) {
+	case 1:
+		val = *(uint8_t *)bytes;
+		break;
+	case 2:
+		val = *(uint16_t *)bytes;
+		break;
+	case 4:
+		val = *(uint32_t *)bytes;
+		break;
+#if BITS_PER_LONG >= 64
+	case 8:
+		val = *(uint64_t *)bytes;
+		break;
+#endif /* BITS_PER_LONG */
+	default:
+		ksdebug(change, "Aborted.  Invalid relocation size.\n");
+		return UNEXPECTED;
+	}
+
+	val &= howto->dst_mask;
+	if (howto->signed_addend)
+		val |= -(val & (howto->dst_mask & ~(howto->dst_mask >> 1)));
+	val <<= howto->rightshift;
+	val -= r->insn_addend + r->target_addend;
+	*valp = val;
+	return OK;
+}
+
+/*
+ * Given a relocation, the address of its storage unit, and the
+ * address of the symbol the relocation references, write the
+ * relocation's final value into the storage unit.
+ */
+static abort_t write_reloc_value(struct ksplice_mod_change *change,
+				 const struct ksplice_reloc *r,
+				 unsigned long addr, unsigned long sym_addr)
+{
+	unsigned long val = sym_addr + r->target_addend + r->insn_addend;
+	const struct ksplice_reloc_howto *howto = r->howto;
+	val >>= howto->rightshift;
+	switch (howto->size) {
+	case 1:
+		*(uint8_t *)addr = (*(uint8_t *)addr & ~howto->dst_mask) |
+		    (val & howto->dst_mask);
+		break;
+	case 2:
+		*(uint16_t *)addr = (*(uint16_t *)addr & ~howto->dst_mask) |
+		    (val & howto->dst_mask);
+		break;
+	case 4:
+		*(uint32_t *)addr = (*(uint32_t *)addr & ~howto->dst_mask) |
+		    (val & howto->dst_mask);
+		break;
+#if BITS_PER_LONG >= 64
+	case 8:
+		*(uint64_t *)addr = (*(uint64_t *)addr & ~howto->dst_mask) |
+		    (val & howto->dst_mask);
+		break;
+#endif /* BITS_PER_LONG */
+	default:
+		ksdebug(change, "Aborted.  Invalid relocation size.\n");
+		return UNEXPECTED;
+	}
+
+	if (read_reloc_value(change, r, addr, &val) != OK || val != sym_addr) {
+		ksdebug(change, "Aborted.  Relocation overflow.\n");
+		return UNEXPECTED;
+	}
+
+	return OK;
+}
+
+static abort_t create_module_list_entry(struct ksplice_mod_change *change,
+					bool to_be_applied)
+{
+	struct ksplice_module_list_entry *entry =
+	    kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (entry == NULL)
+		return OUT_OF_MEMORY;
+	entry->new_code_mod_name =
+	    kstrdup(change->new_code_mod->name, GFP_KERNEL);
+	if (entry->new_code_mod_name == NULL) {
+		kfree(entry);
+		return OUT_OF_MEMORY;
+	}
+	entry->target_mod_name = kstrdup(change->target_name, GFP_KERNEL);
+	if (entry->target_mod_name == NULL) {
+		kfree(entry->new_code_mod_name);
+		kfree(entry);
+		return OUT_OF_MEMORY;
+	}
+	/* The update's kid is guaranteed to outlast the module_list_entry */
+	entry->kid = change->update->kid;
+	entry->applied = to_be_applied;
+	list_add(&entry->update_list, &change->update->ksplice_module_list);
+	return OK;
+}
+
+static void cleanup_module_list_entries(struct update *update)
+{
+	struct ksplice_module_list_entry *entry;
+	list_for_each_entry(entry, &update->ksplice_module_list, update_list) {
+		kfree(entry->target_mod_name);
+		kfree(entry->new_code_mod_name);
+	}
+	clear_list(&update->ksplice_module_list,
+		   struct ksplice_module_list_entry, update_list);
+}
+
+/* Replacement address used for functions deleted by the patch */
+static void __attribute__((noreturn)) ksplice_deleted(void)
+{
+	printk(KERN_CRIT "Called a kernel function deleted by Ksplice!\n");
+	BUG();
+}
+
+/* Floodfill to run-pre match the sections within a change. */
+static abort_t match_change_sections(struct ksplice_mod_change *change,
+				   bool consider_data_sections)
+{
+	struct ksplice_section *sect;
+	abort_t ret;
+	int remaining = 0;
+	bool progress;
+
+	for (sect = change->old_code.sections;
+	     sect < change->old_code.sections_end; sect++) {
+		if ((sect->flags & KSPLICE_SECTION_DATA) == 0 &&
+		    (sect->flags & KSPLICE_SECTION_STRING) == 0 &&
+		    (sect->flags & KSPLICE_SECTION_MATCHED) == 0)
+			remaining++;
+	}
+
+	while (remaining > 0) {
+		progress = false;
+		for (sect = change->old_code.sections;
+		     sect < change->old_code.sections_end; sect++) {
+			if ((sect->flags & KSPLICE_SECTION_MATCHED) != 0)
+				continue;
+			if ((!consider_data_sections &&
+			     (sect->flags & KSPLICE_SECTION_DATA) != 0) ||
+			    (sect->flags & KSPLICE_SECTION_STRING) != 0)
+				continue;
+			ret = find_section(change, sect);
+			if (ret == OK) {
+				sect->flags |= KSPLICE_SECTION_MATCHED;
+				if ((sect->flags & KSPLICE_SECTION_DATA) == 0)
+					remaining--;
+				progress = true;
+			} else if (ret != NO_MATCH) {
+				return ret;
+			}
+		}
+
+		if (progress)
+			continue;
+
+		for (sect = change->old_code.sections;
+		     sect < change->old_code.sections_end; sect++) {
+			if ((sect->flags & KSPLICE_SECTION_MATCHED) != 0 ||
+			    (sect->flags & KSPLICE_SECTION_STRING) != 0)
+				continue;
+			ksdebug(change, "run-pre: could not match %s "
+				"section %s\n",
+				(sect->flags & KSPLICE_SECTION_DATA) != 0 ?
+				"data" :
+				(sect->flags & KSPLICE_SECTION_RODATA) != 0 ?
+				"rodata" : "text", sect->symbol->label);
+		}
+		ksdebug(change, "Aborted.  run-pre: could not match some "
+			"sections.\n");
+		return NO_MATCH;
+	}
+	return OK;
+}
+
+/*
+ * Search for the section in the running kernel.  Returns OK if and
+ * only if it finds precisely one address in the kernel matching the
+ * section.
+ */
+static abort_t find_section(struct ksplice_mod_change *change,
+			    struct ksplice_section *sect)
+{
+	int i;
+	abort_t ret;
+	unsigned long run_addr;
+	LIST_HEAD(vals);
+	struct candidate_val *v, *n;
+
+	ret = lookup_symbol(change, sect->symbol, &vals);
+	if (ret != OK) {
+		release_vals(&vals);
+		return ret;
+	}
+
+	ksdebug(change, "run-pre: starting sect search for %s\n",
+		sect->symbol->label);
+
+	list_for_each_entry_safe(v, n, &vals, list) {
+		run_addr = v->val;
+
+		yield();
+		ret = try_addr(change, sect, run_addr, NULL, RUN_PRE_INITIAL);
+		if (ret == NO_MATCH) {
+			list_del(&v->list);
+			kfree(v);
+		} else if (ret != OK) {
+			release_vals(&vals);
+			return ret;
+		}
+	}
+
+	if (singular(&vals)) {
+		LIST_HEAD(safety_records);
+		run_addr = list_entry(vals.next, struct candidate_val,
+				      list)->val;
+		ret = try_addr(change, sect, run_addr, &safety_records,
+			       RUN_PRE_FINAL);
+		release_vals(&vals);
+		if (ret != OK) {
+			clear_list(&safety_records, struct safety_record, list);
+			ksdebug(change, "run-pre: Final run failed for sect "
+				"%s:\n", sect->symbol->label);
+		} else {
+			list_splice(&safety_records, &change->safety_records);
+		}
+		return ret;
+	} else if (!list_empty(&vals)) {
+		struct candidate_val *val;
+		ksdebug(change, "run-pre: multiple candidates for sect %s:\n",
+			sect->symbol->label);
+		i = 0;
+		list_for_each_entry(val, &vals, list) {
+			i++;
+			ksdebug(change, "%lx\n", val->val);
+			if (i > 5) {
+				ksdebug(change, "...\n");
+				break;
+			}
+		}
+		release_vals(&vals);
+		return NO_MATCH;
+	}
+	release_vals(&vals);
+	return NO_MATCH;
+}
+
+/*
+ * try_addr is the the interface to run-pre matching.  Its primary
+ * purpose is to manage debugging information for run-pre matching;
+ * all the hard work is in run_pre_cmp.
+ */
+static abort_t try_addr(struct ksplice_mod_change *change,
+			struct ksplice_section *sect,
+			unsigned long run_addr,
+			struct list_head *safety_records,
+			enum run_pre_mode mode)
+{
+	abort_t ret;
+	const struct module *run_module = __module_address(run_addr);
+
+	if (run_module == change->new_code_mod) {
+		ksdebug(change, "run-pre: unexpected address %lx in new_code "
+			"module %s for sect %s\n", run_addr, run_module->name,
+			sect->symbol->label);
+		return UNEXPECTED;
+	}
+	if (!patches_module(run_module, change->target)) {
+		ksdebug(change, "run-pre: ignoring address %lx in other module "
+			"%s for sect %s\n", run_addr, run_module == NULL ?
+			"vmlinux" : run_module->name, sect->symbol->label);
+		return NO_MATCH;
+	}
+
+	ret = create_labelval(change, sect->symbol, run_addr, TEMP);
+	if (ret != OK)
+		return ret;
+
+	ret = run_pre_cmp(change, sect, run_addr, safety_records, mode);
+	if (ret == NO_MATCH && mode != RUN_PRE_FINAL) {
+		set_temp_labelvals(change, NOVAL);
+		ksdebug(change, "run-pre: %s sect %s does not match (r_a=%lx "
+			"p_a=%lx s=%lx)\n",
+			(sect->flags & KSPLICE_SECTION_RODATA) != 0 ? "rodata" :
+			(sect->flags & KSPLICE_SECTION_DATA) != 0 ? "data" :
+			"text", sect->symbol->label, run_addr, sect->address,
+			sect->size);
+		ksdebug(change, "run-pre: ");
+		if (change->update->debug >= 1) {
+			ret = run_pre_cmp(change, sect, run_addr,
+					  safety_records, RUN_PRE_DEBUG);
+			set_temp_labelvals(change, NOVAL);
+		}
+		ksdebug(change, "\n");
+		return ret;
+	} else if (ret != OK) {
+		set_temp_labelvals(change, NOVAL);
+		return ret;
+	}
+
+	if (mode != RUN_PRE_FINAL) {
+		set_temp_labelvals(change, NOVAL);
+		ksdebug(change, "run-pre: candidate for sect %s=%lx\n",
+			sect->symbol->label, run_addr);
+		return OK;
+	}
+
+	set_temp_labelvals(change, VAL);
+	ksdebug(change, "run-pre: found sect %s=%lx\n", sect->symbol->label,
+		run_addr);
+	return OK;
+}
+
+/*
+ * run_pre_cmp is the primary run-pre matching function; it determines
+ * whether the given ksplice_section matches the code or data in the
+ * running kernel starting at run_addr.
+ *
+ * If run_pre_mode is RUN_PRE_FINAL, a safety record for the matched
+ * section is created.
+ *
+ * The run_pre_mode is also used to determine what debugging
+ * information to display.
+ */
+static abort_t run_pre_cmp(struct ksplice_mod_change *change,
+			   const struct ksplice_section *sect,
+			   unsigned long run_addr,
+			   struct list_head *safety_records,
+			   enum run_pre_mode mode)
+{
+	int matched = 0;
+	abort_t ret;
+	const struct ksplice_reloc *r, *finger;
+	const unsigned char *pre, *run, *pre_start, *run_start;
+	unsigned char runval;
+
+	pre_start = (const unsigned char *)sect->address;
+	run_start = (const unsigned char *)run_addr;
+
+	finger = init_reloc_search(change, sect);
+
+	pre = pre_start;
+	run = run_start;
+	while (pre < pre_start + sect->size) {
+		unsigned long offset = pre - pre_start;
+		ret = lookup_reloc(change, &finger, (unsigned long)pre, &r);
+		if (ret == OK) {
+			ret = handle_reloc(change, sect, r, (unsigned long)run,
+					   mode);
+			if (ret != OK) {
+				if (mode == RUN_PRE_INITIAL)
+					ksdebug(change, "reloc in sect does "
+						"not match after %lx/%lx "
+						"bytes\n", offset, sect->size);
+				return ret;
+			}
+			if (mode == RUN_PRE_DEBUG)
+				print_bytes(change, run, r->howto->size, pre,
+					    r->howto->size);
+			pre += r->howto->size;
+			run += r->howto->size;
+			finger++;
+			continue;
+		} else if (ret != NO_MATCH) {
+			return ret;
+		}
+
+		if ((sect->flags & KSPLICE_SECTION_TEXT) != 0) {
+			ret = handle_paravirt(change, (unsigned long)pre,
+					      (unsigned long)run, &matched);
+			if (ret != OK)
+				return ret;
+			if (matched != 0) {
+				if (mode == RUN_PRE_DEBUG)
+					print_bytes(change, run, matched, pre,
+						    matched);
+				pre += matched;
+				run += matched;
+				continue;
+			}
+		}
+
+		if (probe_kernel_read(&runval, (void *)run, 1) == -EFAULT) {
+			if (mode == RUN_PRE_INITIAL)
+				ksdebug(change, "sect unmapped after %lx/%lx "
+					"bytes\n", offset, sect->size);
+			return NO_MATCH;
+		}
+
+		if (runval != *pre &&
+		    (sect->flags & KSPLICE_SECTION_DATA) == 0) {
+			if (mode == RUN_PRE_INITIAL)
+				ksdebug(change, "sect does not match after "
+					"%lx/%lx bytes\n", offset, sect->size);
+			if (mode == RUN_PRE_DEBUG) {
+				print_bytes(change, run, 1, pre, 1);
+				ksdebug(change, "[p_o=%lx] ! ", offset);
+				print_bytes(change, run + 1, 2, pre + 1, 2);
+			}
+			return NO_MATCH;
+		}
+		if (mode == RUN_PRE_DEBUG)
+			print_bytes(change, run, 1, pre, 1);
+		pre++;
+		run++;
+	}
+	return create_safety_record(change, sect, safety_records, run_addr,
+				    run - run_start);
+}
+
+static void print_bytes(struct ksplice_mod_change *change,
+			const unsigned char *run, int runc,
+			const unsigned char *pre, int prec)
+{
+	int o;
+	int matched = min(runc, prec);
+	for (o = 0; o < matched; o++) {
+		if (run[o] == pre[o])
+			ksdebug(change, "%02x ", run[o]);
+		else
+			ksdebug(change, "%02x/%02x ", run[o], pre[o]);
+	}
+	for (o = matched; o < runc; o++)
+		ksdebug(change, "%02x/ ", run[o]);
+	for (o = matched; o < prec; o++)
+		ksdebug(change, "/%02x ", pre[o]);
+}
+
+struct range {
+	unsigned long address;
+	unsigned long size;
+};
+
+static int reloc_bsearch_compare(const void *key, const void *elt)
+{
+	const struct range *range = key;
+	const struct ksplice_reloc *r = elt;
+	if (range->address + range->size <= r->blank_addr)
+		return -1;
+	if (range->address > r->blank_addr)
+		return 1;
+	return 0;
+}
+
+static const struct ksplice_reloc *find_reloc(const struct ksplice_reloc *start,
+					      const struct ksplice_reloc *end,
+					      unsigned long address,
+					      unsigned long size)
+{
+	const struct ksplice_reloc *r;
+	struct range range = { address, size };
+	r = bsearch((void *)&range, start, end - start, sizeof(*r),
+		    reloc_bsearch_compare);
+	if (r == NULL)
+		return NULL;
+	while (r > start && (r - 1)->blank_addr >= address)
+		r--;
+	return r;
+}
+
+static const struct ksplice_reloc *
+init_reloc_search(struct ksplice_mod_change *change,
+		  const struct ksplice_section *sect)
+{
+	const struct ksplice_reloc *r;
+	r = find_reloc(change->old_code.relocs, change->old_code.relocs_end,
+		       sect->address, sect->size);
+	if (r == NULL)
+		return change->old_code.relocs_end;
+	return r;
+}
+
+/*
+ * lookup_reloc implements an amortized O(1) lookup for the next
+ * old_code relocation.  It must be called with a strictly increasing
+ * sequence of addresses.
+ *
+ * The fingerp is private data for lookup_reloc, and needs to have
+ * been initialized as a pointer to the result of find_reloc (or
+ * init_reloc_search).
+ */
+static abort_t lookup_reloc(struct ksplice_mod_change *change,
+			    const struct ksplice_reloc **fingerp,
+			    unsigned long addr,
+			    const struct ksplice_reloc **relocp)
+{
+	const struct ksplice_reloc *r = *fingerp;
+	int canary_ret;
+
+	while (r < change->old_code.relocs_end &&
+	       addr >= r->blank_addr + r->howto->size &&
+	       !(addr == r->blank_addr && r->howto->size == 0))
+		r++;
+	*fingerp = r;
+	if (r == change->old_code.relocs_end)
+		return NO_MATCH;
+	if (addr < r->blank_addr)
+		return NO_MATCH;
+	*relocp = r;
+	if (r->howto->type != KSPLICE_HOWTO_RELOC)
+		return OK;
+
+	canary_ret = contains_canary(change, r->blank_addr, r->howto);
+	if (canary_ret < 0)
+		return UNEXPECTED;
+	if (canary_ret == 0) {
+		ksdebug(change, "run-pre: reloc skipped at p_a=%lx to %s+%lx "
+			"(altinstr)\n", r->blank_addr, r->symbol->label,
+			r->target_addend);
+		return NO_MATCH;
+	}
+	if (addr != r->blank_addr) {
+		ksdebug(change, "Invalid nonzero relocation offset\n");
+		return UNEXPECTED;
+	}
+	return OK;
+}
+
+static abort_t handle_reloc(struct ksplice_mod_change *change,
+			    const struct ksplice_section *sect,
+			    const struct ksplice_reloc *r,
+			    unsigned long run_addr, enum run_pre_mode mode)
+{
+	switch (r->howto->type) {
+	case KSPLICE_HOWTO_RELOC:
+		return handle_howto_reloc(change, sect, r, run_addr, mode);
+	case KSPLICE_HOWTO_DATE:
+	case KSPLICE_HOWTO_TIME:
+		return handle_howto_date(change, sect, r, run_addr, mode);
+#ifdef CONFIG_BUG
+	case KSPLICE_HOWTO_BUG:
+		return handle_bug(change, r, run_addr);
+#endif /* CONFIG_BUG */
+	case KSPLICE_HOWTO_EXTABLE:
+		return handle_extable(change, r, run_addr);
+	default:
+		ksdebug(change, "Unexpected howto type %d\n", r->howto->type);
+		return UNEXPECTED;
+	}
+}
+
+/*
+ * For date/time relocations, we check that the sequence of bytes
+ * matches the format of a date or time.
+ */
+static abort_t handle_howto_date(struct ksplice_mod_change *change,
+				 const struct ksplice_section *sect,
+				 const struct ksplice_reloc *r,
+				 unsigned long run_addr, enum run_pre_mode mode)
+{
+	abort_t ret;
+	char *buf = kmalloc(r->howto->size, GFP_KERNEL);
+
+	if (buf == NULL)
+		return OUT_OF_MEMORY;
+	if (probe_kernel_read(buf, (void *)run_addr, r->howto->size) == -EFAULT) {
+		ret = NO_MATCH;
+		goto out;
+	}
+
+	switch (r->howto->type) {
+	case KSPLICE_HOWTO_TIME:
+		if (isdigit(buf[0]) && isdigit(buf[1]) && buf[2] == ':' &&
+		    isdigit(buf[3]) && isdigit(buf[4]) && buf[5] == ':' &&
+		    isdigit(buf[6]) && isdigit(buf[7]))
+			ret = OK;
+		else
+			ret = NO_MATCH;
+		break;
+	case KSPLICE_HOWTO_DATE:
+		if (isalpha(buf[0]) && isalpha(buf[1]) && isalpha(buf[2]) &&
+		    buf[3] == ' ' && (buf[4] == ' ' || isdigit(buf[4])) &&
+		    isdigit(buf[5]) && buf[6] == ' ' && isdigit(buf[7]) &&
+		    isdigit(buf[8]) && isdigit(buf[9]) && isdigit(buf[10]))
+			ret = OK;
+		else
+			ret = NO_MATCH;
+		break;
+	default:
+		ret = UNEXPECTED;
+	}
+	if (ret == NO_MATCH && mode == RUN_PRE_INITIAL)
+		ksdebug(change, "%s string: \"%.*s\" does not match format\n",
+			r->howto->type == KSPLICE_HOWTO_DATE ? "date" : "time",
+			r->howto->size, buf);
+
+	if (ret != OK)
+		goto out;
+	ret = create_labelval(change, r->symbol, run_addr, TEMP);
+out:
+	kfree(buf);
+	return ret;
+}
+
+/*
+ * Extract the value of a symbol used in a relocation in the pre code
+ * during run-pre matching, giving an error if it conflicts with a
+ * previously found value of that symbol
+ */
+static abort_t handle_howto_reloc(struct ksplice_mod_change *change,
+				  const struct ksplice_section *sect,
+				  const struct ksplice_reloc *r,
+				  unsigned long run_addr,
+				  enum run_pre_mode mode)
+{
+	struct ksplice_section *sym_sect = symbol_section(change, r->symbol);
+	unsigned long offset = r->target_addend;
+	unsigned long val;
+	abort_t ret;
+
+	ret = read_reloc_value(change, r, run_addr, &val);
+	if (ret != OK)
+		return ret;
+	if (r->howto->pcrel)
+		val += run_addr;
+
+	if (mode == RUN_PRE_INITIAL)
+		ksdebug(change, "run-pre: reloc at r_a=%lx p_a=%lx to %s+%lx: "
+			"found %s = %lx\n", run_addr, r->blank_addr,
+			r->symbol->label, offset, r->symbol->label, val);
+
+	if (contains_canary(change, run_addr, r->howto) != 0) {
+		ksdebug(change, "Aborted.  Unexpected canary in run code at %lx"
+			"\n", run_addr);
+		return UNEXPECTED;
+	}
+
+	if ((sect->flags & KSPLICE_SECTION_DATA) != 0 &&
+	    sect->symbol == r->symbol)
+		return OK;
+	ret = create_labelval(change, r->symbol, val, TEMP);
+	if (ret == NO_MATCH && mode == RUN_PRE_INITIAL)
+		ksdebug(change, "run-pre: reloc at r_a=%lx p_a=%lx: labelval "
+			"%s = %lx does not match expected %lx\n", run_addr,
+			r->blank_addr, r->symbol->label, r->symbol->value, val);
+
+	if (ret != OK)
+		return ret;
+	if (sym_sect != NULL && (sym_sect->flags & KSPLICE_SECTION_MATCHED) == 0
+	    && (sym_sect->flags & KSPLICE_SECTION_STRING) != 0) {
+		if (mode == RUN_PRE_INITIAL)
+			ksdebug(change, "Recursively comparing string section "
+				"%s\n", sym_sect->symbol->label);
+		else if (mode == RUN_PRE_DEBUG)
+			ksdebug(change, "[str start] ");
+		ret = run_pre_cmp(change, sym_sect, val, NULL, mode);
+		if (mode == RUN_PRE_DEBUG)
+			ksdebug(change, "[str end] ");
+		if (ret == OK && mode == RUN_PRE_INITIAL)
+			ksdebug(change, "Successfully matched string section %s"
+				"\n", sym_sect->symbol->label);
+		else if (mode == RUN_PRE_INITIAL)
+			ksdebug(change, "Failed to match string section %s\n",
+				sym_sect->symbol->label);
+	}
+	return ret;
+}
+
+#ifdef CONFIG_GENERIC_BUG
+static abort_t handle_bug(struct ksplice_mod_change *change,
+			  const struct ksplice_reloc *r, unsigned long run_addr)
+{
+	const struct bug_entry *run_bug = find_bug(run_addr);
+	struct ksplice_section *bug_sect = symbol_section(change, r->symbol);
+	if (run_bug == NULL)
+		return NO_MATCH;
+	if (bug_sect == NULL)
+		return UNEXPECTED;
+	return create_labelval(change, bug_sect->symbol, (unsigned long)run_bug,
+			       TEMP);
+}
+#endif /* CONFIG_GENERIC_BUG */
+
+static abort_t handle_extable(struct ksplice_mod_change *change,
+			      const struct ksplice_reloc *r,
+			      unsigned long run_addr)
+{
+	const struct exception_table_entry *run_ent =
+	    search_exception_tables(run_addr);
+	struct ksplice_section *ex_sect = symbol_section(change, r->symbol);
+	if (run_ent == NULL)
+		return NO_MATCH;
+	if (ex_sect == NULL)
+		return UNEXPECTED;
+	return create_labelval(change, ex_sect->symbol, (unsigned long)run_ent,
+			       TEMP);
+}
+
+static int symbol_section_bsearch_compare(const void *a, const void *b)
+{
+	const struct ksplice_symbol *sym = a;
+	const struct ksplice_section *sect = b;
+	return strcmp(sym->label, sect->symbol->label);
+}
+
+static int compare_section_labels(const void *va, const void *vb)
+{
+	const struct ksplice_section *a = va, *b = vb;
+	return strcmp(a->symbol->label, b->symbol->label);
+}
+
+static struct ksplice_section *symbol_section(struct ksplice_mod_change *change,
+					      const struct ksplice_symbol *sym)
+{
+	return bsearch(sym, change->old_code.sections,
+		       change->old_code.sections_end -
+		       change->old_code.sections,
+		       sizeof(struct ksplice_section),
+		       symbol_section_bsearch_compare);
+}
+
+/* Find the relocation for the oldaddr of a ksplice_patch */
+static const struct ksplice_reloc *
+patch_reloc(struct ksplice_mod_change *change,
+	    const struct ksplice_patch *p)
+{
+	unsigned long addr = (unsigned long)&p->oldaddr;
+	const struct ksplice_reloc *r =
+	    find_reloc(change->new_code.relocs, change->new_code.relocs_end,
+		       addr, sizeof(addr));
+	if (r == NULL || r->blank_addr < addr ||
+	    r->blank_addr >= addr + sizeof(addr))
+		return NULL;
+	return r;
+}
+
+/*
+ * Populates vals with the possible values for ksym from the various
+ * sources Ksplice uses to resolve symbols
+ */
+static abort_t lookup_symbol(struct ksplice_mod_change *change,
+			     const struct ksplice_symbol *ksym,
+			     struct list_head *vals)
+{
+	abort_t ret;
+
+	if (ksym->candidate_vals == NULL) {
+		release_vals(vals);
+		ksdebug(change, "using detected sym %s=%lx\n", ksym->label,
+			ksym->value);
+		return add_candidate_val(change, vals, ksym->value);
+	}
+
+	if (strcmp(ksym->label, "cleanup_module") == 0 && change->target != NULL
+	    && change->target->exit != NULL) {
+		ret = add_candidate_val(change, vals,
+					(unsigned long)change->target->exit);
+		if (ret != OK)
+			return ret;
+	}
+
+	if (ksym->name != NULL) {
+		struct candidate_val *val;
+		list_for_each_entry(val, ksym->candidate_vals, list) {
+			ret = add_candidate_val(change, vals, val->val);
+			if (ret != OK)
+				return ret;
+		}
+
+		ret = new_export_lookup(change, ksym->name, vals);
+		if (ret != OK)
+			return ret;
+	}
+
+	return OK;
+}
+
+/*
+ * An update could one module to export a symbol and at the same time
+ * change another module to use that symbol.  This violates the normal
+ * situation where the changes can be handled independently.
+ *
+ * new_export_lookup obtains symbol values from the changes to the
+ * exported symbol table made by other changes.
+ */
+static abort_t new_export_lookup(struct ksplice_mod_change *ichange,
+				 const char *name, struct list_head *vals)
+{
+	struct ksplice_mod_change *change;
+	struct ksplice_patch *p;
+	list_for_each_entry(change, &ichange->update->changes, list) {
+		for (p = change->patches; p < change->patches_end; p++) {
+			const struct kernel_symbol *sym;
+			const struct ksplice_reloc *r;
+			if (p->type != KSPLICE_PATCH_EXPORT ||
+			    strcmp(name, *(const char **)p->contents) != 0)
+				continue;
+
+			/* Check that the p->oldaddr reloc has been resolved. */
+			r = patch_reloc(change, p);
+			if (r == NULL ||
+			    contains_canary(change, r->blank_addr,
+					    r->howto) != 0)
+				continue;
+			sym = (const struct kernel_symbol *)r->symbol->value;
+
+			/*
+			 * Check that the sym->value reloc has been resolved,
+			 * if there is a Ksplice relocation there.
+			 */
+			r = find_reloc(change->new_code.relocs,
+				       change->new_code.relocs_end,
+				       (unsigned long)&sym->value,
+				       sizeof(&sym->value));
+			if (r != NULL &&
+			    r->blank_addr == (unsigned long)&sym->value &&
+			    contains_canary(change, r->blank_addr,
+					    r->howto) != 0)
+				continue;
+			return add_candidate_val(ichange, vals, sym->value);
+		}
+	}
+	return OK;
+}
+
+/*
+ * When patch_action is called, the update should be fully prepared.
+ * patch_action will try to actually insert or remove trampolines for
+ * the update.
+ */
+static abort_t patch_action(struct update *update, enum ksplice_action action)
+{
+	static int (*const __patch_actions[KS_ACTIONS])(void *) = {
+		[KS_APPLY] = __apply_patches,
+		[KS_REVERSE] = __reverse_patches,
+	};
+	int i;
+	abort_t ret;
+	struct ksplice_mod_change *change;
+
+	ret = map_trampoline_pages(update);
+	if (ret != OK)
+		return ret;
+
+	list_for_each_entry(change, &update->changes, list) {
+		const typeof(int (*)(void)) *f;
+		for (f = change->hooks[action].pre;
+		     f < change->hooks[action].pre_end; f++) {
+			if ((*f)() != 0) {
+				ret = CALL_FAILED;
+				goto out;
+			}
+		}
+	}
+
+	for (i = 0; i < 5; i++) {
+		cleanup_conflicts(update);
+		ret = (__force abort_t)stop_machine(__patch_actions[action],
+						    update, NULL);
+		if (ret != CODE_BUSY)
+			break;
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(msecs_to_jiffies(1000));
+	}
+out:
+	unmap_trampoline_pages(update);
+
+	if (ret == CODE_BUSY) {
+		print_conflicts(update);
+		_ksdebug(update, "Aborted %s.  stack check: to-be-%s "
+			 "code is busy.\n", update->kid,
+			 action == KS_APPLY ? "replaced" : "reversed");
+	} else if (ret == ALREADY_REVERSED) {
+		_ksdebug(update, "Aborted %s.  Ksplice update %s is already "
+			 "reversed.\n", update->kid, update->kid);
+	} else if (ret == MODULE_BUSY) {
+		_ksdebug(update, "Update %s is in use by another module\n",
+			 update->kid);
+	}
+
+	if (ret != OK) {
+		list_for_each_entry(change, &update->changes, list) {
+			const typeof(void (*)(void)) *f;
+			for (f = change->hooks[action].fail;
+			     f < change->hooks[action].fail_end; f++)
+				(*f)();
+		}
+
+		return ret;
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		const typeof(void (*)(void)) *f;
+		for (f = change->hooks[action].post;
+		     f < change->hooks[action].post_end; f++)
+			(*f)();
+	}
+
+	_ksdebug(update, "Atomic patch %s for %s complete\n",
+		 action == KS_APPLY ? "insertion" : "removal", update->kid);
+	return OK;
+}
+
+/* Atomically insert the update; run from within stop_machine */
+static int __apply_patches(void *updateptr)
+{
+	struct update *update = updateptr;
+	struct ksplice_mod_change *change;
+	struct ksplice_module_list_entry *entry;
+	struct ksplice_patch *p;
+	abort_t ret;
+
+	if (update->stage == STAGE_APPLIED)
+		return (__force int)OK;
+
+	if (update->stage != STAGE_PREPARING)
+		return (__force int)UNEXPECTED;
+
+	ret = check_each_task(update);
+	if (ret != OK)
+		return (__force int)ret;
+
+	list_for_each_entry(change, &update->changes, list) {
+		if (try_module_get(change->new_code_mod) != 1) {
+			struct ksplice_mod_change *change1;
+			list_for_each_entry(change1, &update->changes, list) {
+				if (change1 == change)
+					break;
+				module_put(change1->new_code_mod);
+			}
+			module_put(THIS_MODULE);
+			return (__force int)UNEXPECTED;
+		}
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		const typeof(int (*)(void)) *f;
+		for (f = change->hooks[KS_APPLY].check;
+		     f < change->hooks[KS_APPLY].check_end; f++) {
+			if ((*f)() != 0)
+				return (__force int)CALL_FAILED;
+		}
+	}
+
+	/* Commit point: the update application will succeed. */
+
+	update->stage = STAGE_APPLIED;
+	add_taint(TAINT_KSPLICE);
+
+	list_for_each_entry(entry, &update->ksplice_module_list, update_list)
+		list_add(&entry->list, &ksplice_modules);
+
+	list_for_each_entry(change, &update->changes, list) {
+		for (p = change->patches; p < change->patches_end; p++)
+			insert_trampoline(p);
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		const typeof(void (*)(void)) *f;
+		for (f = change->hooks[KS_APPLY].intra;
+		     f < change->hooks[KS_APPLY].intra_end; f++)
+			(*f)();
+	}
+
+	return (__force int)OK;
+}
+
+/* Atomically remove the update; run from within stop_machine */
+static int __reverse_patches(void *updateptr)
+{
+	struct update *update = updateptr;
+	struct ksplice_mod_change *change;
+	struct ksplice_module_list_entry *entry;
+	const struct ksplice_patch *p;
+	abort_t ret;
+
+	if (update->stage != STAGE_APPLIED)
+		return (__force int)OK;
+
+	list_for_each_entry(change, &update->changes, list) {
+		if (module_refcount(change->new_code_mod) != 1)
+			return (__force int)MODULE_BUSY;
+	}
+
+	list_for_each_entry(entry, &update->ksplice_module_list, update_list) {
+		if (!entry->applied &&
+		    find_module(entry->target_mod_name) != NULL)
+			return COLD_UPDATE_LOADED;
+	}
+
+	ret = check_each_task(update);
+	if (ret != OK)
+		return (__force int)ret;
+
+	list_for_each_entry(change, &update->changes, list) {
+		for (p = change->patches; p < change->patches_end; p++) {
+			ret = verify_trampoline(change, p);
+			if (ret != OK)
+				return (__force int)ret;
+		}
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		const typeof(int (*)(void)) *f;
+		for (f = change->hooks[KS_REVERSE].check;
+		     f < change->hooks[KS_REVERSE].check_end; f++) {
+			if ((*f)() != 0)
+				return (__force int)CALL_FAILED;
+		}
+	}
+
+	/* Commit point: the update reversal will succeed. */
+
+	update->stage = STAGE_REVERSED;
+
+	list_for_each_entry(change, &update->changes, list)
+		module_put(change->new_code_mod);
+
+	list_for_each_entry(entry, &update->ksplice_module_list, update_list)
+		list_del(&entry->list);
+
+	list_for_each_entry(change, &update->changes, list) {
+		const typeof(void (*)(void)) *f;
+		for (f = change->hooks[KS_REVERSE].intra;
+		     f < change->hooks[KS_REVERSE].intra_end; f++)
+			(*f)();
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		for (p = change->patches; p < change->patches_end; p++)
+			remove_trampoline(p);
+	}
+
+	return (__force int)OK;
+}
+
+/*
+ * Check whether any thread's instruction pointer or any address of
+ * its stack is contained in one of the safety_records associated with
+ * the update.
+ *
+ * check_each_task must be called from inside stop_machine, because it
+ * does not take tasklist_lock (which cannot be held by anyone else
+ * during stop_machine).
+ */
+static abort_t check_each_task(struct update *update)
+{
+	const struct task_struct *g, *p;
+	abort_t status = OK, ret;
+	do_each_thread(g, p) {
+		/* do_each_thread is a double loop! */
+		ret = check_task(update, p, false);
+		if (ret != OK) {
+			check_task(update, p, true);
+			status = ret;
+		}
+		if (ret != OK && ret != CODE_BUSY)
+			return ret;
+	} while_each_thread(g, p);
+	return status;
+}
+
+static abort_t check_task(struct update *update,
+			  const struct task_struct *t, bool rerun)
+{
+	abort_t status, ret;
+	struct conflict *conf = NULL;
+
+	if (rerun) {
+		conf = kmalloc(sizeof(*conf), GFP_ATOMIC);
+		if (conf == NULL)
+			return OUT_OF_MEMORY;
+		conf->process_name = kstrdup(t->comm, GFP_ATOMIC);
+		if (conf->process_name == NULL) {
+			kfree(conf);
+			return OUT_OF_MEMORY;
+		}
+		conf->pid = t->pid;
+		INIT_LIST_HEAD(&conf->stack);
+		list_add(&conf->list, &update->conflicts);
+	}
+
+	status = check_address(update, conf, KSPLICE_IP(t));
+	if (t == current) {
+		ret = check_stack(update, conf, task_thread_info(t),
+				  (unsigned long *)__builtin_frame_address(0));
+		if (status == OK)
+			status = ret;
+	} else if (!task_curr(t)) {
+		ret = check_stack(update, conf, task_thread_info(t),
+				  (unsigned long *)KSPLICE_SP(t));
+		if (status == OK)
+			status = ret;
+	} else if (!is_stop_machine(t)) {
+		status = UNEXPECTED_RUNNING_TASK;
+	}
+	return status;
+}
+
+static abort_t check_stack(struct update *update, struct conflict *conf,
+			   const struct thread_info *tinfo,
+			   const unsigned long *stack)
+{
+	abort_t status = OK, ret;
+	unsigned long addr;
+
+	while (valid_stack_ptr(tinfo, stack)) {
+		addr = *stack++;
+		ret = check_address(update, conf, addr);
+		if (ret != OK)
+			status = ret;
+	}
+	return status;
+}
+
+static abort_t check_address(struct update *update,
+			     struct conflict *conf, unsigned long addr)
+{
+	abort_t status = OK, ret;
+	const struct safety_record *rec;
+	struct ksplice_mod_change *change;
+	struct conflict_addr *ca = NULL;
+
+	if (conf != NULL) {
+		ca = kmalloc(sizeof(*ca), GFP_ATOMIC);
+		if (ca == NULL)
+			return OUT_OF_MEMORY;
+		ca->addr = addr;
+		ca->has_conflict = false;
+		ca->label = NULL;
+		list_add(&ca->list, &conf->stack);
+	}
+
+	list_for_each_entry(change, &update->changes, list) {
+		unsigned long tramp_addr = follow_trampolines(change, addr);
+		list_for_each_entry(rec, &change->safety_records, list) {
+			ret = check_record(ca, rec, tramp_addr);
+			if (ret != OK)
+				status = ret;
+		}
+	}
+	return status;
+}
+
+static abort_t check_record(struct conflict_addr *ca,
+			    const struct safety_record *rec, unsigned long addr)
+{
+	if (addr >= rec->addr && addr < rec->addr + rec->size) {
+		if (ca != NULL) {
+			ca->label = rec->label;
+			ca->has_conflict = true;
+		}
+		return CODE_BUSY;
+	}
+	return OK;
+}
+
+/* Is the task one of the stop_machine tasks? */
+static bool is_stop_machine(const struct task_struct *t)
+{
+	const char *kstop_prefix = "kstop/";
+	const char *num;
+	if (!strstarts(t->comm, kstop_prefix))
+		return false;
+	num = t->comm + strlen(kstop_prefix);
+	return num[strspn(num, "0123456789")] == '\0';
+}
+
+static void cleanup_conflicts(struct update *update)
+{
+	struct conflict *conf;
+	list_for_each_entry(conf, &update->conflicts, list) {
+		clear_list(&conf->stack, struct conflict_addr, list);
+		kfree(conf->process_name);
+	}
+	clear_list(&update->conflicts, struct conflict, list);
+}
+
+static void print_conflicts(struct update *update)
+{
+	const struct conflict *conf;
+	const struct conflict_addr *ca;
+	list_for_each_entry(conf, &update->conflicts, list) {
+		_ksdebug(update, "stack check: pid %d (%s):", conf->pid,
+			 conf->process_name);
+		list_for_each_entry(ca, &conf->stack, list) {
+			_ksdebug(update, " %lx", ca->addr);
+			if (ca->has_conflict)
+				_ksdebug(update, " [<-CONFLICT]");
+		}
+		_ksdebug(update, "\n");
+	}
+}
+
+static void insert_trampoline(struct ksplice_patch *p)
+{
+	mm_segment_t old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	memcpy(p->saved, p->vaddr, p->size);
+	memcpy(p->vaddr, p->contents, p->size);
+	flush_icache_range(p->oldaddr, p->oldaddr + p->size);
+	set_fs(old_fs);
+}
+
+static abort_t verify_trampoline(struct ksplice_mod_change *change,
+				 const struct ksplice_patch *p)
+{
+	if (memcmp(p->vaddr, p->contents, p->size) != 0) {
+		ksdebug(change, "Aborted.  Trampoline at %lx has been "
+			"overwritten.\n", p->oldaddr);
+		return CODE_BUSY;
+	}
+	return OK;
+}
+
+static void remove_trampoline(const struct ksplice_patch *p)
+{
+	mm_segment_t old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	memcpy(p->vaddr, p->saved, p->size);
+	flush_icache_range(p->oldaddr, p->oldaddr + p->size);
+	set_fs(old_fs);
+}
+
+/* Returns NO_MATCH if there's already a labelval with a different value */
+static abort_t create_labelval(struct ksplice_mod_change *change,
+			       struct ksplice_symbol *ksym,
+			       unsigned long val, int status)
+{
+	val = follow_trampolines(change, val);
+	if (ksym->candidate_vals == NULL)
+		return ksym->value == val ? OK : NO_MATCH;
+
+	ksym->value = val;
+	if (status == TEMP) {
+		struct labelval *lv = kmalloc(sizeof(*lv), GFP_KERNEL);
+		if (lv == NULL)
+			return OUT_OF_MEMORY;
+		lv->symbol = ksym;
+		lv->saved_vals = ksym->candidate_vals;
+		list_add(&lv->list, &change->temp_labelvals);
+	}
+	ksym->candidate_vals = NULL;
+	return OK;
+}
+
+/*
+ * Creates a new safety_record for a old_code section based on its
+ * ksplice_section and run-pre matching information.
+ */
+static abort_t create_safety_record(struct ksplice_mod_change *change,
+				    const struct ksplice_section *sect,
+				    struct list_head *record_list,
+				    unsigned long run_addr,
+				    unsigned long run_size)
+{
+	struct safety_record *rec;
+	struct ksplice_patch *p;
+
+	if (record_list == NULL)
+		return OK;
+
+	for (p = change->patches; p < change->patches_end; p++) {
+		const struct ksplice_reloc *r = patch_reloc(change, p);
+		if (strcmp(sect->symbol->label, r->symbol->label) == 0)
+			break;
+	}
+	if (p >= change->patches_end)
+		return OK;
+
+	rec = kmalloc(sizeof(*rec), GFP_KERNEL);
+	if (rec == NULL)
+		return OUT_OF_MEMORY;
+	/*
+	 * The old_code might be unloaded when checking reversing
+	 * patches, so we need to kstrdup the label here.
+	 */
+	rec->label = kstrdup(sect->symbol->label, GFP_KERNEL);
+	if (rec->label == NULL) {
+		kfree(rec);
+		return OUT_OF_MEMORY;
+	}
+	rec->addr = run_addr;
+	rec->size = run_size;
+
+	list_add(&rec->list, record_list);
+	return OK;
+}
+
+static abort_t add_candidate_val(struct ksplice_mod_change *change,
+				 struct list_head *vals, unsigned long val)
+{
+	struct candidate_val *tmp, *new;
+
+/*
+ * Careful: follow trampolines before comparing values so that we do
+ * not mistake the obsolete function for another copy of the function.
+ */
+	val = follow_trampolines(change, val);
+
+	list_for_each_entry(tmp, vals, list) {
+		if (tmp->val == val)
+			return OK;
+	}
+	new = kmalloc(sizeof(*new), GFP_KERNEL);
+	if (new == NULL)
+		return OUT_OF_MEMORY;
+	new->val = val;
+	list_add(&new->list, vals);
+	return OK;
+}
+
+static void release_vals(struct list_head *vals)
+{
+	clear_list(vals, struct candidate_val, list);
+}
+
+/*
+ * The temp_labelvals list is used to cache those temporary labelvals
+ * that have been created to cross-check the symbol values obtained
+ * from different relocations within a single section being matched.
+ *
+ * If status is VAL, commit the temp_labelvals as final values.
+ *
+ * If status is NOVAL, restore the list of possible values to the
+ * ksplice_symbol, so that it no longer has a known value.
+ */
+static void set_temp_labelvals(struct ksplice_mod_change *change, int status)
+{
+	struct labelval *lv, *n;
+	list_for_each_entry_safe(lv, n, &change->temp_labelvals, list) {
+		if (status == NOVAL) {
+			lv->symbol->candidate_vals = lv->saved_vals;
+		} else {
+			release_vals(lv->saved_vals);
+			kfree(lv->saved_vals);
+		}
+		list_del(&lv->list);
+		kfree(lv);
+	}
+}
+
+/* Is there a Ksplice canary with given howto at blank_addr? */
+static int contains_canary(struct ksplice_mod_change *change,
+			   unsigned long blank_addr,
+			   const struct ksplice_reloc_howto *howto)
+{
+	switch (howto->size) {
+	case 1:
+		return (*(uint8_t *)blank_addr & howto->dst_mask) ==
+		    (KSPLICE_CANARY & howto->dst_mask);
+	case 2:
+		return (*(uint16_t *)blank_addr & howto->dst_mask) ==
+		    (KSPLICE_CANARY & howto->dst_mask);
+	case 4:
+		return (*(uint32_t *)blank_addr & howto->dst_mask) ==
+		    (KSPLICE_CANARY & howto->dst_mask);
+#if BITS_PER_LONG >= 64
+	case 8:
+		return (*(uint64_t *)blank_addr & howto->dst_mask) ==
+		    (KSPLICE_CANARY & howto->dst_mask);
+#endif /* BITS_PER_LONG */
+	default:
+		ksdebug(change, "Aborted.  Invalid relocation size.\n");
+		return -1;
+	}
+}
+
+/*
+ * Compute the address of the code you would actually run if you were
+ * to call the function at addr (i.e., follow the sequence of jumps
+ * starting at addr)
+ */
+static unsigned long follow_trampolines(struct ksplice_mod_change *change,
+					unsigned long addr)
+{
+	unsigned long new_addr;
+	struct module *m;
+
+	while (1) {
+		if (!__kernel_text_address(addr) ||
+		    trampoline_target(change, addr, &new_addr) != OK)
+			return addr;
+		m = __module_text_address(new_addr);
+		if (m == NULL || m == change->target ||
+		    !strstarts(m->name, "ksplice"))
+			return addr;
+		addr = new_addr;
+	}
+}
+
+/* Does module a patch module b? */
+static bool patches_module(const struct module *a, const struct module *b)
+{
+	struct ksplice_module_list_entry *entry;
+	if (a == b)
+		return true;
+	list_for_each_entry(entry, &ksplice_modules, list) {
+		if (strcmp(entry->target_mod_name, b->name) == 0 &&
+		    strcmp(entry->new_code_mod_name, a->name) == 0)
+			return true;
+	}
+	return false;
+}
+
+static bool singular(struct list_head *list)
+{
+	return !list_empty(list) && list->next->next == list;
+}
+
+static void *bsearch(const void *key, const void *base, size_t n,
+		     size_t size, int (*cmp)(const void *key, const void *elt))
+{
+	int start = 0, end = n - 1, mid, result;
+	if (n == 0)
+		return NULL;
+	while (start <= end) {
+		mid = (start + end) / 2;
+		result = cmp(key, base + mid * size);
+		if (result < 0)
+			end = mid - 1;
+		else if (result > 0)
+			start = mid + 1;
+		else
+			return (void *)base + mid * size;
+	}
+	return NULL;
+}
+
+static int compare_relocs(const void *a, const void *b)
+{
+	const struct ksplice_reloc *ra = a, *rb = b;
+	if (ra->blank_addr > rb->blank_addr)
+		return 1;
+	else if (ra->blank_addr < rb->blank_addr)
+		return -1;
+	else
+		return ra->howto->size - rb->howto->size;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+static abort_t init_debug_buf(struct update *update)
+{
+	update->debug_blob.size = 0;
+	update->debug_blob.data = NULL;
+	update->debugfs_dentry =
+	    debugfs_create_blob(update->name, S_IFREG | S_IRUSR, NULL,
+				&update->debug_blob);
+	if (update->debugfs_dentry == NULL)
+		return OUT_OF_MEMORY;
+	return OK;
+}
+
+static void clear_debug_buf(struct update *update)
+{
+	if (update->debugfs_dentry == NULL)
+		return;
+	debugfs_remove(update->debugfs_dentry);
+	update->debugfs_dentry = NULL;
+	update->debug_blob.size = 0;
+	vfree(update->debug_blob.data);
+	update->debug_blob.data = NULL;
+}
+
+static int _ksdebug(struct update *update, const char *fmt, ...)
+{
+	va_list args;
+	unsigned long size, old_size, new_size;
+
+	if (update->debug == 0)
+		return 0;
+
+	/* size includes the trailing '\0' */
+	va_start(args, fmt);
+	size = 1 + vsnprintf(update->debug_blob.data, 0, fmt, args);
+	va_end(args);
+	old_size = update->debug_blob.size == 0 ? 0 :
+	    max(PAGE_SIZE, roundup_pow_of_two(update->debug_blob.size));
+	new_size = update->debug_blob.size + size == 0 ? 0 :
+	    max(PAGE_SIZE, roundup_pow_of_two(update->debug_blob.size + size));
+	if (new_size > old_size) {
+		char *buf = vmalloc(new_size);
+		if (buf == NULL)
+			return -ENOMEM;
+		memcpy(buf, update->debug_blob.data, update->debug_blob.size);
+		vfree(update->debug_blob.data);
+		update->debug_blob.data = buf;
+	}
+	va_start(args, fmt);
+	update->debug_blob.size += vsnprintf(update->debug_blob.data +
+					     update->debug_blob.size,
+					     size, fmt, args);
+	va_end(args);
+	return 0;
+}
+#else /* CONFIG_DEBUG_FS */
+static abort_t init_debug_buf(struct update *update)
+{
+	return OK;
+}
+
+static void clear_debug_buf(struct update *update)
+{
+	return;
+}
+
+static int _ksdebug(struct update *update, const char *fmt, ...)
+{
+	va_list args;
+
+	if (update->debug == 0)
+		return 0;
+
+	if (!update->debug_continue_line)
+		printk(KERN_DEBUG "ksplice: ");
+
+	va_start(args, fmt);
+	vprintk(fmt, args);
+	va_end(args);
+
+	update->debug_continue_line =
+	    fmt[0] == '\0' || fmt[strlen(fmt) - 1] != '\n';
+	return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+struct update_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct update *update, char *buf);
+	ssize_t (*store)(struct update *update, const char *buf, size_t len);
+};
+
+static ssize_t update_attr_show(struct kobject *kobj, struct attribute *attr,
+				char *buf)
+{
+	struct update_attribute *attribute =
+	    container_of(attr, struct update_attribute, attr);
+	struct update *update = container_of(kobj, struct update, kobj);
+	if (attribute->show == NULL)
+		return -EIO;
+	return attribute->show(update, buf);
+}
+
+static ssize_t update_attr_store(struct kobject *kobj, struct attribute *attr,
+				 const char *buf, size_t len)
+{
+	struct update_attribute *attribute =
+	    container_of(attr, struct update_attribute, attr);
+	struct update *update = container_of(kobj, struct update, kobj);
+	if (attribute->store == NULL)
+		return -EIO;
+	return attribute->store(update, buf, len);
+}
+
+static struct sysfs_ops update_sysfs_ops = {
+	.show = update_attr_show,
+	.store = update_attr_store,
+};
+
+static void update_release(struct kobject *kobj)
+{
+	struct update *update;
+	update = container_of(kobj, struct update, kobj);
+	cleanup_ksplice_update(update);
+}
+
+static ssize_t stage_show(struct update *update, char *buf)
+{
+	switch (update->stage) {
+	case STAGE_PREPARING:
+		return snprintf(buf, PAGE_SIZE, "preparing\n");
+	case STAGE_APPLIED:
+		return snprintf(buf, PAGE_SIZE, "applied\n");
+	case STAGE_REVERSED:
+		return snprintf(buf, PAGE_SIZE, "reversed\n");
+	}
+	return 0;
+}
+
+static ssize_t abort_cause_show(struct update *update, char *buf)
+{
+	switch (update->abort_cause) {
+	case OK:
+		return snprintf(buf, PAGE_SIZE, "ok\n");
+	case NO_MATCH:
+		return snprintf(buf, PAGE_SIZE, "no_match\n");
+	case CODE_BUSY:
+		return snprintf(buf, PAGE_SIZE, "code_busy\n");
+	case MODULE_BUSY:
+		return snprintf(buf, PAGE_SIZE, "module_busy\n");
+	case OUT_OF_MEMORY:
+		return snprintf(buf, PAGE_SIZE, "out_of_memory\n");
+	case FAILED_TO_FIND:
+		return snprintf(buf, PAGE_SIZE, "failed_to_find\n");
+	case ALREADY_REVERSED:
+		return snprintf(buf, PAGE_SIZE, "already_reversed\n");
+	case MISSING_EXPORT:
+		return snprintf(buf, PAGE_SIZE, "missing_export\n");
+	case UNEXPECTED_RUNNING_TASK:
+		return snprintf(buf, PAGE_SIZE, "unexpected_running_task\n");
+	case TARGET_NOT_LOADED:
+		return snprintf(buf, PAGE_SIZE, "target_not_loaded\n");
+	case CALL_FAILED:
+		return snprintf(buf, PAGE_SIZE, "call_failed\n");
+	case COLD_UPDATE_LOADED:
+		return snprintf(buf, PAGE_SIZE, "cold_update_loaded\n");
+	case UNEXPECTED:
+		return snprintf(buf, PAGE_SIZE, "unexpected\n");
+	default:
+		return snprintf(buf, PAGE_SIZE, "unknown\n");
+	}
+	return 0;
+}
+
+static ssize_t conflict_show(struct update *update, char *buf)
+{
+	const struct conflict *conf;
+	const struct conflict_addr *ca;
+	int used = 0;
+	mutex_lock(&module_mutex);
+	list_for_each_entry(conf, &update->conflicts, list) {
+		used += snprintf(buf + used, PAGE_SIZE - used, "%s %d",
+				 conf->process_name, conf->pid);
+		list_for_each_entry(ca, &conf->stack, list) {
+			if (!ca->has_conflict)
+				continue;
+			used += snprintf(buf + used, PAGE_SIZE - used, " %s",
+					 ca->label);
+		}
+		used += snprintf(buf + used, PAGE_SIZE - used, "\n");
+	}
+	mutex_unlock(&module_mutex);
+	return used;
+}
+
+/* Used to pass maybe_cleanup_ksplice_update to kthread_run */
+static int maybe_cleanup_ksplice_update_wrapper(void *updateptr)
+{
+	struct update *update = updateptr;
+	mutex_lock(&module_mutex);
+	maybe_cleanup_ksplice_update(update);
+	mutex_unlock(&module_mutex);
+	return 0;
+}
+
+static ssize_t stage_store(struct update *update, const char *buf, size_t len)
+{
+	enum stage old_stage;
+	mutex_lock(&module_mutex);
+	old_stage = update->stage;
+	if ((strncmp(buf, "applied", len) == 0 ||
+	     strncmp(buf, "applied\n", len) == 0) &&
+	    update->stage == STAGE_PREPARING)
+		update->abort_cause = apply_update(update);
+	else if ((strncmp(buf, "reversed", len) == 0 ||
+		  strncmp(buf, "reversed\n", len) == 0) &&
+		 update->stage == STAGE_APPLIED)
+		update->abort_cause = reverse_update(update);
+	else if ((strncmp(buf, "cleanup", len) == 0 ||
+		  strncmp(buf, "cleanup\n", len) == 0) &&
+		 update->stage == STAGE_REVERSED)
+		kthread_run(maybe_cleanup_ksplice_update_wrapper, update,
+			    "ksplice_cleanup_%s", update->kid);
+
+	mutex_unlock(&module_mutex);
+	return len;
+}
+
+static ssize_t debug_show(struct update *update, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", update->debug);
+}
+
+static ssize_t debug_store(struct update *update, const char *buf, size_t len)
+{
+	unsigned long l;
+	int ret = strict_strtoul(buf, 10, &l);
+	if (ret != 0)
+		return ret;
+	update->debug = l;
+	return len;
+}
+
+static ssize_t partial_show(struct update *update, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", update->partial);
+}
+
+static ssize_t partial_store(struct update *update, const char *buf, size_t len)
+{
+	unsigned long l;
+	int ret = strict_strtoul(buf, 10, &l);
+	if (ret != 0)
+		return ret;
+	update->partial = l;
+	return len;
+}
+
+static struct update_attribute stage_attribute =
+	__ATTR(stage, 0600, stage_show, stage_store);
+static struct update_attribute abort_cause_attribute =
+	__ATTR(abort_cause, 0400, abort_cause_show, NULL);
+static struct update_attribute debug_attribute =
+	__ATTR(debug, 0600, debug_show, debug_store);
+static struct update_attribute partial_attribute =
+	__ATTR(partial, 0600, partial_show, partial_store);
+static struct update_attribute conflict_attribute =
+	__ATTR(conflicts, 0400, conflict_show, NULL);
+
+static struct attribute *update_attrs[] = {
+	&stage_attribute.attr,
+	&abort_cause_attribute.attr,
+	&debug_attribute.attr,
+	&partial_attribute.attr,
+	&conflict_attribute.attr,
+	NULL
+};
+
+static struct kobj_type update_ktype = {
+	.sysfs_ops = &update_sysfs_ops,
+	.release = update_release,
+	.default_attrs = update_attrs,
+};
+
+static int init_ksplice(void)
+{
+	ksplice_kobj = kobject_create_and_add("ksplice", kernel_kobj);
+	if (ksplice_kobj == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+static void cleanup_ksplice(void)
+{
+	kobject_put(ksplice_kobj);
+}
+
+module_init(init_ksplice);
+module_exit(cleanup_ksplice);
+
+MODULE_AUTHOR("Ksplice, Inc.");
+MODULE_DESCRIPTION("Ksplice rebootless update system");
+MODULE_LICENSE("GPL v2");
diff --git a/kernel/panic.c b/kernel/panic.c
index 2a2ff36..90faf4a 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -156,6 +156,7 @@ static const struct tnt tnts[] = {
 	{ TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' },
 	{ TAINT_WARN, 'W', ' ' },
 	{ TAINT_CRAP, 'C', ' ' },
+	{ TAINT_KSPLICE, 'K', ' ' },
 };
 
 /**
-- 
1.6.1.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/4] x86: Add an option to compile with -ffunction-sections -fdata-sections
  2009-02-25  0:21   ` [PATCH v2 2/4] x86: Add an option to compile " Tim Abbott
  2009-02-25  0:21     ` [PATCH v2 3/4] Ksplice: Export symbols needed for Ksplice Tim Abbott
@ 2009-02-25  1:21     ` H. Peter Anvin
  2009-02-27  2:10       ` [PATCH] modpost: Check the section flags, not name, to catch missing "ax"/"aw" Anders Kaseorg
  1 sibling, 1 reply; 8+ messages in thread
From: H. Peter Anvin @ 2009-02-25  1:21 UTC (permalink / raw)
  To: Tim Abbott
  Cc: linux-kernel, Anders Kaseorg, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

Tim Abbott wrote:
> From: Waseem Daher <wdaher@mit.edu>
> 
> This patch makes it possible to link and boot an x86 kernel with
> -ffunction-sections and -fdata-sections enabled.
> 
> Modpost currently warns whenever it sees a section with a name
> matching [.][0-9]+$ because they are often caused by section flag
> mismatch errors.  When compiling with -ffunction-sections
> -fdata-sections, gcc places various classes of local symbols in
> sections with names such as .rodata.__func__.12345, causing these
> warnings to be printed spuriously.  The simplest fix is to disable the
> warning when CONFIG_FUNCTION_DATA_SECTIONS is enabled.
> 

This is a pretty critical set of warnings, that often represent real
bugs.  I don't think it's acceptable to lose them.  However, you already
have (prior in the sequence) changed those section names to not conflict
with the automatically generated ones, so it seems to me that this
should be fixable without too much pain.

	-hpa

-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH] modpost: Check the section flags, not name, to catch missing "ax"/"aw"
  2009-02-25  1:21     ` [PATCH v2 2/4] x86: Add an option to compile with -ffunction-sections -fdata-sections H. Peter Anvin
@ 2009-02-27  2:10       ` Anders Kaseorg
  2009-02-27 12:35         ` H. Peter Anvin
  0 siblings, 1 reply; 8+ messages in thread
From: Anders Kaseorg @ 2009-02-27  2:10 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Tim Abbott, linux-kernel, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

On Tue, 24 Feb 2009, H. Peter Anvin wrote:
> This is a pretty critical set of warnings, that often represent real 
> bugs.  I don't think it's acceptable to lose them.  However, you already 
> have (prior in the sequence) changed those section names to not conflict 
> with the automatically generated ones, so it seems to me that this 
> should be fixable without too much pain.

Actually, the problem arises from a conflict between two classes of 
automatically generated section names, one from ld, and one from gcc.  
Instead of basing the warning on section names (the existing heuristic 
also fails to warn on some cases where it should, as it turns out), what 
do you think about this patch?  I've tested that it still triggers the 
warning when an "ax" or "aw" is incorrectly removed, and it should handle 
even more cases than before.

Anders

[PATCH] modpost: Check the section flags, not name, to catch missing "ax"/"aw"

When you put
  .section ".foo"
in an assembly file instead of
  .section "foo", "ax"
, one of the possible symptoms is that modpost will see an
ld-generated section name ".foo.1" in section_rel() or section_rela().
But this heuristic has two problems: it will miss a bad section that
has no relocations, and it will incorrectly flag many gcc-generated
sections as bad when compiling with -ffunction-sections
-fdata-sections.

So instead of checking whether the section name matches a particular
pattern, we directly check for a missing SHF_ALLOC in the section
flags.

Signed-off-by: Anders Kaseorg <andersk@mit.edu>
---
 scripts/mod/modpost.c |   49 ++++++++++++++++++-------------------------------
 1 files changed, 18 insertions(+), 31 deletions(-)

diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8892161..bb794fa 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -713,41 +713,27 @@ int match(const char *sym, const char * const pat[])
 
 /* sections that we do not want to do full section mismatch check on */
 static const char *section_white_list[] =
-	{ ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL };
+	{ ".comment", ".debug*", ".stab*", ".note*", ".got*", ".toc*", NULL };
 
 /*
- * Is this section one we do not want to check?
- * This is often debug sections.
- * If we are going to check this section then
- * test if section name ends with a dot and a number.
- * This is used to find sections where the linker have
- * appended a dot-number to make the name unique.
+ * This is used to find sections missing the SHF_ALLOC flag.
  * The cause of this is often a section specified in assembler
- * without "ax" / "aw" and the same section used in .c
- * code where gcc add these.
+ * without "ax" / "aw".
  */
-static int check_section(const char *modname, const char *sec)
-{
-	const char *e = sec + strlen(sec) - 1;
-	if (match(sec, section_white_list))
-		return 1;
-
-	if (*e && isdigit(*e)) {
-		/* consume all digits */
-		while (*e && e != sec && isdigit(*e))
-			e--;
-		if (*e == '.' && !strstr(sec, ".linkonce")) {
-			warn("%s (%s): unexpected section name.\n"
-			     "The (.[number]+) following section name are "
-			     "ld generated and not expected.\n"
-			     "Did you forget to use \"ax\"/\"aw\" "
-			     "in a .S file?\n"
-			     "Note that for example <linux/init.h> contains\n"
-			     "section definitions for use in .S files.\n\n",
-			     modname, sec);
-		}
+static void check_section(const char *modname, struct elf_info *elf,
+                          Elf_Shdr *sechdr)
+{
+	const char *sec = sech_name(elf, sechdr);
+
+	if (sechdr->sh_type == SHT_PROGBITS &&
+	    !(sechdr->sh_flags & SHF_ALLOC) &&
+	    !match(sec, section_white_list)) {
+		warn("%s (%s): unexpected non-allocatable section.\n"
+		     "Did you forget to use \"ax\"/\"aw\" in a .S file?\n"
+		     "Note that for example <linux/init.h> contains\n"
+		     "section definitions for use in .S files.\n\n",
+		     modname, sec);
 	}
-	return 0;
 }
 
 
@@ -1374,7 +1360,7 @@ static void section_rela(const char *modname, struct elf_info *elf,
 	fromsec = sech_name(elf, sechdr);
 	fromsec += strlen(".rela");
 	/* if from section (name) is know good then skip it */
-	if (check_section(modname, fromsec))
+	if (match(fromsec, section_white_list))
 		return;
 
 	for (rela = start; rela < stop; rela++) {
@@ -1418,7 +1404,7 @@ static void section_rel(const char *modname, struct elf_info *elf,
 	fromsec = sech_name(elf, sechdr);
 	fromsec += strlen(".rel");
 	/* if from section (name) is know good then skip it */
-	if (check_section(modname, fromsec))
+	if (match(fromsec, section_white_list))
 		return;
 
 	for (rel = start; rel < stop; rel++) {
@@ -1481,6 +1467,7 @@ static void check_sec_ref(struct module *mod, const char *modname,
 
 	/* Walk through all sections */
 	for (i = 0; i < elf->hdr->e_shnum; i++) {
+		check_section(modname, elf, &elf->sechdrs[i]);
 		/* We want to process only relocation sections and not .init */
 		if (sechdrs[i].sh_type == SHT_RELA)
 			section_rela(modname, elf, &elf->sechdrs[i]);
-- 
1.6.1.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] modpost: Check the section flags, not name, to catch missing "ax"/"aw"
  2009-02-27  2:10       ` [PATCH] modpost: Check the section flags, not name, to catch missing "ax"/"aw" Anders Kaseorg
@ 2009-02-27 12:35         ` H. Peter Anvin
  0 siblings, 0 replies; 8+ messages in thread
From: H. Peter Anvin @ 2009-02-27 12:35 UTC (permalink / raw)
  To: Anders Kaseorg
  Cc: Tim Abbott, linux-kernel, Jeff Arnold, Waseem Daher,
	Denys Vlasenko, Nikanth Karthikesan, Rusty Russell, Andi Kleen

Anders Kaseorg wrote:
> On Tue, 24 Feb 2009, H. Peter Anvin wrote:
>> This is a pretty critical set of warnings, that often represent real 
>> bugs.  I don't think it's acceptable to lose them.  However, you already 
>> have (prior in the sequence) changed those section names to not conflict 
>> with the automatically generated ones, so it seems to me that this 
>> should be fixable without too much pain.
> 
> Actually, the problem arises from a conflict between two classes of 
> automatically generated section names, one from ld, and one from gcc.  
> Instead of basing the warning on section names (the existing heuristic 
> also fails to warn on some cases where it should, as it turns out), what 
> do you think about this patch?  I've tested that it still triggers the 
> warning when an "ax" or "aw" is incorrectly removed, and it should handle 
> even more cases than before.
> 

Seems reasonable to me.

	-hpa


-- 
H. Peter Anvin, Intel Open Source Technology Center
I work for Intel.  I don't speak on their behalf.


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-02-27 12:36 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-02-25  0:21 [PATCH v2 0/4] Ksplice: Rebootless kernel updates Tim Abbott
2009-02-25  0:21 ` [PATCH v2 1/4] Make section names compatible with -ffunction-sections -fdata-sections Tim Abbott
2009-02-25  0:21   ` [PATCH v2 2/4] x86: Add an option to compile " Tim Abbott
2009-02-25  0:21     ` [PATCH v2 3/4] Ksplice: Export symbols needed for Ksplice Tim Abbott
2009-02-25  0:21       ` [PATCH v2 4/4] Ksplice: Support updating x86-32 and x86-64 Tim Abbott
2009-02-25  1:21     ` [PATCH v2 2/4] x86: Add an option to compile with -ffunction-sections -fdata-sections H. Peter Anvin
2009-02-27  2:10       ` [PATCH] modpost: Check the section flags, not name, to catch missing "ax"/"aw" Anders Kaseorg
2009-02-27 12:35         ` H. Peter Anvin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).