Commit 16c6006a authored by Zhen Lei's avatar Zhen Lei Committed by Andrew Morton
Browse files

kexec: enable kexec_crash_size to support two crash kernel regions

The crashk_low_res should be considered by /sys/kernel/kexec_crash_size
to support two crash kernel regions shrinking if existing.

While doing it, crashk_low_res will only be shrunk when the entire
crashk_res is empty; and if the crashk_res is empty and crahk_low_res
is not, change crashk_low_res to be crashk_res.

[bhe@redhat.com: redo changelog]
Link: https://lkml.kernel.org/r/20230527123439.772-7-thunder.leizhen@huawei.com


Signed-off-by: default avatarZhen Lei <thunder.leizhen@huawei.com>
Acked-by: default avatarBaoquan He <bhe@redhat.com>
Cc: Cong Wang <amwang@redhat.com>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Cc: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 5b7bfb32
Loading
Loading
Loading
Loading
+38 −5
Original line number Diff line number Diff line
@@ -1091,6 +1091,11 @@ __bpf_kfunc void crash_kexec(struct pt_regs *regs)
	}
}

static inline resource_size_t crash_resource_size(const struct resource *res)
{
	return !res->end ? 0 : resource_size(res);
}

ssize_t crash_get_memory_size(void)
{
	ssize_t size = 0;
@@ -1098,8 +1103,8 @@ ssize_t crash_get_memory_size(void)
	if (!kexec_trylock())
		return -EBUSY;

	if (crashk_res.end != crashk_res.start)
		size = resource_size(&crashk_res);
	size += crash_resource_size(&crashk_res);
	size += crash_resource_size(&crashk_low_res);

	kexec_unlock();
	return size;
@@ -1136,7 +1141,7 @@ static int __crash_shrink_memory(struct resource *old_res,
int crash_shrink_memory(unsigned long new_size)
{
	int ret = 0;
	unsigned long old_size;
	unsigned long old_size, low_size;

	if (!kexec_trylock())
		return -EBUSY;
@@ -1145,14 +1150,42 @@ int crash_shrink_memory(unsigned long new_size)
		ret = -ENOENT;
		goto unlock;
	}
	old_size = !crashk_res.end ? 0 : resource_size(&crashk_res);

	low_size = crash_resource_size(&crashk_low_res);
	old_size = crash_resource_size(&crashk_res) + low_size;
	new_size = roundup(new_size, KEXEC_CRASH_MEM_ALIGN);
	if (new_size >= old_size) {
		ret = (new_size == old_size) ? 0 : -EINVAL;
		goto unlock;
	}

	ret = __crash_shrink_memory(&crashk_res, new_size);
	/*
	 * (low_size > new_size) implies that low_size is greater than zero.
	 * This also means that if low_size is zero, the else branch is taken.
	 *
	 * If low_size is greater than 0, (low_size > new_size) indicates that
	 * crashk_low_res also needs to be shrunken. Otherwise, only crashk_res
	 * needs to be shrunken.
	 */
	if (low_size > new_size) {
		ret = __crash_shrink_memory(&crashk_res, 0);
		if (ret)
			goto unlock;

		ret = __crash_shrink_memory(&crashk_low_res, new_size);
	} else {
		ret = __crash_shrink_memory(&crashk_res, new_size - low_size);
	}

	/* Swap crashk_res and crashk_low_res if needed */
	if (!crashk_res.end && crashk_low_res.end) {
		crashk_res.start = crashk_low_res.start;
		crashk_res.end   = crashk_low_res.end;
		release_resource(&crashk_low_res);
		crashk_low_res.start = 0;
		crashk_low_res.end   = 0;
		insert_resource(&iomem_resource, &crashk_res);
	}

unlock:
	kexec_unlock();