Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Aug 2018 18:25:21 +0000 (11:25 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 26 Aug 2018 18:25:21 +0000 (11:25 -0700)
Pull perf updates from Thomas Gleixner:
 "Kernel:
   - Improve kallsyms coverage
   - Add x86 entry trampolines to kcore
   - Fix ARM SPE handling
   - Correct PPC event post processing

  Tools:
   - Make the build system more robust
   - Small fixes and enhancements all over the place
   - Update kernel ABI header copies
   - Preparatory work for converting libtraceevnt to a shared library
   - License cleanups"

* 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (100 commits)
  tools arch: Update arch/x86/lib/memcpy_64.S copy used in 'perf bench mem memcpy'
  tools arch x86: Update tools's copy of cpufeatures.h
  perf python: Fix pyrf_evlist__read_on_cpu() interface
  perf mmap: Store real cpu number in 'struct perf_mmap'
  perf tools: Remove ext from struct kmod_path
  perf tools: Add gzip_is_compressed function
  perf tools: Add lzma_is_compressed function
  perf tools: Add is_compressed callback to compressions array
  perf tools: Move the temp file processing into decompress_kmodule
  perf tools: Use compression id in decompress_kmodule()
  perf tools: Store compression id into struct dso
  perf tools: Add compression id into 'struct kmod_path'
  perf tools: Make is_supported_compression() static
  perf tools: Make decompress_to_file() function static
  perf tools: Get rid of dso__needs_decompress() call in __open_dso()
  perf tools: Get rid of dso__needs_decompress() call in symbol__disassemble()
  perf tools: Get rid of dso__needs_decompress() call in read_object_code()
  tools lib traceevent: Change to SPDX License format
  perf llvm: Allow passing options to llc in addition to clang
  perf parser: Improve error message for PMU address filters
  ...

1  2 
fs/proc/kcore.c
include/linux/kcore.h
tools/arch/x86/include/asm/cpufeatures.h

diff --combined fs/proc/kcore.c
index 80464432dfe6459eeec7d41498a65abb4f9d0dbe,00282f134336aaa9a43360f1625b553ed33bdccb..ad72261ee3fe8d1959038fa0ee9bf6d0ff276449
@@@ -10,7 -10,6 +10,7 @@@
   *    Safe accesses to vmalloc/direct-mapped discontiguous areas, Kanoj Sarcar <kanoj@sgi.com>
   */
  
 +#include <linux/crash_core.h>
  #include <linux/mm.h>
  #include <linux/proc_fs.h>
  #include <linux/kcore.h>
@@@ -50,23 -49,32 +50,23 @@@ static struct proc_dir_entry *proc_root
  #define       kc_offset_to_vaddr(o) ((o) + PAGE_OFFSET)
  #endif
  
 -/* An ELF note in memory */
 -struct memelfnote
 -{
 -      const char *name;
 -      int type;
 -      unsigned int datasz;
 -      void *data;
 -};
 -
  static LIST_HEAD(kclist_head);
 -static DEFINE_RWLOCK(kclist_lock);
 +static DECLARE_RWSEM(kclist_lock);
  static int kcore_need_update = 1;
  
 -void
 -kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
 +/* This doesn't grab kclist_lock, so it should only be used at init time. */
 +void __init kclist_add(struct kcore_list *new, void *addr, size_t size,
 +                     int type)
  {
        new->addr = (unsigned long)addr;
        new->size = size;
        new->type = type;
  
 -      write_lock(&kclist_lock);
        list_add_tail(&new->list, &kclist_head);
 -      write_unlock(&kclist_lock);
  }
  
 -static size_t get_kcore_size(int *nphdr, size_t *elf_buflen)
 +static size_t get_kcore_size(int *nphdr, size_t *phdrs_len, size_t *notes_len,
 +                           size_t *data_offset)
  {
        size_t try, size;
        struct kcore_list *m;
                        size = try;
                *nphdr = *nphdr + 1;
        }
 -      *elf_buflen =   sizeof(struct elfhdr) + 
 -                      (*nphdr + 2)*sizeof(struct elf_phdr) + 
 -                      3 * ((sizeof(struct elf_note)) +
 -                           roundup(sizeof(CORE_STR), 4)) +
 -                      roundup(sizeof(struct elf_prstatus), 4) +
 -                      roundup(sizeof(struct elf_prpsinfo), 4) +
 -                      roundup(arch_task_struct_size, 4);
 -      *elf_buflen = PAGE_ALIGN(*elf_buflen);
 -      return size + *elf_buflen;
 -}
 -
 -static void free_kclist_ents(struct list_head *head)
 -{
 -      struct kcore_list *tmp, *pos;
  
 -      list_for_each_entry_safe(pos, tmp, head, list) {
 -              list_del(&pos->list);
 -              kfree(pos);
 -      }
 +      *phdrs_len = *nphdr * sizeof(struct elf_phdr);
 +      *notes_len = (4 * sizeof(struct elf_note) +
 +                    3 * ALIGN(sizeof(CORE_STR), 4) +
 +                    VMCOREINFO_NOTE_NAME_BYTES +
 +                    ALIGN(sizeof(struct elf_prstatus), 4) +
 +                    ALIGN(sizeof(struct elf_prpsinfo), 4) +
 +                    ALIGN(arch_task_struct_size, 4) +
 +                    ALIGN(vmcoreinfo_size, 4));
 +      *data_offset = PAGE_ALIGN(sizeof(struct elfhdr) + *phdrs_len +
 +                                *notes_len);
 +      return *data_offset + size;
  }
 -/*
 - * Replace all KCORE_RAM/KCORE_VMEMMAP information with passed list.
 - */
 -static void __kcore_update_ram(struct list_head *list)
 -{
 -      int nphdr;
 -      size_t size;
 -      struct kcore_list *tmp, *pos;
 -      LIST_HEAD(garbage);
 -
 -      write_lock(&kclist_lock);
 -      if (kcore_need_update) {
 -              list_for_each_entry_safe(pos, tmp, &kclist_head, list) {
 -                      if (pos->type == KCORE_RAM
 -                              || pos->type == KCORE_VMEMMAP)
 -                              list_move(&pos->list, &garbage);
 -              }
 -              list_splice_tail(list, &kclist_head);
 -      } else
 -              list_splice(list, &garbage);
 -      kcore_need_update = 0;
 -      proc_root_kcore->size = get_kcore_size(&nphdr, &size);
 -      write_unlock(&kclist_lock);
 -
 -      free_kclist_ents(&garbage);
 -}
 -
  
  #ifdef CONFIG_HIGHMEM
  /*
   * because memory hole is not as big as !HIGHMEM case.
   * (HIGHMEM is special because part of memory is _invisible_ from the kernel.)
   */
 -static int kcore_update_ram(void)
 +static int kcore_ram_list(struct list_head *head)
  {
 -      LIST_HEAD(head);
        struct kcore_list *ent;
 -      int ret = 0;
  
        ent = kmalloc(sizeof(*ent), GFP_KERNEL);
        if (!ent)
        ent->addr = (unsigned long)__va(0);
        ent->size = max_low_pfn << PAGE_SHIFT;
        ent->type = KCORE_RAM;
 -      list_add(&ent->list, &head);
 -      __kcore_update_ram(&head);
 -      return ret;
 +      list_add(&ent->list, head);
 +      return 0;
  }
  
  #else /* !CONFIG_HIGHMEM */
@@@ -210,10 -255,11 +210,10 @@@ free_out
        return 1;
  }
  
 -static int kcore_update_ram(void)
 +static int kcore_ram_list(struct list_head *list)
  {
        int nid, ret;
        unsigned long end_pfn;
 -      LIST_HEAD(head);
  
        /* Not inialized....update now */
        /* find out "max pfn" */
                        end_pfn = node_end;
        }
        /* scan 0 to max_pfn */
 -      ret = walk_system_ram_range(0, end_pfn, &head, kclist_add_private);
 -      if (ret) {
 -              free_kclist_ents(&head);
 +      ret = walk_system_ram_range(0, end_pfn, list, kclist_add_private);
 +      if (ret)
                return -ENOMEM;
 -      }
 -      __kcore_update_ram(&head);
 -      return ret;
 +      return 0;
  }
  #endif /* CONFIG_HIGHMEM */
  
 -/*****************************************************************************/
 -/*
 - * determine size of ELF note
 - */
 -static int notesize(struct memelfnote *en)
 -{
 -      int sz;
 -
 -      sz = sizeof(struct elf_note);
 -      sz += roundup((strlen(en->name) + 1), 4);
 -      sz += roundup(en->datasz, 4);
 -
 -      return sz;
 -} /* end notesize() */
 -
 -/*****************************************************************************/
 -/*
 - * store a note in the header buffer
 - */
 -static char *storenote(struct memelfnote *men, char *bufp)
 +static int kcore_update_ram(void)
  {
 -      struct elf_note en;
 -
 -#define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
 -
 -      en.n_namesz = strlen(men->name) + 1;
 -      en.n_descsz = men->datasz;
 -      en.n_type = men->type;
 -
 -      DUMP_WRITE(&en, sizeof(en));
 -      DUMP_WRITE(men->name, en.n_namesz);
 -
 -      /* XXX - cast from long long to long to avoid need for libgcc.a */
 -      bufp = (char*) roundup((unsigned long)bufp,4);
 -      DUMP_WRITE(men->data, men->datasz);
 -      bufp = (char*) roundup((unsigned long)bufp,4);
 -
 -#undef DUMP_WRITE
 -
 -      return bufp;
 -} /* end storenote() */
 +      LIST_HEAD(list);
 +      LIST_HEAD(garbage);
 +      int nphdr;
 +      size_t phdrs_len, notes_len, data_offset;
 +      struct kcore_list *tmp, *pos;
 +      int ret = 0;
  
 -/*
 - * store an ELF coredump header in the supplied buffer
 - * nphdr is the number of elf_phdr to insert
 - */
 -static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff)
 -{
 -      struct elf_prstatus prstatus;   /* NT_PRSTATUS */
 -      struct elf_prpsinfo prpsinfo;   /* NT_PRPSINFO */
 -      struct elf_phdr *nhdr, *phdr;
 -      struct elfhdr *elf;
 -      struct memelfnote notes[3];
 -      off_t offset = 0;
 -      struct kcore_list *m;
 +      down_write(&kclist_lock);
 +      if (!xchg(&kcore_need_update, 0))
 +              goto out;
  
 -      /* setup ELF header */
 -      elf = (struct elfhdr *) bufp;
 -      bufp += sizeof(struct elfhdr);
 -      offset += sizeof(struct elfhdr);
 -      memcpy(elf->e_ident, ELFMAG, SELFMAG);
 -      elf->e_ident[EI_CLASS]  = ELF_CLASS;
 -      elf->e_ident[EI_DATA]   = ELF_DATA;
 -      elf->e_ident[EI_VERSION]= EV_CURRENT;
 -      elf->e_ident[EI_OSABI] = ELF_OSABI;
 -      memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
 -      elf->e_type     = ET_CORE;
 -      elf->e_machine  = ELF_ARCH;
 -      elf->e_version  = EV_CURRENT;
 -      elf->e_entry    = 0;
 -      elf->e_phoff    = sizeof(struct elfhdr);
 -      elf->e_shoff    = 0;
 -      elf->e_flags    = ELF_CORE_EFLAGS;
 -      elf->e_ehsize   = sizeof(struct elfhdr);
 -      elf->e_phentsize= sizeof(struct elf_phdr);
 -      elf->e_phnum    = nphdr;
 -      elf->e_shentsize= 0;
 -      elf->e_shnum    = 0;
 -      elf->e_shstrndx = 0;
 -
 -      /* setup ELF PT_NOTE program header */
 -      nhdr = (struct elf_phdr *) bufp;
 -      bufp += sizeof(struct elf_phdr);
 -      offset += sizeof(struct elf_phdr);
 -      nhdr->p_type    = PT_NOTE;
 -      nhdr->p_offset  = 0;
 -      nhdr->p_vaddr   = 0;
 -      nhdr->p_paddr   = 0;
 -      nhdr->p_filesz  = 0;
 -      nhdr->p_memsz   = 0;
 -      nhdr->p_flags   = 0;
 -      nhdr->p_align   = 0;
 -
 -      /* setup ELF PT_LOAD program header for every area */
 -      list_for_each_entry(m, &kclist_head, list) {
 -              phdr = (struct elf_phdr *) bufp;
 -              bufp += sizeof(struct elf_phdr);
 -              offset += sizeof(struct elf_phdr);
 -
 -              phdr->p_type    = PT_LOAD;
 -              phdr->p_flags   = PF_R|PF_W|PF_X;
 -              phdr->p_offset  = kc_vaddr_to_offset(m->addr) + dataoff;
 -              if (m->type == KCORE_REMAP)
 -                      phdr->p_vaddr   = (size_t)m->vaddr;
 -              else
 -                      phdr->p_vaddr   = (size_t)m->addr;
 -              if (m->type == KCORE_RAM || m->type == KCORE_TEXT || m->type == KCORE_REMAP)
 -                      phdr->p_paddr   = __pa(m->addr);
 -              else
 -                      phdr->p_paddr   = (elf_addr_t)-1;
 -              phdr->p_filesz  = phdr->p_memsz = m->size;
 -              phdr->p_align   = PAGE_SIZE;
 +      ret = kcore_ram_list(&list);
 +      if (ret) {
 +              /* Couldn't get the RAM list, try again next time. */
 +              WRITE_ONCE(kcore_need_update, 1);
 +              list_splice_tail(&list, &garbage);
 +              goto out;
        }
  
 -      /*
 -       * Set up the notes in similar form to SVR4 core dumps made
 -       * with info from their /proc.
 -       */
 -      nhdr->p_offset  = offset;
 -
 -      /* set up the process status */
 -      notes[0].name = CORE_STR;
 -      notes[0].type = NT_PRSTATUS;
 -      notes[0].datasz = sizeof(struct elf_prstatus);
 -      notes[0].data = &prstatus;
 -
 -      memset(&prstatus, 0, sizeof(struct elf_prstatus));
 -
 -      nhdr->p_filesz  = notesize(&notes[0]);
 -      bufp = storenote(&notes[0], bufp);
 -
 -      /* set up the process info */
 -      notes[1].name   = CORE_STR;
 -      notes[1].type   = NT_PRPSINFO;
 -      notes[1].datasz = sizeof(struct elf_prpsinfo);
 -      notes[1].data   = &prpsinfo;
 -
 -      memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
 -      prpsinfo.pr_state       = 0;
 -      prpsinfo.pr_sname       = 'R';
 -      prpsinfo.pr_zomb        = 0;
 -
 -      strcpy(prpsinfo.pr_fname, "vmlinux");
 -      strlcpy(prpsinfo.pr_psargs, saved_command_line, sizeof(prpsinfo.pr_psargs));
 -
 -      nhdr->p_filesz  += notesize(&notes[1]);
 -      bufp = storenote(&notes[1], bufp);
 +      list_for_each_entry_safe(pos, tmp, &kclist_head, list) {
 +              if (pos->type == KCORE_RAM || pos->type == KCORE_VMEMMAP)
 +                      list_move(&pos->list, &garbage);
 +      }
 +      list_splice_tail(&list, &kclist_head);
  
 -      /* set up the task structure */
 -      notes[2].name   = CORE_STR;
 -      notes[2].type   = NT_TASKSTRUCT;
 -      notes[2].datasz = arch_task_struct_size;
 -      notes[2].data   = current;
 +      proc_root_kcore->size = get_kcore_size(&nphdr, &phdrs_len, &notes_len,
 +                                             &data_offset);
  
 -      nhdr->p_filesz  += notesize(&notes[2]);
 -      bufp = storenote(&notes[2], bufp);
 +out:
 +      up_write(&kclist_lock);
 +      list_for_each_entry_safe(pos, tmp, &garbage, list) {
 +              list_del(&pos->list);
 +              kfree(pos);
 +      }
 +      return ret;
 +}
  
 -} /* end elf_kcore_store_hdr() */
 +static void append_kcore_note(char *notes, size_t *i, const char *name,
 +                            unsigned int type, const void *desc,
 +                            size_t descsz)
 +{
 +      struct elf_note *note = (struct elf_note *)&notes[*i];
 +
 +      note->n_namesz = strlen(name) + 1;
 +      note->n_descsz = descsz;
 +      note->n_type = type;
 +      *i += sizeof(*note);
 +      memcpy(&notes[*i], name, note->n_namesz);
 +      *i = ALIGN(*i + note->n_namesz, 4);
 +      memcpy(&notes[*i], desc, descsz);
 +      *i = ALIGN(*i + descsz, 4);
 +}
  
 -/*****************************************************************************/
 -/*
 - * read from the ELF header and then kernel memory
 - */
  static ssize_t
  read_kcore(struct file *file, char __user *buffer, size_t buflen, loff_t *fpos)
  {
        char *buf = file->private_data;
 -      ssize_t acc = 0;
 -      size_t size, tsz;
 -      size_t elf_buflen;
 +      size_t phdrs_offset, notes_offset, data_offset;
 +      size_t phdrs_len, notes_len;
 +      struct kcore_list *m;
 +      size_t tsz;
        int nphdr;
        unsigned long start;
 +      size_t orig_buflen = buflen;
 +      int ret = 0;
  
 -      read_lock(&kclist_lock);
 -      size = get_kcore_size(&nphdr, &elf_buflen);
 +      down_read(&kclist_lock);
 +
 +      get_kcore_size(&nphdr, &phdrs_len, &notes_len, &data_offset);
 +      phdrs_offset = sizeof(struct elfhdr);
 +      notes_offset = phdrs_offset + phdrs_len;
 +
 +      /* ELF file header. */
 +      if (buflen && *fpos < sizeof(struct elfhdr)) {
 +              struct elfhdr ehdr = {
 +                      .e_ident = {
 +                              [EI_MAG0] = ELFMAG0,
 +                              [EI_MAG1] = ELFMAG1,
 +                              [EI_MAG2] = ELFMAG2,
 +                              [EI_MAG3] = ELFMAG3,
 +                              [EI_CLASS] = ELF_CLASS,
 +                              [EI_DATA] = ELF_DATA,
 +                              [EI_VERSION] = EV_CURRENT,
 +                              [EI_OSABI] = ELF_OSABI,
 +                      },
 +                      .e_type = ET_CORE,
 +                      .e_machine = ELF_ARCH,
 +                      .e_version = EV_CURRENT,
 +                      .e_phoff = sizeof(struct elfhdr),
 +                      .e_flags = ELF_CORE_EFLAGS,
 +                      .e_ehsize = sizeof(struct elfhdr),
 +                      .e_phentsize = sizeof(struct elf_phdr),
 +                      .e_phnum = nphdr,
 +              };
 +
 +              tsz = min_t(size_t, buflen, sizeof(struct elfhdr) - *fpos);
 +              if (copy_to_user(buffer, (char *)&ehdr + *fpos, tsz)) {
 +                      ret = -EFAULT;
 +                      goto out;
 +              }
  
 -      if (buflen == 0 || *fpos >= size) {
 -              read_unlock(&kclist_lock);
 -              return 0;
 +              buffer += tsz;
 +              buflen -= tsz;
 +              *fpos += tsz;
        }
  
 -      /* trim buflen to not go beyond EOF */
 -      if (buflen > size - *fpos)
 -              buflen = size - *fpos;
 -
 -      /* construct an ELF core header if we'll need some of it */
 -      if (*fpos < elf_buflen) {
 -              char * elf_buf;
 -
 -              tsz = elf_buflen - *fpos;
 -              if (buflen < tsz)
 -                      tsz = buflen;
 -              elf_buf = kzalloc(elf_buflen, GFP_ATOMIC);
 -              if (!elf_buf) {
 -                      read_unlock(&kclist_lock);
 -                      return -ENOMEM;
 +      /* ELF program headers. */
 +      if (buflen && *fpos < phdrs_offset + phdrs_len) {
 +              struct elf_phdr *phdrs, *phdr;
 +
 +              phdrs = kzalloc(phdrs_len, GFP_KERNEL);
 +              if (!phdrs) {
 +                      ret = -ENOMEM;
 +                      goto out;
                }
 -              elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen);
 -              read_unlock(&kclist_lock);
 -              if (copy_to_user(buffer, elf_buf + *fpos, tsz)) {
 -                      kfree(elf_buf);
 -                      return -EFAULT;
 +
 +              phdrs[0].p_type = PT_NOTE;
 +              phdrs[0].p_offset = notes_offset;
 +              phdrs[0].p_filesz = notes_len;
 +
 +              phdr = &phdrs[1];
 +              list_for_each_entry(m, &kclist_head, list) {
 +                      phdr->p_type = PT_LOAD;
 +                      phdr->p_flags = PF_R | PF_W | PF_X;
 +                      phdr->p_offset = kc_vaddr_to_offset(m->addr) + data_offset;
-                       phdr->p_vaddr = (size_t)m->addr;
-                       if (m->type == KCORE_RAM)
++                      if (m->type == KCORE_REMAP)
++                              phdr->p_vaddr = (size_t)m->vaddr;
++                      else
++                              phdr->p_vaddr = (size_t)m->addr;
++                      if (m->type == KCORE_RAM || m->type == KCORE_REMAP)
 +                              phdr->p_paddr = __pa(m->addr);
 +                      else if (m->type == KCORE_TEXT)
 +                              phdr->p_paddr = __pa_symbol(m->addr);
 +                      else
 +                              phdr->p_paddr = (elf_addr_t)-1;
 +                      phdr->p_filesz = phdr->p_memsz = m->size;
 +                      phdr->p_align = PAGE_SIZE;
 +                      phdr++;
                }
 -              kfree(elf_buf);
 +
 +              tsz = min_t(size_t, buflen, phdrs_offset + phdrs_len - *fpos);
 +              if (copy_to_user(buffer, (char *)phdrs + *fpos - phdrs_offset,
 +                               tsz)) {
 +                      kfree(phdrs);
 +                      ret = -EFAULT;
 +                      goto out;
 +              }
 +              kfree(phdrs);
 +
 +              buffer += tsz;
                buflen -= tsz;
                *fpos += tsz;
 -              buffer += tsz;
 -              acc += tsz;
 +      }
 +
 +      /* ELF note segment. */
 +      if (buflen && *fpos < notes_offset + notes_len) {
 +              struct elf_prstatus prstatus = {};
 +              struct elf_prpsinfo prpsinfo = {
 +                      .pr_sname = 'R',
 +                      .pr_fname = "vmlinux",
 +              };
 +              char *notes;
 +              size_t i = 0;
 +
 +              strlcpy(prpsinfo.pr_psargs, saved_command_line,
 +                      sizeof(prpsinfo.pr_psargs));
 +
 +              notes = kzalloc(notes_len, GFP_KERNEL);
 +              if (!notes) {
 +                      ret = -ENOMEM;
 +                      goto out;
 +              }
 +
 +              append_kcore_note(notes, &i, CORE_STR, NT_PRSTATUS, &prstatus,
 +                                sizeof(prstatus));
 +              append_kcore_note(notes, &i, CORE_STR, NT_PRPSINFO, &prpsinfo,
 +                                sizeof(prpsinfo));
 +              append_kcore_note(notes, &i, CORE_STR, NT_TASKSTRUCT, current,
 +                                arch_task_struct_size);
 +              /*
 +               * vmcoreinfo_size is mostly constant after init time, but it
 +               * can be changed by crash_save_vmcoreinfo(). Racing here with a
 +               * panic on another CPU before the machine goes down is insanely
 +               * unlikely, but it's better to not leave potential buffer
 +               * overflows lying around, regardless.
 +               */
 +              append_kcore_note(notes, &i, VMCOREINFO_NOTE_NAME, 0,
 +                                vmcoreinfo_data,
 +                                min(vmcoreinfo_size, notes_len - i));
 +
 +              tsz = min_t(size_t, buflen, notes_offset + notes_len - *fpos);
 +              if (copy_to_user(buffer, notes + *fpos - notes_offset, tsz)) {
 +                      kfree(notes);
 +                      ret = -EFAULT;
 +                      goto out;
 +              }
 +              kfree(notes);
  
 -              /* leave now if filled buffer already */
 -              if (buflen == 0)
 -                      return acc;
 -      } else
 -              read_unlock(&kclist_lock);
 +              buffer += tsz;
 +              buflen -= tsz;
 +              *fpos += tsz;
 +      }
  
        /*
         * Check to see if our file offset matches with any of
         * the addresses in the elf_phdr on our list.
         */
 -      start = kc_offset_to_vaddr(*fpos - elf_buflen);
 +      start = kc_offset_to_vaddr(*fpos - data_offset);
        if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
                tsz = buflen;
 -              
 -      while (buflen) {
 -              struct kcore_list *m;
  
 -              read_lock(&kclist_lock);
 -              list_for_each_entry(m, &kclist_head, list) {
 -                      if (start >= m->addr && start < (m->addr+m->size))
 -                              break;
 +      m = NULL;
 +      while (buflen) {
 +              /*
 +               * If this is the first iteration or the address is not within
 +               * the previous entry, search for a matching entry.
 +               */
 +              if (!m || start < m->addr || start >= m->addr + m->size) {
 +                      list_for_each_entry(m, &kclist_head, list) {
 +                              if (start >= m->addr &&
 +                                  start < m->addr + m->size)
 +                                      break;
 +                      }
                }
 -              read_unlock(&kclist_lock);
  
                if (&m->list == &kclist_head) {
 -                      if (clear_user(buffer, tsz))
 -                              return -EFAULT;
 +                      if (clear_user(buffer, tsz)) {
 +                              ret = -EFAULT;
 +                              goto out;
 +                      }
                } else if (m->type == KCORE_VMALLOC) {
                        vread(buf, (char *)start, tsz);
                        /* we have to zero-fill user buffer even if no read */
 -                      if (copy_to_user(buffer, buf, tsz))
 -                              return -EFAULT;
 +                      if (copy_to_user(buffer, buf, tsz)) {
 +                              ret = -EFAULT;
 +                              goto out;
 +                      }
                } else if (m->type == KCORE_USER) {
                        /* User page is handled prior to normal kernel page: */
 -                      if (copy_to_user(buffer, (char *)start, tsz))
 -                              return -EFAULT;
 +                      if (copy_to_user(buffer, (char *)start, tsz)) {
 +                              ret = -EFAULT;
 +                              goto out;
 +                      }
                } else {
                        if (kern_addr_valid(start)) {
                                /*
                                 * hardened user copy kernel text checks.
                                 */
                                if (probe_kernel_read(buf, (void *) start, tsz)) {
 -                                      if (clear_user(buffer, tsz))
 -                                              return -EFAULT;
 +                                      if (clear_user(buffer, tsz)) {
 +                                              ret = -EFAULT;
 +                                              goto out;
 +                                      }
                                } else {
 -                                      if (copy_to_user(buffer, buf, tsz))
 -                                              return -EFAULT;
 +                                      if (copy_to_user(buffer, buf, tsz)) {
 +                                              ret = -EFAULT;
 +                                              goto out;
 +                                      }
                                }
                        } else {
 -                              if (clear_user(buffer, tsz))
 -                                      return -EFAULT;
 +                              if (clear_user(buffer, tsz)) {
 +                                      ret = -EFAULT;
 +                                      goto out;
 +                              }
                        }
                }
                buflen -= tsz;
                *fpos += tsz;
                buffer += tsz;
 -              acc += tsz;
                start += tsz;
                tsz = (buflen > PAGE_SIZE ? PAGE_SIZE : buflen);
        }
  
 -      return acc;
 +out:
 +      up_read(&kclist_lock);
 +      if (ret)
 +              return ret;
 +      return orig_buflen - buflen;
  }
  
 -
  static int open_kcore(struct inode *inode, struct file *filp)
  {
        if (!capable(CAP_SYS_RAWIO))
@@@ -551,8 -595,9 +554,8 @@@ static int __meminit kcore_callback(str
        switch (action) {
        case MEM_ONLINE:
        case MEM_OFFLINE:
 -              write_lock(&kclist_lock);
                kcore_need_update = 1;
 -              write_unlock(&kclist_lock);
 +              break;
        }
        return NOTIFY_OK;
  }
diff --combined include/linux/kcore.h
index c20f296438fbb84997474cb681a51e57eef558ef,bc088ef96358504a07f20e8c824649ea359ef1d4..8c3f8c14eeaafd5b1035f4ef2fec81384f94f77c
@@@ -12,11 -12,13 +12,13 @@@ enum kcore_type 
        KCORE_VMEMMAP,
        KCORE_USER,
        KCORE_OTHER,
+       KCORE_REMAP,
  };
  
  struct kcore_list {
        struct list_head list;
        unsigned long addr;
+       unsigned long vaddr;
        size_t size;
        int type;
  };
@@@ -35,12 -37,23 +37,23 @@@ struct vmcoredd_node 
  };
  
  #ifdef CONFIG_PROC_KCORE
 -extern void kclist_add(struct kcore_list *, void *, size_t, int type);
 +void __init kclist_add(struct kcore_list *, void *, size_t, int type);
+ static inline
+ void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
+ {
+       m->vaddr = (unsigned long)vaddr;
+       kclist_add(m, addr, sz, KCORE_REMAP);
+ }
  #else
  static inline
  void kclist_add(struct kcore_list *new, void *addr, size_t size, int type)
  {
  }
+ static inline
+ void kclist_add_remap(struct kcore_list *m, void *addr, void *vaddr, size_t sz)
+ {
+ }
  #endif
  
  #endif /* _LINUX_KCORE_H */
index 64aaa3f5f36ca2c6cb43f7ab5d02c0e8510a010d,b5c60faf8429397f7f32decfb1569c59f487a9c6..89a048c2faec7f8a818d1a461ccd7fa67eca0fd9
  #define X86_FEATURE_IBPB              ( 7*32+26) /* Indirect Branch Prediction Barrier */
  #define X86_FEATURE_STIBP             ( 7*32+27) /* Single Thread Indirect Branch Predictors */
  #define X86_FEATURE_ZEN                       ( 7*32+28) /* "" CPU is AMD family 0x17 (Zen) */
 -#define X86_FEATURE_IBRS_ENHANCED     ( 7*32+29) /* Enhanced IBRS */
 +#define X86_FEATURE_L1TF_PTEINV               ( 7*32+29) /* "" L1TF workaround PTE inversion */
++#define X86_FEATURE_IBRS_ENHANCED     ( 7*32+30) /* Enhanced IBRS */
  
  /* Virtualization flags: Linux defined, word 8 */
  #define X86_FEATURE_TPR_SHADOW                ( 8*32+ 0) /* Intel TPR Shadow */
  
  #define X86_FEATURE_VMMCALL           ( 8*32+15) /* Prefer VMMCALL to VMCALL */
  #define X86_FEATURE_XENPV             ( 8*32+16) /* "" Xen paravirtual guest */
+ #define X86_FEATURE_EPT_AD            ( 8*32+17) /* Intel Extended Page Table access-dirty bit */
  
  /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */
  #define X86_FEATURE_FSGSBASE          ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/
  #define X86_FEATURE_PCONFIG           (18*32+18) /* Intel PCONFIG */
  #define X86_FEATURE_SPEC_CTRL         (18*32+26) /* "" Speculation Control (IBRS + IBPB) */
  #define X86_FEATURE_INTEL_STIBP               (18*32+27) /* "" Single Thread Indirect Branch Predictors */
 +#define X86_FEATURE_FLUSH_L1D         (18*32+28) /* Flush L1D cache */
  #define X86_FEATURE_ARCH_CAPABILITIES (18*32+29) /* IA32_ARCH_CAPABILITIES MSR (Intel) */
  #define X86_FEATURE_SPEC_CTRL_SSBD    (18*32+31) /* "" Speculative Store Bypass Disable */
  
  #define X86_BUG_SPECTRE_V1            X86_BUG(15) /* CPU is affected by Spectre variant 1 attack with conditional branches */
  #define X86_BUG_SPECTRE_V2            X86_BUG(16) /* CPU is affected by Spectre variant 2 attack with indirect branches */
  #define X86_BUG_SPEC_STORE_BYPASS     X86_BUG(17) /* CPU is affected by speculative store bypass attack */
 +#define X86_BUG_L1TF                  X86_BUG(18) /* CPU is affected by L1 Terminal Fault */
  
  #endif /* _ASM_X86_CPUFEATURES_H */