| From 688878e2ddfa186f04a1aea90ae8db7e09d9c296 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 22 Oct 2020 14:03:03 +0100 |
| Subject: afs: Fix page leak on afs_write_begin() failure |
| |
| From: David Howells <dhowells@redhat.com> |
| |
| [ Upstream commit 21db2cdc667f744691a407105b7712bc18d74023 ] |
| |
| Fix the leak of the target page in afs_write_begin() when it fails. |
| |
| Fixes: 15b4650e55e0 ("afs: convert to new aops") |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| cc: Nick Piggin <npiggin@gmail.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/afs/write.c | 23 +++++++++++------------ |
| 1 file changed, 11 insertions(+), 12 deletions(-) |
| |
| diff --git a/fs/afs/write.c b/fs/afs/write.c |
| index 02facb19a0f1d..7fae9f8b38eb3 100644 |
| --- a/fs/afs/write.c |
| +++ b/fs/afs/write.c |
| @@ -76,7 +76,7 @@ static int afs_fill_page(struct afs_vnode *vnode, struct key *key, |
| */ |
| int afs_write_begin(struct file *file, struct address_space *mapping, |
| loff_t pos, unsigned len, unsigned flags, |
| - struct page **pagep, void **fsdata) |
| + struct page **_page, void **fsdata) |
| { |
| struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); |
| struct page *page; |
| @@ -110,9 +110,6 @@ int afs_write_begin(struct file *file, struct address_space *mapping, |
| SetPageUptodate(page); |
| } |
| |
| - /* page won't leak in error case: it eventually gets cleaned off LRU */ |
| - *pagep = page; |
| - |
| try_again: |
| /* See if this page is already partially written in a way that we can |
| * merge the new write with. |
| @@ -155,6 +152,7 @@ try_again: |
| set_page_private(page, priv); |
| else |
| attach_page_private(page, (void *)priv); |
| + *_page = page; |
| _leave(" = 0"); |
| return 0; |
| |
| @@ -164,17 +162,18 @@ try_again: |
| flush_conflicting_write: |
| _debug("flush conflict"); |
| ret = write_one_page(page); |
| - if (ret < 0) { |
| - _leave(" = %d", ret); |
| - return ret; |
| - } |
| + if (ret < 0) |
| + goto error; |
| |
| ret = lock_page_killable(page); |
| - if (ret < 0) { |
| - _leave(" = %d", ret); |
| - return ret; |
| - } |
| + if (ret < 0) |
| + goto error; |
| goto try_again; |
| + |
| +error: |
| + put_page(page); |
| + _leave(" = %d", ret); |
| + return ret; |
| } |
| |
| /* |
| -- |
| 2.27.0 |
| |