diff options
Diffstat (limited to 'fs/coredump.c')
| -rw-r--r-- | fs/coredump.c | 81 | 
1 files changed, 50 insertions, 31 deletions
diff --git a/fs/coredump.c b/fs/coredump.c index 9bdeca12ae0..a93f7e6ea4c 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -40,7 +40,6 @@  #include <trace/events/task.h>  #include "internal.h" -#include "coredump.h"  #include <trace/events/sched.h> @@ -74,10 +73,15 @@ static int expand_corename(struct core_name *cn, int size)  static int cn_vprintf(struct core_name *cn, const char *fmt, va_list arg)  {  	int free, need; +	va_list arg_copy;  again:  	free = cn->size - cn->used; -	need = vsnprintf(cn->corename + cn->used, free, fmt, arg); + +	va_copy(arg_copy, arg); +	need = vsnprintf(cn->corename + cn->used, free, fmt, arg_copy); +	va_end(arg_copy); +  	if (need < free) {  		cn->used += need;  		return 0; @@ -302,7 +306,7 @@ static int zap_threads(struct task_struct *tsk, struct mm_struct *mm,  	if (unlikely(nr < 0))  		return nr; -	tsk->flags = PF_DUMPCORE; +	tsk->flags |= PF_DUMPCORE;  	if (atomic_read(&mm->mm_users) == nr + 1)  		goto done;  	/* @@ -485,7 +489,7 @@ static int umh_pipe_setup(struct subprocess_info *info, struct cred *new)  	return err;  } -void do_coredump(siginfo_t *siginfo) +void do_coredump(const siginfo_t *siginfo)  {  	struct core_state core_state;  	struct core_name cn; @@ -645,7 +649,7 @@ void do_coredump(siginfo_t *siginfo)  		 */  		if (!uid_eq(inode->i_uid, current_fsuid()))  			goto close_fail; -		if (!cprm.file->f_op || !cprm.file->f_op->write) +		if (!cprm.file->f_op->write)  			goto close_fail;  		if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file))  			goto close_fail; @@ -685,40 +689,55 @@ fail:   * do on a core-file: use only these functions to write out all the   * necessary info.   */ -int dump_write(struct file *file, const void *addr, int nr) +int dump_emit(struct coredump_params *cprm, const void *addr, int nr)  { -	return !dump_interrupted() && -		access_ok(VERIFY_READ, addr, nr) && -		file->f_op->write(file, addr, nr, &file->f_pos) == nr; +	struct file *file = cprm->file; +	loff_t pos = file->f_pos; +	ssize_t n; +	if (cprm->written + nr > cprm->limit) +		return 0; +	while (nr) { +		if (dump_interrupted()) +			return 0; +		n = __kernel_write(file, addr, nr, &pos); +		if (n <= 0) +			return 0; +		file->f_pos = pos; +		cprm->written += n; +		nr -= n; +	} +	return 1;  } -EXPORT_SYMBOL(dump_write); +EXPORT_SYMBOL(dump_emit); -int dump_seek(struct file *file, loff_t off) +int dump_skip(struct coredump_params *cprm, size_t nr)  { -	int ret = 1; - +	static char zeroes[PAGE_SIZE]; +	struct file *file = cprm->file;  	if (file->f_op->llseek && file->f_op->llseek != no_llseek) { +		if (cprm->written + nr > cprm->limit) +			return 0;  		if (dump_interrupted() || -		    file->f_op->llseek(file, off, SEEK_CUR) < 0) +		    file->f_op->llseek(file, nr, SEEK_CUR) < 0)  			return 0; +		cprm->written += nr; +		return 1;  	} else { -		char *buf = (char *)get_zeroed_page(GFP_KERNEL); - -		if (!buf) -			return 0; -		while (off > 0) { -			unsigned long n = off; - -			if (n > PAGE_SIZE) -				n = PAGE_SIZE; -			if (!dump_write(file, buf, n)) { -				ret = 0; -				break; -			} -			off -= n; +		while (nr > PAGE_SIZE) { +			if (!dump_emit(cprm, zeroes, PAGE_SIZE)) +				return 0; +			nr -= PAGE_SIZE;  		} -		free_page((unsigned long)buf); +		return dump_emit(cprm, zeroes, nr);  	} -	return ret;  } -EXPORT_SYMBOL(dump_seek); +EXPORT_SYMBOL(dump_skip); + +int dump_align(struct coredump_params *cprm, int align) +{ +	unsigned mod = cprm->written & (align - 1); +	if (align & (align - 1)) +		return 0; +	return mod ? dump_skip(cprm, align - mod) : 1; +} +EXPORT_SYMBOL(dump_align);  | 
