[PATCH v2] ufs: free the buffer head container in ubh_bforget

Ali Ahmet Memis <[email protected]>
Newsgroups org.kernel.vger.stable,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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().
Drop the NULL test in the loop as well, which Luis already noted is
redundant because bforget() ignores a NULL buffer head; ubh_brelse() has
no such test either, so the two now match.

Luis Henriques posted this fix in 2018. It never got a single reply and
was never applied, while fs/ufs had no active maintainer, and the leak is
still present.

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]>
---
v2: drop the NULL test in the loop, as Luis pointed out. That makes this
    the same change as his 2018 patch; if you would rather it went in
    under his authorship I am happy to resend it that way, his call.
    Whitespace on the touched lines modernised to keep checkpatch quiet.

v1: https://lore.kernel.org/all/[email protected]/

 fs/ufs/util.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/ufs/util.c b/fs/ufs/util.c
index dff6f74618de..603d80b93066 100644
--- a/fs/ufs/util.c
+++ b/fs/ufs/util.c
@@ -117,8 +117,9 @@ 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++)
+		bforget(ubh->bh[i]);
+	kfree(ubh);
 }
  
 int ubh_buffer_dirty (struct ufs_buffer_head * ubh)

base-commit: 2d2338c93da79b3bfe4b6099a931d9468d539952
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.