diff options
| -rw-r--r-- | kernel/kexec_handover.c | 28 | 
1 files changed, 24 insertions, 4 deletions
| diff --git a/kernel/kexec_handover.c b/kernel/kexec_handover.c index e49743ae52c5..65145972d6d6 100644 --- a/kernel/kexec_handover.c +++ b/kernel/kexec_handover.c @@ -144,14 +144,34 @@ static int __kho_preserve_order(struct kho_mem_track *track, unsigned long pfn,  				unsigned int order)  {  	struct kho_mem_phys_bits *bits; -	struct kho_mem_phys *physxa; +	struct kho_mem_phys *physxa, *new_physxa;  	const unsigned long pfn_high = pfn >> order;  	might_sleep(); -	physxa = xa_load_or_alloc(&track->orders, order, sizeof(*physxa)); -	if (IS_ERR(physxa)) -		return PTR_ERR(physxa); +	physxa = xa_load(&track->orders, order); +	if (!physxa) { +		int err; + +		new_physxa = kzalloc(sizeof(*physxa), GFP_KERNEL); +		if (!new_physxa) +			return -ENOMEM; + +		xa_init(&new_physxa->phys_bits); +		physxa = xa_cmpxchg(&track->orders, order, NULL, new_physxa, +				    GFP_KERNEL); + +		err = xa_err(physxa); +		if (err || physxa) { +			xa_destroy(&new_physxa->phys_bits); +			kfree(new_physxa); + +			if (err) +				return err; +		} else { +			physxa = new_physxa; +		} +	}  	bits = xa_load_or_alloc(&physxa->phys_bits, pfn_high / PRESERVE_BITS,  				sizeof(*bits)); | 
