Source
DEFINE_DEBUGFS_ATTRIBUTE(count_threshold_ops, u64_get, count_threshold_set, "%lld\n");
// SPDX-License-Identifier: GPL-2.0
/*
* RAS Correctable Errors Collector
*
* This is a simple gadget which collects correctable errors and counts their
* occurrence per physical page address.
*
* We've opted for possibly the simplest data structure to collect those - an
* array of the size of a memory page. It stores 512 u64's with the following
* structure:
*
* [63 ... PFN ... 12 | 11 ... generation ... 10 | 9 ... count ... 0]
*
* The generation in the two highest order bits is two bits which are set to 11b
* on every insertion. During the course of each entry's existence, the
* generation field gets decremented during spring cleaning to 10b, then 01b and
* then 00b.
*
* This way we're employing the natural numeric ordering to make sure that newly
* inserted/touched elements have higher 12-bit counts (which we've manufactured)
* and thus iterating over the array initially won't kick out those elements
* which were inserted last.
*
* Spring cleaning is what we do when we reach a certain number CLEAN_ELEMS of
* elements entered into the array, during which, we're decaying all elements.
* If, after decay, an element gets inserted again, its generation is set to 11b
* to make sure it has higher numerical count than other, older elements and
* thus emulate an an LRU-like behavior when deleting elements to free up space
* in the page.
*
* When an element reaches it's max count of count_threshold, we try to poison
* it by assuming that errors triggered count_threshold times in a single page
* are excessive and that page shouldn't be used anymore. count_threshold is
* initialized to COUNT_MASK which is the maximum.
*
* That error event entry causes cec_add_elem() to return !0 value and thus
* signal to its callers to log the error.
*
* To the question why we've chosen a page and moving elements around with
* memmove(), it is because it is a very simple structure to handle and max data
* movement is 4K which on highly optimized modern CPUs is almost unnoticeable.
* We wanted to avoid the pointer traversal of more complex structures like a
* linked list or some sort of a balancing search tree.
*
* Deleting an element takes O(n) but since it is only a single page, it should
* be fast enough and it shouldn't happen all too often depending on error
* patterns.
*/
/*
* We use DECAY_BITS bits of PAGE_SHIFT bits for counting decay, i.e., how long
* elements have stayed in the array without having been accessed again.