#define OBJECT_PHYS (1 << 4)
/* flag set for per-CPU pointers */
#define OBJECT_PERCPU (1 << 5)
+/* flag set on an object left unreferenced by the full scan, pending confirmation */
+#define OBJECT_SUSPECT (1 << 6)
/* set when __remove_object() called */
#define DELSTATE_REMOVED (1 << 0)
static unsigned long jiffies_last_scan;
/* delay between automatic memory scannings */
static unsigned long jiffies_scan_wait;
+/* number of objects flagged OBJECT_SUSPECT during the current scan */
+static int nr_suspects;
/* enables or disables the task stacks scanning */
static int kmemleak_stack_scan = 1;
/* protects the memory scanning, parameters and debug/kmemleak file access */
*/
object->count++;
if (color_gray(object)) {
+ /* referenced after all, no longer a suspect */
+ if (object->flags & OBJECT_SUSPECT) {
+ object->flags &= ~OBJECT_SUSPECT;
+ nr_suspects--;
+ }
/* put_object() called when removing from gray_list */
WARN_ON(!get_object(object));
list_add_tail(&object->gray_list, &gray_list);
* kernel's standard allocators. This function must be called with the
* scan_mutex held.
*/
-static void kmemleak_scan(void)
+static int __kmemleak_scan(bool full)
{
struct kmemleak_object *object;
struct zone *zone;
int __maybe_unused i;
- struct xarray dedup;
- int new_leaks = 0;
int stop = 0;
jiffies_last_scan = jiffies;
+ if (full)
+ nr_suspects = 0;
/* prepare the kmemleak_object's */
rcu_read_lock();
/* reset the reference count (whiten the object) */
object->count = 0;
+ if (full)
+ object->flags &= ~OBJECT_SUSPECT;
if (color_gray(object) && get_object(object))
list_add_tail(&object->gray_list, &gray_list);
scan_gray:
scan_gray_list();
+ /* a confirmation scan does not look for modified objects */
+ if (!full)
+ return nr_suspects;
+
/*
* Check for new or unreferenced objects modified since the previous
* scan and color them gray until the next scan.
/* color it gray temporarily */
object->count = object->min_count;
list_add_tail(&object->gray_list, &gray_list);
+ } else if (unreferenced_object(object) &&
+ !(object->flags & OBJECT_REPORTED)) {
+ /* flag the objects left unreferenced by this scan */
+ object->flags |= OBJECT_SUSPECT;
+ nr_suspects++;
}
raw_spin_unlock_irq(&object->lock);
}
*/
scan_gray_list();
+ return nr_suspects;
+}
+
+/*
+ * Scan the memory and report the unreferenced objects as leaks. Must be
+ * called with the scan_mutex held.
+ */
+static void kmemleak_scan(void)
+{
+ struct kmemleak_object *object;
+ struct xarray dedup;
+ int new_leaks = 0;
+
+ /*
+ * Full scan. Objects left unreferenced are flagged OBJECT_SUSPECT and
+ * counted in the return value; nothing to confirm or report otherwise.
+ */
+ if (!__kmemleak_scan(true))
+ return;
+
/*
* If scanning was stopped do not report any new unreferenced objects.
*/
if (scan_should_stop())
return;
+ /*
+ * A live object whose only reference is moved by, for example, a
+ * concurrent RCU update can be missed for one scan and reported as a
+ * transient false positive. Scan again and only report the objects
+ * left unreferenced (still flagged OBJECT_SUSPECT) by both scans.
+ */
+ __kmemleak_scan(false);
+ if (scan_should_stop())
+ return;
+
/*
* Scanning result reporting. When verbose printing is enabled, dedupe
* by stackdepot trace_handle so each unique backtrace is logged once
trace_handle = 0;
dedup_print = false;
if (unreferenced_object(object) &&
+ (object->flags & OBJECT_SUSPECT) &&
!(object->flags & OBJECT_REPORTED)) {
object->flags |= OBJECT_REPORTED;
if (kmemleak_verbose) {