static int cec_add_elem()

in cec.c [321:395]


static int cec_add_elem(u64 pfn)
{
	struct ce_array *ca = &ce_arr;
	int count, err, ret = 0;
	unsigned int to = 0;

	/*
	 * We can be called very early on the identify_cpu() path where we are
	 * not initialized yet. We ignore the error for simplicity.
	 */
	if (!ce_arr.array || ce_arr.disabled)
		return -ENODEV;

	mutex_lock(&ce_mutex);

	ca->ces_entered++;

	/* Array full, free the LRU slot. */
	if (ca->n == MAX_ELEMS)
		WARN_ON(!del_lru_elem_unlocked(ca));

	err = find_elem(ca, pfn, &to);
	if (err < 0) {
		/*
		 * Shift range [to-end] to make room for one more element.
		 */
		memmove((void *)&ca->array[to + 1],
			(void *)&ca->array[to],
			(ca->n - to) * sizeof(u64));

		ca->array[to] = pfn << PAGE_SHIFT;
		ca->n++;
	}

	/* Add/refresh element generation and increment count */
	ca->array[to] |= DECAY_MASK << COUNT_BITS;
	ca->array[to]++;

	/* Check action threshold and soft-offline, if reached. */
	count = COUNT(ca->array[to]);
	if (count >= action_threshold) {
		u64 pfn = ca->array[to] >> PAGE_SHIFT;

		if (!pfn_valid(pfn)) {
			pr_warn("CEC: Invalid pfn: 0x%llx\n", pfn);
		} else {
			/* We have reached max count for this page, soft-offline it. */
			pr_err("Soft-offlining pfn: 0x%llx\n", pfn);
			memory_failure_queue(pfn, MF_SOFT_OFFLINE);
			ca->pfns_poisoned++;
		}

		del_elem(ca, to);

		/*
		 * Return a >0 value to callers, to denote that we've reached
		 * the offlining threshold.
		 */
		ret = 1;

		goto unlock;
	}

	ca->decay_count++;

	if (ca->decay_count >= CLEAN_ELEMS)
		do_spring_cleaning(ca);

	WARN_ON_ONCE(sanity_check(ca));

unlock:
	mutex_unlock(&ce_mutex);

	return ret;
}