u64 bytenr, u64 owner_root,
int level)
{
+ struct extent_buffer *eb;
+
if (btrfs_is_testing(fs_info))
return alloc_test_extent_buffer(fs_info, bytenr);
- return alloc_extent_buffer(fs_info, bytenr, owner_root, level);
+ eb = alloc_extent_buffer(fs_info, bytenr, owner_root, level);
+#ifdef CONFIG_BTRFS_DEBUG
+ if (!IS_ERR(eb)) {
+ if (!eb->dbg_create_ip)
+ eb->dbg_create_ip = _RET_IP_;
+ btrfs_eb_dbg_grab(eb, _RET_IP_);
+ }
+#endif
+ return eb;
}
/*
eb = list_first_entry(&fs_info->allocated_ebs,
struct extent_buffer, leak_list);
btrfs_err(fs_info,
- "buffer leak start %llu len %u refs %d bflags %lu owner %llu",
+"buffer leak start %llu len %u refs %d bflags %lu owner %llu gen %llu level %d nritems %u log_index %d lock_owner %d f0up %d",
eb->start, eb->len, refcount_read(&eb->refs), eb->bflags,
- btrfs_header_owner(eb));
+ btrfs_header_owner(eb), btrfs_header_generation(eb),
+ btrfs_header_level(eb), btrfs_header_nritems(eb),
+ eb->log_index, eb->lock_owner,
+ eb->folios[0] ? folio_test_uptodate(eb->folios[0]) : -1);
+ btrfs_err(fs_info, " leak: created %pS staled %pS grabs %u",
+ (void *)eb->dbg_create_ip, (void *)eb->dbg_stale_ip,
+ eb->dbg_grab_n);
+ for (int i = 0; i < 6; i++)
+ btrfs_err(fs_info, " leak: grab[%d] %pS", i,
+ (void *)eb->dbg_grab_ip[i]);
list_del(&eb->leak_list);
WARN_ON_ONCE(1);
kmem_cache_free(extent_buffer_cache, eb);
spin_lock(&eb->refs_lock);
spin_unlock(&eb->refs_lock);
}
+ btrfs_eb_dbg_grab(eb, _RET_IP_);
mark_extent_buffer_accessed(eb);
return eb;
}
spin_lock(&eb->refs_lock);
set_bit(EXTENT_BUFFER_STALE, &eb->bflags);
+#ifdef CONFIG_BTRFS_DEBUG
+ eb->dbg_stale_ip = _RET_IP_;
+#endif
if (refcount_read(&eb->refs) == 2 && !extent_buffer_under_io(eb) &&
test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags))
#ifdef CONFIG_BTRFS_DEBUG
struct list_head leak_list;
pid_t lock_owner;
+ /* DEBUG (cand27): where the last refs were taken / the block staled */
+ unsigned long dbg_grab_ip[6];
+ unsigned int dbg_grab_n;
+ unsigned long dbg_create_ip;
+ unsigned long dbg_stale_ip;
#endif
};
+#ifdef CONFIG_BTRFS_DEBUG
+static inline void btrfs_eb_dbg_grab(struct extent_buffer *eb, unsigned long ip)
+{
+ eb->dbg_grab_ip[eb->dbg_grab_n++ % 6] = ip;
+}
+#else
+#define btrfs_eb_dbg_grab(eb, ip) do {} while (0)
+#endif
+
struct btrfs_eb_write_context {
struct writeback_control *wbc;
struct extent_buffer *eb;