Commit d0f1088b authored by Al Viro's avatar Al Viro
Browse files

coredump: don't bother with do_truncate()



have dump_skip() just remember how much needs to be skipped,
leave actual seeks/writing zeroes to the next dump_emit()
or the end of coredump output, whichever comes first.
And instead of playing with do_truncate() in the end, just
write one NUL at the end of the last gap (if any).

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent a38fd874
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -149,8 +149,7 @@ static int spufs_arch_write_note(struct spu_context *ctx, int i,
			return -EIO;
	}

	if (!dump_skip(cprm, roundup(cprm->pos - ret + sz, 4) - cprm->pos))
		return -EIO;
	dump_skip_to(cprm, roundup(cprm->pos - ret + sz, 4));
	return 0;
}

+1 −3
Original line number Diff line number Diff line
@@ -2267,8 +2267,7 @@ static int elf_core_dump(struct coredump_params *cprm)
		goto end_coredump;

	/* Align to page */
	if (!dump_skip(cprm, dataoff - cprm->pos))
		goto end_coredump;
	dump_skip_to(cprm, dataoff);

	for (i = 0; i < vma_count; i++) {
		struct core_vma_metadata *meta = vma_meta + i;
@@ -2276,7 +2275,6 @@ static int elf_core_dump(struct coredump_params *cprm)
		if (!dump_user_range(cprm, meta->start, meta->dump_size))
			goto end_coredump;
	}
	dump_truncate(cprm);

	if (!elf_core_write_extra_data(cprm))
		goto end_coredump;
+1 −2
Original line number Diff line number Diff line
@@ -1631,8 +1631,7 @@ static int elf_fdpic_core_dump(struct coredump_params *cprm)
				goto end_coredump;
	}

	if (!dump_skip(cprm, dataoff - cprm->pos))
		goto end_coredump;
	dump_skip_to(cprm, dataoff);

	if (!elf_fdpic_dump_segments(cprm, vma_meta, vma_count))
		goto end_coredump;
+43 −29
Original line number Diff line number Diff line
@@ -809,6 +809,16 @@ void do_coredump(const kernel_siginfo_t *siginfo)
		}
		file_start_write(cprm.file);
		core_dumped = binfmt->core_dump(&cprm);
		/*
		 * Ensures that file size is big enough to contain the current
		 * file postion. This prevents gdb from complaining about
		 * a truncated file if the last "write" to the file was
		 * dump_skip.
		 */
		if (cprm.to_skip) {
			cprm.to_skip--;
			dump_emit(&cprm, "", 1);
		}
		file_end_write(cprm.file);
	}
	if (ispipe && core_pipe_limit)
@@ -835,7 +845,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
 * do on a core-file: use only these functions to write out all the
 * necessary info.
 */
int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
static int __dump_emit(struct coredump_params *cprm, const void *addr, int nr)
{
	struct file *file = cprm->file;
	loff_t pos = file->f_pos;
@@ -855,9 +865,8 @@ int dump_emit(struct coredump_params *cprm, const void *addr, int nr)

	return 1;
}
EXPORT_SYMBOL(dump_emit);

int dump_skip(struct coredump_params *cprm, size_t nr)
static int __dump_skip(struct coredump_params *cprm, size_t nr)
{
	static char zeroes[PAGE_SIZE];
	struct file *file = cprm->file;
@@ -869,12 +878,34 @@ int dump_skip(struct coredump_params *cprm, size_t nr)
		return 1;
	} else {
		while (nr > PAGE_SIZE) {
			if (!dump_emit(cprm, zeroes, PAGE_SIZE))
			if (!__dump_emit(cprm, zeroes, PAGE_SIZE))
				return 0;
			nr -= PAGE_SIZE;
		}
		return dump_emit(cprm, zeroes, nr);
		return __dump_emit(cprm, zeroes, nr);
	}
}

int dump_emit(struct coredump_params *cprm, const void *addr, int nr)
{
	if (cprm->to_skip) {
		if (!__dump_skip(cprm, cprm->to_skip))
			return 0;
		cprm->to_skip = 0;
	}
	return __dump_emit(cprm, addr, nr);
}
EXPORT_SYMBOL(dump_emit);

void dump_skip_to(struct coredump_params *cprm, unsigned long pos)
{
	cprm->to_skip = pos - cprm->pos;
}
EXPORT_SYMBOL(dump_skip_to);

void dump_skip(struct coredump_params *cprm, size_t nr)
{
	cprm->to_skip += nr;
}
EXPORT_SYMBOL(dump_skip);

@@ -902,11 +933,11 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start,
			stop = !dump_emit(cprm, kaddr, PAGE_SIZE);
			kunmap_local(kaddr);
			put_page(page);
		} else {
			stop = !dump_skip(cprm, PAGE_SIZE);
		}
			if (stop)
				return 0;
		} else {
			dump_skip(cprm, PAGE_SIZE);
		}
	}
	return 1;
}
@@ -914,32 +945,15 @@ int dump_user_range(struct coredump_params *cprm, unsigned long start,

int dump_align(struct coredump_params *cprm, int align)
{
	unsigned mod = cprm->pos & (align - 1);
	unsigned mod = (cprm->pos + cprm->to_skip) & (align - 1);
	if (align & (align - 1))
		return 0;
	return mod ? dump_skip(cprm, align - mod) : 1;
	if (mod)
		cprm->to_skip += align - mod;
	return 1;
}
EXPORT_SYMBOL(dump_align);

/*
 * Ensures that file size is big enough to contain the current file
 * postion. This prevents gdb from complaining about a truncated file
 * if the last "write" to the file was dump_skip.
 */
void dump_truncate(struct coredump_params *cprm)
{
	struct file *file = cprm->file;
	loff_t offset;

	if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
		offset = file->f_op->llseek(file, 0, SEEK_CUR);
		if (i_size_read(file->f_mapping->host) < offset)
			do_truncate(file_mnt_user_ns(file), file->f_path.dentry,
				    offset, 0, file);
	}
}
EXPORT_SYMBOL(dump_truncate);

/*
 * The purpose of always_dump_vma() is to make sure that special kernel mappings
 * that are useful for post-mortem analysis are included in every core dump.
+1 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ struct coredump_params {
	unsigned long mm_flags;
	loff_t written;
	loff_t pos;
	loff_t to_skip;
};

/*
Loading