Skip to contentSkip to conversation

binfmt_elf.c: core file shrinking

PATCH In review Thanh-Lam NGUYEN 2 participants 5 messages Oct 11, 2011 – Oct 18, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 binfmt_elf.c: core file shrinking

The vma_shrink function looks for the 1st allocated and the last allocated page. Only this part is dumped to the disk (the virual start address and the size are dupdated to reflect the new dumped information).

---
 linux/fs/binfmt_elf.c |   54
++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 55 insertions(+), 4 deletions(-)
fs/binfmt_elf.c +42 -0
@@ -1085,6 +1085,48 @@
  * Jeremy Fitzhardinge <[email protected]>
  */
 
+/*
+ * Search for 1st and last allocated page from vma_start to vma_end.
+ * Update vma_start and vma_end to reflect the result.
+ */
+void vma_shrink(struct vm_area_struct *vma, unsigned long *vma_start,
+		unsigned long *vma_end)
+{
+	int allocated;
+	unsigned long start, addr, end;
+
+	allocated = 0;
+	start = end = *vma_start;
+	for (addr = *vma_start; _addr < *vma_end; addr += PAGE_SIZE) {
+		struct page *page;
+		if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+				   &page, NULL) <= 0) {
+			/* NO PAGE */
+			if (!allocated)
+				start = addr;
+		} else {
+			if (page == ZERO_PAGE(0)) {
+				/* ZERO PAGE */
+				if (!allocated)
+					start = addr;
+			} else {
+				/* ALLOCATED PAGE */
+				if (!allocated)
+					start = addr;
+				end = addr;
+				allocated = 1;
+			}
+			page_cache_release(page);
+		}
+	}
+	if (end < start)
+		end = start;
+	if (allocated)
+		end += PAGE_SIZE;
+	*vma_start = start;
+	*vma_end = end;
+}
+
 /*
  * Decide what to dump of a segment, part, all or none.
  */
@@ -1980,13 +2022,19 @@ static int elf_core_dump(struct coredump_params

*cprm)
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
+ unsigned long start = vma->vm_start;
+ unsigned long end = vma->vm_end;
phdr.p_type = PT_LOAD;
phdr.p_offset = offset;
- phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags);
- phdr.p_memsz = vma->vm_end - vma->vm_start;
+ if (phdr.p_filesz) {
+ vma_shrink(vma, &start, &end);
+ phdr.p_filesz = end-start;
+ }
+ phdr.p_vaddr = start;
+ phdr.p_memsz = vma->vm_end - phdr.p_vaddr;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; if (vma->vm_flags & VM_WRITE)
@@ -2018,11 +2066,15 @@ static int elf_core_dump(struct coredump_params *cprm)
for (vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
unsigned long addr;
+ unsigned long start;
unsigned long end;
- end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
+ start = vma->vm_start;
+ end = start + vma_dump_size(vma, cprm->mm_flags);
+ if (start < end)
+ vma_shrink(vma, &start, &end);
- for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
+ for (addr = start; addr < end; addr += PAGE_SIZE) {
struct page *page;
int stop;

---
=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~=
Thanh lam NGUYEN
Prestataire externe ALTEN | ALTEN Subcontractor
pour ALCATEL-LUCENT | in ALCATEL-LUCENT

email: [email protected]

#1 lore raw

Sorry for upping the patch,
as it is my first contribution I would like to know if there is any problem with it.

Best regard
Thanh lam NGUYEN

Quoted 116 lines · Thanh-Lam NGUYEN

The vma_shrink function looks for the 1st allocated and the last allocated page. Only this part is dumped to the disk (the virual start address and the size are dupdated to reflect the new dumped information).

---
 linux/fs/binfmt_elf.c |   54
++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 55 insertions(+), 4 deletions(-)
fs/binfmt_elf.c +56 -3
@@ -1085,6 +1085,48 @@
  * Jeremy Fitzhardinge <[email protected]>
  */
 
+/*
+ * Search for 1st and last allocated page from vma_start to vma_end.
+ * Update vma_start and vma_end to reflect the result.
+ */
+void vma_shrink(struct vm_area_struct *vma, unsigned long *vma_start,
+		unsigned long *vma_end)
+{
+	int allocated;
+	unsigned long start, addr, end;
+
+	allocated = 0;
+	start = end = *vma_start;
+	for (addr = *vma_start; _addr < *vma_end; addr += PAGE_SIZE) {
+		struct page *page;
+		if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+				   &page, NULL) <= 0) {
+			/* NO PAGE */
+			if (!allocated)
+				start = addr;
+		} else {
+			if (page == ZERO_PAGE(0)) {
+				/* ZERO PAGE */
+				if (!allocated)
+					start = addr;
+			} else {
+				/* ALLOCATED PAGE */
+				if (!allocated)
+					start = addr;
+				end = addr;
+				allocated = 1;
+			}
+			page_cache_release(page);
+		}
+	}
+	if (end < start)
+		end = start;
+	if (allocated)
+		end += PAGE_SIZE;
+	*vma_start = start;
+	*vma_end = end;
+}
+
 /*
  * Decide what to dump of a segment, part, all or none.
  */
@@ -1980,13 +2022,19 @@ static int elf_core_dump(struct coredump_params
 *cprm)
 	for (vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
 		struct elf_phdr phdr;
+		unsigned long start = vma->vm_start;
+		unsigned long end = vma->vm_end;
  		phdr.p_type = PT_LOAD;
 		phdr.p_offset = offset;
-		phdr.p_vaddr = vma->vm_start;
 		phdr.p_paddr = 0;
 		phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags);
-		phdr.p_memsz = vma->vm_end - vma->vm_start;
+		if (phdr.p_filesz) {
+			vma_shrink(vma, &start, &end);
+			phdr.p_filesz = end-start;
+		}
+		phdr.p_vaddr = start;
+		phdr.p_memsz = vma->vm_end - phdr.p_vaddr;
 		offset += phdr.p_filesz;
 		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
 		if (vma->vm_flags & VM_WRITE)
@@ -2018,11 +2066,15 @@ static int elf_core_dump(struct coredump_params
 *cprm)
 	for (vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
 		unsigned long addr;
+		unsigned long start;
 		unsigned long end;
 -		end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
+		start = vma->vm_start;
+		end = start + vma_dump_size(vma, cprm->mm_flags);
+		if (start < end)
+			vma_shrink(vma, &start, &end);
 -		for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
+		for (addr = start; addr < end; addr += PAGE_SIZE) {
 			struct page *page;
 			int stop;
 
---

=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~=
Thanh lam NGUYEN
Prestataire externe ALTEN | ALTEN Subcontractor
pour ALCATEL-LUCENT | in ALCATEL-LUCENT

email: [email protected]

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

Signature · 9 lines
=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~=
Thanh lam NGUYEN
Prestataire externe ALTEN        | ALTEN Subcontractor
pour ALCATEL-LUCENT              | in ALCATEL-LUCENT

Tel: +333906 77095

Equipe/Team: SWINT
email: [email protected]
#2 lore raw
Quoted 4 lines · Thanh-Lam NGUYEN

Sorry for upping the patch,
as it is my first contribution I would like to know if there is any problem with it.

Quoted 15 lines

Best regard
Thanh lam NGUYEN

Quoted 10 lines · Thanh-Lam NGUYEN

The vma_shrink function looks for the 1st allocated and the last allocated page. Only this part is dumped to the disk (the virual start address and the size are dupdated to reflect the new dumped information).

---
 linux/fs/binfmt_elf.c |   54
++++++++++++++++++++++++++++++++++++++++++++++----

corrupted message?

Quoted 8 lines
Quoted 8 lines
 1 file changed, 55 insertions(+), 4 deletions(-)
fs/binfmt_elf.c +0 -0
@@ -1085,6 +1085,48 @@
   * Jeremy Fitzhardinge <[email protected]>
   */
 
Quoted 13 lines

fs/binfmt_elf.c line 1100

Quoted 13 lines
fs/binfmt_elf.c +13 -0
+/*
+ * Search for 1st and last allocated page from vma_start to vma_end.
+ * Update vma_start and vma_end to reflect the result.
+ */
+void vma_shrink(struct vm_area_struct *vma, unsigned long *vma_start,
+             unsigned long *vma_end)
+{
+     int allocated;
+     unsigned long start, addr, end;
+
+     allocated = 0;
+     start = end = *vma_start;
+     for (addr = *vma_start; _addr < *vma_end; addr += PAGE_SIZE) {

-----^ where is _addr from?

Quoted 4 lines
Quoted 4 lines
fs/binfmt_elf.c +4 -0
+             struct page *page;
+             if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+                                &page, NULL) <= 0) {
+                     /* NO PAGE */
#3 lore raw
Quoted 32 lines · Hillf Danton
Quoted 4 lines · Thanh-Lam NGUYEN

Sorry for upping the patch,
as it is my first contribution I would like to know if there is any problem with it.

Quoted 15 lines

Best regard
Thanh lam NGUYEN

Quoted 10 lines · Thanh-Lam NGUYEN

The vma_shrink function looks for the 1st allocated and the last allocated page. Only this part is dumped to the disk (the virual start address and the size are dupdated to reflect the new dumped information).

---
 linux/fs/binfmt_elf.c |   54

++++++++++++++++++++++++++++++++++++++++++++++----

corrupted message?

Quoted 8 lines
Quoted 8 lines
 1 file changed, 55 insertions(+), 4 deletions(-)
fs/binfmt_elf.c +0 -0
@@ -1085,6 +1085,48 @@
  * Jeremy Fitzhardinge <[email protected]>
  */
 
Quoted 16 lines
Quoted 5 lines
Quoted 5 lines
fs/binfmt_elf.c +5 -0
+/*
+ * Search for 1st and last allocated page from vma_start to vma_end.
+ * Update vma_start and vma_end to reflect the result.
+ */
+void vma_shrink(struct vm_area_struct *vma, unsigned long *vma_start,
Quoted 8 lines

fs/binfmt_elf.c line 1100

Quoted 8 lines
fs/binfmt_elf.c +8 -0
+             unsigned long *vma_end)
+{
+     int allocated;
+     unsigned long start, addr, end;
+
+     allocated = 0;
+     start = end = *vma_start;
+     for (addr = *vma_start; _addr < *vma_end; addr += PAGE_SIZE) {

-----^ where is _addr from?

My bad, it's addr and not _addr.

Quoted 9 lines
Quoted 4 lines

fs/binfmt_elf.c line 1104

Quoted 4 lines
fs/binfmt_elf.c +4 -0
+             struct page *page;
+             if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+                                &page, NULL) <= 0) {
+                     /* NO PAGE */

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 9 lines
=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~=
Thanh lam NGUYEN
Prestataire externe ALTEN        | ALTEN Subcontractor
pour ALCATEL-LUCENT              | in ALCATEL-LUCENT

Tel: +333906 77095

Equipe/Team: SWINT
email: [email protected]
#4 lore raw
In reply to Thanh-Lam NGUYEN

Here is the patch with the fix on the variable name.
To be sure that the mailer does not screw the patch, it is attached and not inlined.

Signature · 7 lines
=~=~=~=~=~=~=~=~=~=~=~=~==~=~=~=~=~=~=~=~=~=~=~=~=~=~=
Thanh lam NGUYEN
Prestataire externe ALTEN        | ALTEN Subcontractor
pour ALCATEL-LUCENT              | in ALCATEL-LUCENT

Equipe/Team: SWINT
email: [email protected]

The vma_shrink function looks for the 1st allocated and the last allocated page. Only this part is dumped to the disk (the virual start address and the size are updated to reflect the new dumped information).

---
 linux/fs/binfmt_elf.c |   54 ++++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 55 insertions(+), 4 deletions(-)
fs/binfmt_elf.c +56 -4
@@ -1085,6 +1085,48 @@
  * Jeremy Fitzhardinge <[email protected]>
  */
 
+/*
+ * Search for 1st and last allocated page from vma_start to vma_end.
+ * Update vma_start and vma_end to reflect the result.
+ */
+void vma_shrink(struct vm_area_struct *vma, unsigned long *vma_start,
+		unsigned long *vma_end)
+{
+	int allocated;
+	unsigned long start, addr, end;
+
+	allocated = 0;
+	start = end = *vma_start;
+	for (addr = *vma_start; addr < *vma_end; addr += PAGE_SIZE) {
+		struct page *page;
+		if (get_user_pages(current, current->mm, addr, 1, 0, 1,
+				   &page, NULL) <= 0) {
+			/* NO PAGE */
+			if (!allocated)
+				start = addr;
+		} else {
+			if (page == ZERO_PAGE(0)) {
+				/* ZERO PAGE */
+				if (!allocated)
+					start = addr;
+			} else {
+				/* ALLOCATED PAGE */
+				if (!allocated)
+					start = addr;
+				end = addr;
+				allocated = 1;
+			}
+			page_cache_release(page);
+		}
+	}
+	if (end < start)
+		end = start;
+	if (allocated)
+		end += PAGE_SIZE;
+	*vma_start = start;
+	*vma_end = end;
+}
+
 /*
  * Decide what to dump of a segment, part, all or none.
  */
@@ -1980,13 +2022,19 @@ static int elf_core_dump(struct coredump_params *cprm)
 	for (vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
 		struct elf_phdr phdr;
+		unsigned long start = vma->vm_start;
+		unsigned long end = vma->vm_end;
 
 		phdr.p_type = PT_LOAD;
 		phdr.p_offset = offset;
-		phdr.p_vaddr = vma->vm_start;
 		phdr.p_paddr = 0;
 		phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags);
-		phdr.p_memsz = vma->vm_end - vma->vm_start;
+		if (phdr.p_filesz) {
+			vma_shrink(vma, &start, &end);
+			phdr.p_filesz = end-start;
+		}
+		phdr.p_vaddr = start;
+		phdr.p_memsz = vma->vm_end - phdr.p_vaddr;
 		offset += phdr.p_filesz;
 		phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
 		if (vma->vm_flags & VM_WRITE)
@@ -2018,11 +2066,15 @@ static int elf_core_dump(struct coredump_params *cprm)
 	for (vma = first_vma(current, gate_vma); vma != NULL;
 			vma = next_vma(vma, gate_vma)) {
 		unsigned long addr;
+		unsigned long start;
 		unsigned long end;
 
-		end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
+		start = vma->vm_start;
+		end = start + vma_dump_size(vma, cprm->mm_flags);
+		if (start < end)
+			vma_shrink(vma, &start, &end);
 
-		for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
+		for (addr = start; addr < end; addr += PAGE_SIZE) {
 			struct page *page;
 			int stop;