[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)
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.