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;
}