Subject: linux-next: manual merge of the akpm-current tree with the tip tree

From: Stephen Rothwell <[email-masked]>
Date: Mon, 20 Aug 2018 14:32:22 +1000

Hi Andrew,

Today's linux-next merge of the akpm-current tree got conflicts in:

  fs/proc/kcore.c
  include/linux/kcore.h

between commit:

  6855dc41b246 ("x86: Add entry trampolines to kcore")

from the tip tree and commits:

  4eb27c275abf ("fs/proc/kcore.c: use __pa_symbol() for KCORE_TEXT list entries")
  ea551910d3f4 ("proc/kcore: clean up ELF header generation")
  537412a2958f ("proc/kcore: don't grab lock for kclist_add()")

from the akpm-current tree.

I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging.  You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.

-- 
Cheers,
Stephen Rothwell

diff --cc fs/proc/kcore.c
index 00282f134336,80464432dfe6..000000000000
--- a/fs/proc/kcore.c
+++ b/fs/proc/kcore.c
@@@ -448,53 -291,148 +291,151 @@@ static ssize_
  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
diff --cc include/linux/kcore.h
index bc088ef96358,c20f296438fb..000000000000
--- a/include/linux/kcore.h
+++ b/include/linux/kcore.h
@@@ -37,13 -35,7 +37,13 @@@ 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)