--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+#ifndef _LINUX_REF_TRACKER_H
+#define _LINUX_REF_TRACKER_H
+#include <linux/refcount.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct ref_tracker;
+
+struct ref_tracker_dir {
+#ifdef CONFIG_REF_TRACKER
+       spinlock_t              lock;
+       unsigned int            quarantine_avail;
+       refcount_t              untracked;
+       struct list_head        list; /* List of active trackers */
+       struct list_head        quarantine; /* List of dead trackers */
+#endif
+};
+
+#ifdef CONFIG_REF_TRACKER
+static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
+                                       unsigned int quarantine_count)
+{
+       INIT_LIST_HEAD(&dir->list);
+       INIT_LIST_HEAD(&dir->quarantine);
+       spin_lock_init(&dir->lock);
+       dir->quarantine_avail = quarantine_count;
+       refcount_set(&dir->untracked, 1);
+}
+
+void ref_tracker_dir_exit(struct ref_tracker_dir *dir);
+
+void ref_tracker_dir_print(struct ref_tracker_dir *dir,
+                          unsigned int display_limit);
+
+int ref_tracker_alloc(struct ref_tracker_dir *dir,
+                     struct ref_tracker **trackerp, gfp_t gfp);
+
+int ref_tracker_free(struct ref_tracker_dir *dir,
+                    struct ref_tracker **trackerp);
+
+#else /* CONFIG_REF_TRACKER */
+
+static inline void ref_tracker_dir_init(struct ref_tracker_dir *dir,
+                                       unsigned int quarantine_count)
+{
+}
+
+static inline void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
+{
+}
+
+static inline void ref_tracker_dir_print(struct ref_tracker_dir *dir,
+                                        unsigned int display_limit)
+{
+}
+
+static inline int ref_tracker_alloc(struct ref_tracker_dir *dir,
+                                   struct ref_tracker **trackerp,
+                                   gfp_t gfp)
+{
+       return 0;
+}
+
+static inline int ref_tracker_free(struct ref_tracker_dir *dir,
+                                  struct ref_tracker **trackerp)
+{
+       return 0;
+}
+
+#endif
+
+#endif /* _LINUX_REF_TRACKER_H */
 
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/export.h>
+#include <linux/ref_tracker.h>
+#include <linux/slab.h>
+#include <linux/stacktrace.h>
+#include <linux/stackdepot.h>
+
+#define REF_TRACKER_STACK_ENTRIES 16
+
+struct ref_tracker {
+       struct list_head        head;   /* anchor into dir->list or dir->quarantine */
+       bool                    dead;
+       depot_stack_handle_t    alloc_stack_handle;
+       depot_stack_handle_t    free_stack_handle;
+};
+
+void ref_tracker_dir_exit(struct ref_tracker_dir *dir)
+{
+       struct ref_tracker *tracker, *n;
+       unsigned long flags;
+       bool leak = false;
+
+       spin_lock_irqsave(&dir->lock, flags);
+       list_for_each_entry_safe(tracker, n, &dir->quarantine, head) {
+               list_del(&tracker->head);
+               kfree(tracker);
+               dir->quarantine_avail++;
+       }
+       list_for_each_entry_safe(tracker, n, &dir->list, head) {
+               pr_err("leaked reference.\n");
+               if (tracker->alloc_stack_handle)
+                       stack_depot_print(tracker->alloc_stack_handle);
+               leak = true;
+               list_del(&tracker->head);
+               kfree(tracker);
+       }
+       spin_unlock_irqrestore(&dir->lock, flags);
+       WARN_ON_ONCE(leak);
+       WARN_ON_ONCE(refcount_read(&dir->untracked) != 1);
+}
+EXPORT_SYMBOL(ref_tracker_dir_exit);
+
+void ref_tracker_dir_print(struct ref_tracker_dir *dir,
+                          unsigned int display_limit)
+{
+       struct ref_tracker *tracker;
+       unsigned long flags;
+       unsigned int i = 0;
+
+       spin_lock_irqsave(&dir->lock, flags);
+       list_for_each_entry(tracker, &dir->list, head) {
+               if (i < display_limit) {
+                       pr_err("leaked reference.\n");
+                       if (tracker->alloc_stack_handle)
+                               stack_depot_print(tracker->alloc_stack_handle);
+                       i++;
+               } else {
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&dir->lock, flags);
+}
+EXPORT_SYMBOL(ref_tracker_dir_print);
+
+int ref_tracker_alloc(struct ref_tracker_dir *dir,
+                     struct ref_tracker **trackerp,
+                     gfp_t gfp)
+{
+       unsigned long entries[REF_TRACKER_STACK_ENTRIES];
+       struct ref_tracker *tracker;
+       unsigned int nr_entries;
+       unsigned long flags;
+
+       *trackerp = tracker = kzalloc(sizeof(*tracker), gfp | __GFP_NOFAIL);
+       if (unlikely(!tracker)) {
+               pr_err_once("memory allocation failure, unreliable refcount tracker.\n");
+               refcount_inc(&dir->untracked);
+               return -ENOMEM;
+       }
+       nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 1);
+       nr_entries = filter_irq_stacks(entries, nr_entries);
+       tracker->alloc_stack_handle = stack_depot_save(entries, nr_entries, gfp);
+
+       spin_lock_irqsave(&dir->lock, flags);
+       list_add(&tracker->head, &dir->list);
+       spin_unlock_irqrestore(&dir->lock, flags);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ref_tracker_alloc);
+
+int ref_tracker_free(struct ref_tracker_dir *dir,
+                    struct ref_tracker **trackerp)
+{
+       unsigned long entries[REF_TRACKER_STACK_ENTRIES];
+       struct ref_tracker *tracker = *trackerp;
+       depot_stack_handle_t stack_handle;
+       unsigned int nr_entries;
+       unsigned long flags;
+
+       if (!tracker) {
+               refcount_dec(&dir->untracked);
+               return -EEXIST;
+       }
+       nr_entries = stack_trace_save(entries, ARRAY_SIZE(entries), 1);
+       nr_entries = filter_irq_stacks(entries, nr_entries);
+       stack_handle = stack_depot_save(entries, nr_entries, GFP_ATOMIC);
+
+       spin_lock_irqsave(&dir->lock, flags);
+       if (tracker->dead) {
+               pr_err("reference already released.\n");
+               if (tracker->alloc_stack_handle) {
+                       pr_err("allocated in:\n");
+                       stack_depot_print(tracker->alloc_stack_handle);
+               }
+               if (tracker->free_stack_handle) {
+                       pr_err("freed in:\n");
+                       stack_depot_print(tracker->free_stack_handle);
+               }
+               spin_unlock_irqrestore(&dir->lock, flags);
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
+       tracker->dead = true;
+
+       tracker->free_stack_handle = stack_handle;
+
+       list_move_tail(&tracker->head, &dir->quarantine);
+       if (!dir->quarantine_avail) {
+               tracker = list_first_entry(&dir->quarantine, struct ref_tracker, head);
+               list_del(&tracker->head);
+       } else {
+               dir->quarantine_avail--;
+               tracker = NULL;
+       }
+       spin_unlock_irqrestore(&dir->lock, flags);
+
+       kfree(tracker);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ref_tracker_free);