Re: [PATCH] ceph: fix refcount leak in write_folio_nounlock()

Viacheslav Dubeyko <[email protected]>
Newsgroups org.kernel.vger.ceph-devel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <[email protected]>
On Thu, 2026-06-11 at 22:34 +0800, WenTao Liang wrote:
> write_folio_nounlock() unconditionally increments
> fsc->writeback_count before allocating an OSD request.  If an
> early error causes the function to return without queuing an
> active write, the counter is never decremented, leaking a
> reference and making the filesystem appear permanently
> congested.  Three such paths exist:
> 
> - ceph_osdc_new_request() fails: the folio is redirtied, but
>   writeback_count remains incremented.
> 
> - After the request is allocated, the fscrypt bounce page
>   allocation fails.  The function ends writeback on the folio
>   and releases the request, but does not drop the
>   writeback_count reference.
> 
> - The write is interrupted by a signal (e.g. -ERESTARTSYS).
>   The folio is redirtied and writeback is ended, yet again the
>   counter is left elevated.
> 
> Fix the leaks by adding an atomic_long_dec() in each of these
> early return paths, balancing the initial inc.
> 
> Cc: [email protected]
> Fixes: 6390987f2f4c ("ceph: fold ceph_sync_writepages into
> writepage_nounlock")
> Signed-off-by: WenTao Liang <[email protected]>
> ---
>  fs/ceph/addr.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c
> index 0a86f672cc09..dac2b0ae7d37 100644
> --- a/fs/ceph/addr.c
> +++ b/fs/ceph/addr.c
> @@ -790,6 +790,7 @@ static int write_folio_nounlock(struct folio
> *folio,
>  				    ceph_wbc.truncate_size, true);
>  	if (IS_ERR(req)) {
>  		folio_redirty_for_writepage(wbc, folio);
> +		atomic_long_dec(&fsc->writeback_count);
>  		return PTR_ERR(req);
>  	}
>  
> @@ -809,6 +810,7 @@ static int write_folio_nounlock(struct folio
> *folio,
>  			folio_redirty_for_writepage(wbc, folio);
>  			folio_end_writeback(folio);
>  			ceph_osdc_put_request(req);
> +			atomic_long_dec(&fsc->writeback_count);
>  			return PTR_ERR(bounce_page);
>  		}
>  	}
> @@ -847,6 +849,7 @@ static int write_folio_nounlock(struct folio
> *folio,
>  			      ceph_vinop(inode), folio);
>  			folio_redirty_for_writepage(wbc, folio);
>  			folio_end_writeback(folio);
> +			atomic_long_dec(&fsc->writeback_count);
>  			return err;
>  		}
>  		if (err == -EBLOCKLISTED)

Maybe, I am missing something. But I have the feeling that we already
received likewise patch and we've discussed this solution. As I
remember correctly, I recommended to use this pattern:

	if (atomic_long_dec_return(&fsc->writeback_count) <
	    CONGESTION_OFF_THRESH(fsc->mount_options->congestion_kb))
		fsc->write_congested = false;

Thanks,
Slava.
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.