xfs: don't leak xfs_buf_cancel structures when recovery fails
authorDarrick J. Wong <djwong@kernel.org>
Fri, 27 May 2022 00:26:38 +0000 (10:26 +1000)
committerDave Chinner <david@fromorbit.com>
Fri, 27 May 2022 00:26:38 +0000 (10:26 +1000)
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>
fs/xfs/xfs_buf_item_recover.c

index d2e2dff01b99f596782bb3bdbba60702fdd82c5a..f983af4de0a54070de1a0e3d60af4cfe7026a32d 100644 (file)
@@ -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;
 }