Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

btrfs: fix delayed_node ref_tracker use after free

Move the print before releasing the delayed node.

In my initial testing there was a bug that was causing delayed_nodes
to not get freed which is why I put the print after the release. This
obviously neglects the case where the delayed node is properly freed.

Add condition to make sure we only print if we have more than one
reference to the delayed_node to prevent printing when we only have
the reference taken in btrfs_kill_all_delayed_nodes().

Fixes: b767a28d6154 ("btrfs: print leaked references in kill_all_delayed_nodes()")
Tested-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Leo Martins <loemra.dev@gmail.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>

authored by

Leo Martins and committed by
David Sterba
0fd7e7a1 1fabe43b

+8 -1
+1 -1
fs/btrfs/delayed-inode.c
··· 2110 2110 2111 2111 for (int i = 0; i < count; i++) { 2112 2112 __btrfs_kill_delayed_node(delayed_nodes[i]); 2113 + btrfs_delayed_node_ref_tracker_dir_print(delayed_nodes[i]); 2113 2114 btrfs_release_delayed_node(delayed_nodes[i], 2114 2115 &delayed_node_trackers[i]); 2115 - btrfs_delayed_node_ref_tracker_dir_print(delayed_nodes[i]); 2116 2116 } 2117 2117 } 2118 2118 }
+7
fs/btrfs/delayed-inode.h
··· 219 219 if (!btrfs_test_opt(node->root->fs_info, REF_TRACKER)) 220 220 return; 221 221 222 + /* 223 + * Only print if there are leaked references. The caller is 224 + * holding one reference, so if refs == 1 there is no leak. 225 + */ 226 + if (refcount_read(&node->refs) == 1) 227 + return; 228 + 222 229 ref_tracker_dir_print(&node->ref_dir.dir, 223 230 BTRFS_DELAYED_NODE_REF_TRACKER_DISPLAY_LIMIT); 224 231 }