diff options
Diffstat (limited to 'fs/proc/vmcore.c')
| -rw-r--r-- | fs/proc/vmcore.c | 52 | 
1 files changed, 49 insertions, 3 deletions
| diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c index 74802bc5ded..cd99bf55765 100644 --- a/fs/proc/vmcore.c +++ b/fs/proc/vmcore.c @@ -35,6 +35,46 @@ static u64 vmcore_size;  static struct proc_dir_entry *proc_vmcore = NULL; +/* + * Returns > 0 for RAM pages, 0 for non-RAM pages, < 0 on error + * The called function has to take care of module refcounting. + */ +static int (*oldmem_pfn_is_ram)(unsigned long pfn); + +int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn)) +{ +	if (oldmem_pfn_is_ram) +		return -EBUSY; +	oldmem_pfn_is_ram = fn; +	return 0; +} +EXPORT_SYMBOL_GPL(register_oldmem_pfn_is_ram); + +void unregister_oldmem_pfn_is_ram(void) +{ +	oldmem_pfn_is_ram = NULL; +	wmb(); +} +EXPORT_SYMBOL_GPL(unregister_oldmem_pfn_is_ram); + +static int pfn_is_ram(unsigned long pfn) +{ +	int (*fn)(unsigned long pfn); +	/* pfn is ram unless fn() checks pagetype */ +	int ret = 1; + +	/* +	 * Ask hypervisor if the pfn is really ram. +	 * A ballooned page contains no data and reading from such a page +	 * will cause high load in the hypervisor. +	 */ +	fn = oldmem_pfn_is_ram; +	if (fn) +		ret = fn(pfn); + +	return ret; +} +  /* Reads a page from the oldmem device from given offset. */  static ssize_t read_from_oldmem(char *buf, size_t count,  				u64 *ppos, int userbuf) @@ -55,9 +95,15 @@ static ssize_t read_from_oldmem(char *buf, size_t count,  		else  			nr_bytes = count; -		tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf); -		if (tmp < 0) -			return tmp; +		/* If pfn is not ram, return zeros for sparse dump files */ +		if (pfn_is_ram(pfn) == 0) +			memset(buf, 0, nr_bytes); +		else { +			tmp = copy_oldmem_page(pfn, buf, nr_bytes, +						offset, userbuf); +			if (tmp < 0) +				return tmp; +		}  		*ppos += nr_bytes;  		count -= nr_bytes;  		buf += nr_bytes; | 
