Re: [PATCH] ufs: free the buffer head container in ubh_bforget
Luis Henriques <[email protected]> Sun, 02 Aug 2026 10:28:29 +0100
| Newsgroups | org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
On Sat, Aug 01 2026, Ali Ahmet Memis wrote: > ubh_bforget() forgets the buffer heads referenced by a struct > ufs_buffer_head but never frees the container itself, unlike its > sibling ubh_brelse() which calls kfree() on the way out. The only > caller, free_full_branch(), allocates the container through ubh_bread() > while releasing an indirect block during truncate, so every fully > removed indirect block leaks one ufs_buffer_head. Truncating or > unlinking a large file then leaks one allocation per indirect block, > which kmemleak reports with a free_full_branch, ufs_truncate_blocks, > ufs_evict_inode backtrace. > > Free the container after forgetting its buffers, mirroring ubh_brelse(). > > Luis Henriques posted a fix for this leak in 2018, but it was never > applied while fs/ufs had no active maintainer, and the leak is still > present. It's been a while, and I don't even remember why I was running xfstests against this filesystem :-) But the fix still looks OK. My original patch also dropped the 'if', but that's just a minor detail. I don't know who's using this ufs driver these days -- each BSD has it's own thing, and it's likely to be risky to mount a filesystem in rw mode. Cheers, -- Luís > Link: https://lore.kernel.org/all/[email protected]/ > Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") > Cc: [email protected] > Signed-off-by: Ali Ahmet Memis <[email protected]> > --- > fs/ufs/util.c | 6 ++++-- > 1 file changed, 4 insertions(+), 2 deletions(-) > > diff --git a/fs/ufs/util.c b/fs/ufs/util.c > index dff6f7461..3c65fbef6 100644 > --- a/fs/ufs/util.c > +++ b/fs/ufs/util.c > @@ -117,8 +117,10 @@ void ubh_bforget (struct ufs_buffer_head * ubh) > unsigned i; > if (!ubh) > return; > - for ( i = 0; i < ubh->count; i++ ) if ( ubh->bh[i] ) > - bforget (ubh->bh[i]); > + for (i = 0; i < ubh->count; i++) > + if (ubh->bh[i]) > + bforget(ubh->bh[i]); > + kfree(ubh); > } > > int ubh_buffer_dirty (struct ufs_buffer_head * ubh) > -- > 2.54.0 >