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

xfs: don't leak xfs_buf_cancel structures when recovery fails

If log recovery fails, we free the memory used by the buffer
cancellation buckets, but we don't actually traverse each bucket list to
free the individual xfs_buf_cancel objects. This leads to a memory
leak, as reported by kmemleak in xfs/051:

unreferenced object 0xffff888103629560 (size 32):
comm "mount", pid 687045, jiffies 4296935916 (age 10.752s)
hex dump (first 32 bytes):
08 d3 0a 01 00 00 00 00 08 00 00 00 01 00 00 00 ................
d0 f5 0b 92 81 88 ff ff 80 64 64 25 81 88 ff ff .........dd%....
backtrace:
[<ffffffffa0317c83>] kmem_alloc+0x73/0x140 [xfs]
[<ffffffffa03234a9>] xlog_recover_buf_commit_pass1+0x139/0x200 [xfs]
[<ffffffffa032dc27>] xlog_recover_commit_trans+0x307/0x350 [xfs]
[<ffffffffa032df15>] xlog_recovery_process_trans+0xa5/0xe0 [xfs]
[<ffffffffa032e12d>] xlog_recover_process_data+0x8d/0x140 [xfs]
[<ffffffffa032e49d>] xlog_do_recovery_pass+0x19d/0x740 [xfs]
[<ffffffffa032f22d>] xlog_do_log_recovery+0x6d/0x150 [xfs]
[<ffffffffa032f343>] xlog_do_recover+0x33/0x1d0 [xfs]
[<ffffffffa032faba>] xlog_recover+0xda/0x190 [xfs]
[<ffffffffa03194bc>] xfs_log_mount+0x14c/0x360 [xfs]
[<ffffffffa030bfed>] xfs_mountfs+0x50d/0xa60 [xfs]
[<ffffffffa03124b5>] xfs_fs_fill_super+0x6a5/0x950 [xfs]
[<ffffffff812b92a5>] get_tree_bdev+0x175/0x280
[<ffffffff812b7c3a>] vfs_get_tree+0x1a/0x80
[<ffffffff812e366f>] path_mount+0x6ff/0xaa0
[<ffffffff812e3b13>] __x64_sys_mount+0x103/0x140

Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>

authored by

Darrick J. Wong and committed by
Dave Chinner
8db074bd 27232349

+13
+13
fs/xfs/xfs_buf_item_recover.c
··· 1034 1034 xlog_free_buf_cancel_table( 1035 1035 struct xlog *log) 1036 1036 { 1037 + int i; 1038 + 1037 1039 if (!log->l_buf_cancel_table) 1038 1040 return; 1041 + 1042 + for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) { 1043 + struct xfs_buf_cancel *bc; 1044 + 1045 + while ((bc = list_first_entry_or_null( 1046 + &log->l_buf_cancel_table[i], 1047 + struct xfs_buf_cancel, bc_list))) { 1048 + list_del(&bc->bc_list); 1049 + kmem_free(bc); 1050 + } 1051 + } 1039 1052 1040 1053 kmem_free(log->l_buf_cancel_table); 1041 1054 log->l_buf_cancel_table = NULL;