Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8f606604 authored by zijun_hu's avatar zijun_hu Committed by Linus Torvalds
Browse files

mm/percpu.c: fix panic triggered by BUG_ON() falsely

As shown by pcpu_build_alloc_info(), the number of units within a percpu
group is deduced by rounding up the number of CPUs within the group to
@upa boundary/ Therefore, the number of CPUs isn't equal to the units's
if it isn't aligned to @upa normally.  However, pcpu_page_first_chunk()
uses BUG_ON() to assert that one number is equal to the other roughly,
so a panic is maybe triggered by the BUG_ON() incorrectly.

In order to fix this issue, the number of CPUs is rounded up then
compared with units's and the BUG_ON() is replaced with a warning and
return of an error code as well, to keep system alive as much as
possible.

Link: http://lkml.kernel.org/r/57FCF07C.2020103@zoho.com


Signed-off-by: default avatarzijun_hu <zijun_hu@htc.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Christoph Lameter <cl@linux.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent c5caf21a
Loading
Loading
Loading
Loading
+12 −4
Original line number Original line Diff line number Diff line
@@ -2093,6 +2093,8 @@ int __init pcpu_page_first_chunk(size_t reserved_size,
	size_t pages_size;
	size_t pages_size;
	struct page **pages;
	struct page **pages;
	int unit, i, j, rc;
	int unit, i, j, rc;
	int upa;
	int nr_g0_units;


	snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10);
	snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10);


@@ -2100,7 +2102,12 @@ int __init pcpu_page_first_chunk(size_t reserved_size,
	if (IS_ERR(ai))
	if (IS_ERR(ai))
		return PTR_ERR(ai);
		return PTR_ERR(ai);
	BUG_ON(ai->nr_groups != 1);
	BUG_ON(ai->nr_groups != 1);
	BUG_ON(ai->groups[0].nr_units != num_possible_cpus());
	upa = ai->alloc_size/ai->unit_size;
	nr_g0_units = roundup(num_possible_cpus(), upa);
	if (unlikely(WARN_ON(ai->groups[0].nr_units != nr_g0_units))) {
		pcpu_free_alloc_info(ai);
		return -EINVAL;
	}


	unit_pages = ai->unit_size >> PAGE_SHIFT;
	unit_pages = ai->unit_size >> PAGE_SHIFT;


@@ -2111,9 +2118,9 @@ int __init pcpu_page_first_chunk(size_t reserved_size,


	/* allocate pages */
	/* allocate pages */
	j = 0;
	j = 0;
	for (unit = 0; unit < num_possible_cpus(); unit++)
	for (unit = 0; unit < num_possible_cpus(); unit++) {
		for (i = 0; i < unit_pages; i++) {
		unsigned int cpu = ai->groups[0].cpu_map[unit];
		unsigned int cpu = ai->groups[0].cpu_map[unit];
		for (i = 0; i < unit_pages; i++) {
			void *ptr;
			void *ptr;


			ptr = alloc_fn(cpu, PAGE_SIZE, PAGE_SIZE);
			ptr = alloc_fn(cpu, PAGE_SIZE, PAGE_SIZE);
@@ -2126,6 +2133,7 @@ int __init pcpu_page_first_chunk(size_t reserved_size,
			kmemleak_free(ptr);
			kmemleak_free(ptr);
			pages[j++] = virt_to_page(ptr);
			pages[j++] = virt_to_page(ptr);
		}
		}
	}


	/* allocate vm area, map the pages and copy static data */
	/* allocate vm area, map the pages and copy static data */
	vm.flags = VM_ALLOC;
	vm.flags = VM_ALLOC;