[PATCH] ceph: fix refcount leak in write_folio_nounlock()
WenTao Liang <[email protected]>
| Newsgroups | org.kernel.vger.ceph-devel,org.kernel.vger.linux-kernel,org.kernel.vger.stable |
|---|---|
| Message-ID | <[email protected]> |
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) -- 2.50.1 (Apple Git-155)