diff mbox series

btrfs: fix memory leak in btrfs_read_folio

Message ID fb513314c27317128426ab6e84bbb644603e65f5.1709628782.git.jth@kernel.org (mailing list archive)
State New, archived
Headers show
Series btrfs: fix memory leak in btrfs_read_folio | expand

Commit Message

Johannes Thumshirn March 5, 2024, 8:53 a.m. UTC
From: Johannes Thumshirn <johannes.thumshirn@wdc.com>

A recent fstests run with enabled kmemleak revealed the following splat:

  unreferenced object 0xffff88810276bf80 (size 128):
    comm "fssum", pid 2428, jiffies 4294909974
    hex dump (first 32 bytes):
      80 bf 76 02 81 88 ff ff 00 00 00 00 00 00 00 00  ..v.............
      00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
    backtrace (crc 1d0b936a):
      [<000000000fe42cf8>] kmem_cache_alloc+0x196/0x310
      [<00000000adb72ffd>] alloc_extent_map+0x15/0x40
      [<000000008d9259d5>] btrfs_get_extent+0xa3/0x8e0
      [<0000000015a05e9a>] btrfs_do_readpage+0x1a5/0x730
      [<0000000060fddacb>] btrfs_read_folio+0x77/0x90
      [<00000000509dda36>] filemap_read_folio+0x24/0x1e0
      [<00000000dee3c1b4>] do_read_cache_folio+0x79/0x2c0
      [<00000000bf294762>] read_cache_page+0x14/0x40
      [<0000000048653172>] page_get_link+0x25/0xe0
      [<0000000094b5d096>] vfs_readlink+0x86/0xf0
      [<00000000698ab966>] do_readlinkat+0x97/0xf0
      [<00000000a55a2b4c>] __x64_sys_readlink+0x19/0x20
      [<000000006e1b608e>] do_syscall_64+0x77/0x150
      [<000000008fcc6e49>] entry_SYSCALL_64_afer_hwframe+0x6e/0x76

This leaked object is the 'em_cached' extent map, which will not be freed
when btrfs_read_folio() finishes if it is set.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
---
 fs/btrfs/extent_io.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Qu Wenruo March 5, 2024, 9:03 a.m. UTC | #1
在 2024/3/5 19:23, Johannes Thumshirn 写道:
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>
> A recent fstests run with enabled kmemleak revealed the following splat:
>
>    unreferenced object 0xffff88810276bf80 (size 128):
>      comm "fssum", pid 2428, jiffies 4294909974
>      hex dump (first 32 bytes):
>        80 bf 76 02 81 88 ff ff 00 00 00 00 00 00 00 00  ..v.............
>        00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>      backtrace (crc 1d0b936a):
>        [<000000000fe42cf8>] kmem_cache_alloc+0x196/0x310
>        [<00000000adb72ffd>] alloc_extent_map+0x15/0x40
>        [<000000008d9259d5>] btrfs_get_extent+0xa3/0x8e0
>        [<0000000015a05e9a>] btrfs_do_readpage+0x1a5/0x730
>        [<0000000060fddacb>] btrfs_read_folio+0x77/0x90
>        [<00000000509dda36>] filemap_read_folio+0x24/0x1e0
>        [<00000000dee3c1b4>] do_read_cache_folio+0x79/0x2c0
>        [<00000000bf294762>] read_cache_page+0x14/0x40
>        [<0000000048653172>] page_get_link+0x25/0xe0
>        [<0000000094b5d096>] vfs_readlink+0x86/0xf0
>        [<00000000698ab966>] do_readlinkat+0x97/0xf0
>        [<00000000a55a2b4c>] __x64_sys_readlink+0x19/0x20
>        [<000000006e1b608e>] do_syscall_64+0x77/0x150
>        [<000000008fcc6e49>] entry_SYSCALL_64_afer_hwframe+0x6e/0x76
>
> This leaked object is the 'em_cached' extent map, which will not be freed
> when btrfs_read_folio() finishes if it is set.
>
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

Reviewed-by: Qu Wenruo <wqu@suse.com>

Thanks,
Qu
> ---
>   fs/btrfs/extent_io.c | 2 ++
>   1 file changed, 2 insertions(+)
>
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 65e4c8fc89b1..832be9030aa1 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -1162,6 +1162,8 @@ int btrfs_read_folio(struct file *file, struct folio *folio)
>   	btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
>
>   	ret = btrfs_do_readpage(page, &em_cached, &bio_ctrl, NULL);
> +	if (em_cached)
> +		free_extent_map(em_cached);
>   	/*
>   	 * If btrfs_do_readpage() failed we will want to submit the assembled
>   	 * bio to do the cleanup.
Filipe Manana March 5, 2024, 10:46 a.m. UTC | #2
On Tue, Mar 5, 2024 at 8:54 AM Johannes Thumshirn <jth@kernel.org> wrote:
>
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
>
> A recent fstests run with enabled kmemleak revealed the following splat:
>
>   unreferenced object 0xffff88810276bf80 (size 128):
>     comm "fssum", pid 2428, jiffies 4294909974
>     hex dump (first 32 bytes):
>       80 bf 76 02 81 88 ff ff 00 00 00 00 00 00 00 00  ..v.............
>       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>     backtrace (crc 1d0b936a):
>       [<000000000fe42cf8>] kmem_cache_alloc+0x196/0x310
>       [<00000000adb72ffd>] alloc_extent_map+0x15/0x40
>       [<000000008d9259d5>] btrfs_get_extent+0xa3/0x8e0
>       [<0000000015a05e9a>] btrfs_do_readpage+0x1a5/0x730
>       [<0000000060fddacb>] btrfs_read_folio+0x77/0x90
>       [<00000000509dda36>] filemap_read_folio+0x24/0x1e0
>       [<00000000dee3c1b4>] do_read_cache_folio+0x79/0x2c0
>       [<00000000bf294762>] read_cache_page+0x14/0x40
>       [<0000000048653172>] page_get_link+0x25/0xe0
>       [<0000000094b5d096>] vfs_readlink+0x86/0xf0
>       [<00000000698ab966>] do_readlinkat+0x97/0xf0
>       [<00000000a55a2b4c>] __x64_sys_readlink+0x19/0x20
>       [<000000006e1b608e>] do_syscall_64+0x77/0x150
>       [<000000008fcc6e49>] entry_SYSCALL_64_afer_hwframe+0x6e/0x76
>
> This leaked object is the 'em_cached' extent map, which will not be freed
> when btrfs_read_folio() finishes if it is set.

Ok, so this fixes "btrfs: pass a valid extent map cache pointer to
__get_extent_map()".

>
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> ---
>  fs/btrfs/extent_io.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 65e4c8fc89b1..832be9030aa1 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -1162,6 +1162,8 @@ int btrfs_read_folio(struct file *file, struct folio *folio)
>         btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
>
>         ret = btrfs_do_readpage(page, &em_cached, &bio_ctrl, NULL);
> +       if (em_cached)
> +               free_extent_map(em_cached);

There's no need for the if not-NULL check.
Like most freeing functions in the kernel (kfree, kvfree, most of
btrfs' own) and user space, free_extent_map() ignores a NULL pointer.

Otherwise it looks good.

Reviewed-by: Filipe Manana <fdmanana@suse.com>

Thanks.

>         /*
>          * If btrfs_do_readpage() failed we will want to submit the assembled
>          * bio to do the cleanup.
> --
> 2.35.3
>
>
David Sterba March 5, 2024, 4:05 p.m. UTC | #3
On Tue, Mar 05, 2024 at 09:53:35AM +0100, Johannes Thumshirn wrote:
> From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> 
> A recent fstests run with enabled kmemleak revealed the following splat:
> 
>   unreferenced object 0xffff88810276bf80 (size 128):
>     comm "fssum", pid 2428, jiffies 4294909974
>     hex dump (first 32 bytes):
>       80 bf 76 02 81 88 ff ff 00 00 00 00 00 00 00 00  ..v.............
>       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
>     backtrace (crc 1d0b936a):
>       [<000000000fe42cf8>] kmem_cache_alloc+0x196/0x310
>       [<00000000adb72ffd>] alloc_extent_map+0x15/0x40
>       [<000000008d9259d5>] btrfs_get_extent+0xa3/0x8e0
>       [<0000000015a05e9a>] btrfs_do_readpage+0x1a5/0x730
>       [<0000000060fddacb>] btrfs_read_folio+0x77/0x90
>       [<00000000509dda36>] filemap_read_folio+0x24/0x1e0
>       [<00000000dee3c1b4>] do_read_cache_folio+0x79/0x2c0
>       [<00000000bf294762>] read_cache_page+0x14/0x40
>       [<0000000048653172>] page_get_link+0x25/0xe0
>       [<0000000094b5d096>] vfs_readlink+0x86/0xf0
>       [<00000000698ab966>] do_readlinkat+0x97/0xf0
>       [<00000000a55a2b4c>] __x64_sys_readlink+0x19/0x20
>       [<000000006e1b608e>] do_syscall_64+0x77/0x150
>       [<000000008fcc6e49>] entry_SYSCALL_64_afer_hwframe+0x6e/0x76
> 
> This leaked object is the 'em_cached' extent map, which will not be freed
> when btrfs_read_folio() finishes if it is set.
> 
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>

As Filipe noted it's from my patch "btrfs: pass a valid extent map cache
pointer to __get_extent_map()", I'd rather fold the fix than to add the
fixup commit.
Naohiro Aota March 6, 2024, 7:33 a.m. UTC | #4
On Tue, Mar 05, 2024 at 10:46:35AM +0000, Filipe Manana wrote:
> On Tue, Mar 5, 2024 at 8:54 AM Johannes Thumshirn <jth@kernel.org> wrote:
> >
> > From: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> >
> > A recent fstests run with enabled kmemleak revealed the following splat:
> >
> >   unreferenced object 0xffff88810276bf80 (size 128):
> >     comm "fssum", pid 2428, jiffies 4294909974
> >     hex dump (first 32 bytes):
> >       80 bf 76 02 81 88 ff ff 00 00 00 00 00 00 00 00  ..v.............
> >       00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
> >     backtrace (crc 1d0b936a):
> >       [<000000000fe42cf8>] kmem_cache_alloc+0x196/0x310
> >       [<00000000adb72ffd>] alloc_extent_map+0x15/0x40
> >       [<000000008d9259d5>] btrfs_get_extent+0xa3/0x8e0
> >       [<0000000015a05e9a>] btrfs_do_readpage+0x1a5/0x730
> >       [<0000000060fddacb>] btrfs_read_folio+0x77/0x90
> >       [<00000000509dda36>] filemap_read_folio+0x24/0x1e0
> >       [<00000000dee3c1b4>] do_read_cache_folio+0x79/0x2c0
> >       [<00000000bf294762>] read_cache_page+0x14/0x40
> >       [<0000000048653172>] page_get_link+0x25/0xe0
> >       [<0000000094b5d096>] vfs_readlink+0x86/0xf0
> >       [<00000000698ab966>] do_readlinkat+0x97/0xf0
> >       [<00000000a55a2b4c>] __x64_sys_readlink+0x19/0x20
> >       [<000000006e1b608e>] do_syscall_64+0x77/0x150
> >       [<000000008fcc6e49>] entry_SYSCALL_64_afer_hwframe+0x6e/0x76
> >
> > This leaked object is the 'em_cached' extent map, which will not be freed
> > when btrfs_read_folio() finishes if it is set.
> 
> Ok, so this fixes "btrfs: pass a valid extent map cache pointer to
> __get_extent_map()".
> 
> >
> > Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> > ---
> >  fs/btrfs/extent_io.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> > index 65e4c8fc89b1..832be9030aa1 100644
> > --- a/fs/btrfs/extent_io.c
> > +++ b/fs/btrfs/extent_io.c
> > @@ -1162,6 +1162,8 @@ int btrfs_read_folio(struct file *file, struct folio *folio)
> >         btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
> >
> >         ret = btrfs_do_readpage(page, &em_cached, &bio_ctrl, NULL);
> > +       if (em_cached)
> > +               free_extent_map(em_cached);
> 
> There's no need for the if not-NULL check.
> Like most freeing functions in the kernel (kfree, kvfree, most of
> btrfs' own) and user space, free_extent_map() ignores a NULL pointer.

FYI, get_extent_allocation_hint() and extent_readahead() does the same "if
(em) free_extent_map(em);" pattern, which we may want to clean up.

> 
> Otherwise it looks good.
> 
> Reviewed-by: Filipe Manana <fdmanana@suse.com>
> 
> Thanks.
> 
> >         /*
> >          * If btrfs_do_readpage() failed we will want to submit the assembled
> >          * bio to do the cleanup.
> > --
> > 2.35.3
> >
> >
diff mbox series

Patch

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 65e4c8fc89b1..832be9030aa1 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1162,6 +1162,8 @@  int btrfs_read_folio(struct file *file, struct folio *folio)
 	btrfs_lock_and_flush_ordered_range(inode, start, end, NULL);
 
 	ret = btrfs_do_readpage(page, &em_cached, &bio_ctrl, NULL);
+	if (em_cached)
+		free_extent_map(em_cached);
 	/*
 	 * If btrfs_do_readpage() failed we will want to submit the assembled
 	 * bio to do the cleanup.