From 8db074bd84df5ccc88bff3f8f900f66f4b8349fa Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 27 May 2022 10:26:38 +1000 Subject: [PATCH] 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: [] kmem_alloc+0x73/0x140 [xfs] [] xlog_recover_buf_commit_pass1+0x139/0x200 [xfs] [] xlog_recover_commit_trans+0x307/0x350 [xfs] [] xlog_recovery_process_trans+0xa5/0xe0 [xfs] [] xlog_recover_process_data+0x8d/0x140 [xfs] [] xlog_do_recovery_pass+0x19d/0x740 [xfs] [] xlog_do_log_recovery+0x6d/0x150 [xfs] [] xlog_do_recover+0x33/0x1d0 [xfs] [] xlog_recover+0xda/0x190 [xfs] [] xfs_log_mount+0x14c/0x360 [xfs] [] xfs_mountfs+0x50d/0xa60 [xfs] [] xfs_fs_fill_super+0x6a5/0x950 [xfs] [] get_tree_bdev+0x175/0x280 [] vfs_get_tree+0x1a/0x80 [] path_mount+0x6ff/0xaa0 [] __x64_sys_mount+0x103/0x140 Signed-off-by: Darrick J. Wong Reviewed-by: Christoph Hellwig Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_buf_item_recover.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/xfs/xfs_buf_item_recover.c b/fs/xfs/xfs_buf_item_recover.c index d2e2dff01b99..f983af4de0a5 100644 --- a/fs/xfs/xfs_buf_item_recover.c +++ b/fs/xfs/xfs_buf_item_recover.c @@ -1034,9 +1034,22 @@ void xlog_free_buf_cancel_table( struct xlog *log) { + int i; + if (!log->l_buf_cancel_table) return; + for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) { + struct xfs_buf_cancel *bc; + + while ((bc = list_first_entry_or_null( + &log->l_buf_cancel_table[i], + struct xfs_buf_cancel, bc_list))) { + list_del(&bc->bc_list); + kmem_free(bc); + } + } + kmem_free(log->l_buf_cancel_table); log->l_buf_cancel_table = NULL; } -- 2.25.1