[PATCH 1/2] powerpc/fadump: use static allocation for reserved memory ranges

Mahesh J Salgaonkar mahesh at linux.ibm.com
Mon Apr 20 15:10:16 AEST 2020


On 2020-03-11 01:57:00 Wed, Hari Bathini wrote:
> At times, memory ranges have to be looked up during early boot, when
> kernel couldn't be initialized for dynamic memory allocation. In fact,
> reserved-ranges look up is needed during FADump memory reservation.
> Without accounting for reserved-ranges in reserving memory for FADump,
> MPIPL boot fails with memory corruption issues. So, extend memory
> ranges handling to support static allocation and populate reserved
> memory ranges during early boot.
> 
> Fixes: dda9dbfeeb7a ("powerpc/fadump: consider reserved ranges while releasing memory")
> Cc: stable at vger.kernel.org # v5.4+
> Signed-off-by: Hari Bathini <hbathini at linux.ibm.com>

Reviewed-by: Mahesh Salgaonkar <mahesh at linux.ibm.com>

Thanks,
-Mahesh.

> ---
>  arch/powerpc/include/asm/fadump-internal.h |    4 +
>  arch/powerpc/kernel/fadump.c               |   77 ++++++++++++++++------------
>  2 files changed, 48 insertions(+), 33 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/fadump-internal.h b/arch/powerpc/include/asm/fadump-internal.h
> index c814a2b..8d61c8f 100644
> --- a/arch/powerpc/include/asm/fadump-internal.h
> +++ b/arch/powerpc/include/asm/fadump-internal.h
> @@ -64,12 +64,14 @@ struct fadump_memory_range {
>  };
>  
>  /* fadump memory ranges info */
> +#define RNG_NAME_SZ			16
>  struct fadump_mrange_info {
> -	char				name[16];
> +	char				name[RNG_NAME_SZ];
>  	struct fadump_memory_range	*mem_ranges;
>  	u32				mem_ranges_sz;
>  	u32				mem_range_cnt;
>  	u32				max_mem_ranges;
> +	bool				is_static;
>  };
>  
>  /* Platform specific callback functions */
> diff --git a/arch/powerpc/kernel/fadump.c b/arch/powerpc/kernel/fadump.c
> index ff0114a..7fcf4a8f 100644
> --- a/arch/powerpc/kernel/fadump.c
> +++ b/arch/powerpc/kernel/fadump.c
> @@ -38,8 +38,17 @@ static void __init fadump_reserve_crash_area(u64 base);
>  
>  #ifndef CONFIG_PRESERVE_FA_DUMP
>  static DEFINE_MUTEX(fadump_mutex);
> -struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0 };
> -struct fadump_mrange_info reserved_mrange_info = { "reserved", NULL, 0, 0, 0 };
> +struct fadump_mrange_info crash_mrange_info = { "crash", NULL, 0, 0, 0, false };
> +
> +#define RESERVED_RNGS_SZ	16384 /* 16K - 128 entries */
> +#define RESERVED_RNGS_CNT	(RESERVED_RNGS_SZ / \
> +				 sizeof(struct fadump_memory_range))
> +static struct fadump_memory_range rngs[RESERVED_RNGS_CNT];
> +struct fadump_mrange_info reserved_mrange_info = { "reserved", rngs,
> +						   RESERVED_RNGS_SZ, 0,
> +						   RESERVED_RNGS_CNT, true };
> +
> +static void __init early_init_dt_scan_reserved_ranges(unsigned long node);
>  
>  #ifdef CONFIG_CMA
>  static struct cma *fadump_cma;
> @@ -108,6 +117,11 @@ static int __init fadump_cma_init(void) { return 1; }
>  int __init early_init_dt_scan_fw_dump(unsigned long node, const char *uname,
>  				      int depth, void *data)
>  {
> +	if (depth == 0) {
> +		early_init_dt_scan_reserved_ranges(node);
> +		return 0;
> +	}
> +
>  	if (depth != 1)
>  		return 0;
>  
> @@ -726,10 +740,14 @@ void fadump_free_cpu_notes_buf(void)
>  
>  static void fadump_free_mem_ranges(struct fadump_mrange_info *mrange_info)
>  {
> +	if (mrange_info->is_static) {
> +		mrange_info->mem_range_cnt = 0;
> +		return;
> +	}
> +
>  	kfree(mrange_info->mem_ranges);
> -	mrange_info->mem_ranges = NULL;
> -	mrange_info->mem_ranges_sz = 0;
> -	mrange_info->max_mem_ranges = 0;
> +	memset((void *)((u64)mrange_info + RNG_NAME_SZ), 0,
> +	       (sizeof(struct fadump_mrange_info) - RNG_NAME_SZ));
>  }
>  
>  /*
> @@ -786,6 +804,12 @@ static inline int fadump_add_mem_range(struct fadump_mrange_info *mrange_info,
>  		if (mrange_info->mem_range_cnt == mrange_info->max_mem_ranges) {
>  			int ret;
>  
> +			if (mrange_info->is_static) {
> +				pr_err("Reached array size limit for %s memory ranges\n",
> +				       mrange_info->name);
> +				return -ENOSPC;
> +			}
> +
>  			ret = fadump_alloc_mem_ranges(mrange_info);
>  			if (ret)
>  				return ret;
> @@ -1202,20 +1226,19 @@ static void sort_and_merge_mem_ranges(struct fadump_mrange_info *mrange_info)
>   * Scan reserved-ranges to consider them while reserving/releasing
>   * memory for FADump.
>   */
> -static inline int fadump_scan_reserved_mem_ranges(void)
> +static void __init early_init_dt_scan_reserved_ranges(unsigned long node)
>  {
> -	struct device_node *root;
>  	const __be32 *prop;
>  	int len, ret = -1;
>  	unsigned long i;
>  
> -	root = of_find_node_by_path("/");
> -	if (!root)
> -		return ret;
> +	/* reserved-ranges already scanned */
> +	if (reserved_mrange_info.mem_range_cnt != 0)
> +		return;
>  
> -	prop = of_get_property(root, "reserved-ranges", &len);
> +	prop = of_get_flat_dt_prop(node, "reserved-ranges", &len);
>  	if (!prop)
> -		return ret;
> +		return;
>  
>  	/*
>  	 * Each reserved range is an (address,size) pair, 2 cells each,
> @@ -1237,7 +1260,8 @@ static inline int fadump_scan_reserved_mem_ranges(void)
>  		}
>  	}
>  
> -	return ret;
> +	/* Compact reserved ranges */
> +	sort_and_merge_mem_ranges(&reserved_mrange_info);
>  }
>  
>  /*
> @@ -1251,32 +1275,21 @@ static void fadump_release_memory(u64 begin, u64 end)
>  	u64 ra_start, ra_end, tstart;
>  	int i, ret;
>  
> -	fadump_scan_reserved_mem_ranges();
> -
>  	ra_start = fw_dump.reserve_dump_area_start;
>  	ra_end = ra_start + fw_dump.reserve_dump_area_size;
>  
>  	/*
> -	 * Add reserved dump area to reserved ranges list
> -	 * and exclude all these ranges while releasing memory.
> +	 * If reserved ranges array limit is hit, overwrite the last reserved
> +	 * memory range with reserved dump area to ensure it is excluded from
> +	 * the memory being released (reused for next FADump registration).
>  	 */
> -	ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
> -	if (ret != 0) {
> -		/*
> -		 * Not enough memory to setup reserved ranges but the system is
> -		 * running shortage of memory. So, release all the memory except
> -		 * Reserved dump area (reused for next fadump registration).
> -		 */
> -		if (begin < ra_end && end > ra_start) {
> -			if (begin < ra_start)
> -				fadump_release_reserved_area(begin, ra_start);
> -			if (end > ra_end)
> -				fadump_release_reserved_area(ra_end, end);
> -		} else
> -			fadump_release_reserved_area(begin, end);
> +	if (reserved_mrange_info.mem_range_cnt ==
> +	    reserved_mrange_info.max_mem_ranges)
> +		reserved_mrange_info.mem_range_cnt--;
>  
> +	ret = fadump_add_mem_range(&reserved_mrange_info, ra_start, ra_end);
> +	if (ret != 0)
>  		return;
> -	}
>  
>  	/* Get the reserved ranges list in order first. */
>  	sort_and_merge_mem_ranges(&reserved_mrange_info);
> 

-- 
Mahesh J Salgaonkar



More information about the Linuxppc-dev mailing list