| From e383edb03ba16ca346eabbd4a20efa730f291530 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 26 Oct 2020 14:05:33 +0000 |
| Subject: afs: Fix where page->private is set during write |
| |
| From: David Howells <dhowells@redhat.com> |
| |
| [ Upstream commit f792e3ac82fe2c6c863e93187eb7ddfccab68fa7 ] |
| |
| In afs, page->private is set to indicate the dirty region of a page. This |
| is done in afs_write_begin(), but that can't take account of whether the |
| copy into the page actually worked. |
| |
| Fix this by moving the change of page->private into afs_write_end(). |
| |
| Fixes: 4343d00872e1 ("afs: Get rid of the afs_writeback record") |
| Signed-off-by: David Howells <dhowells@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| fs/afs/write.c | 41 ++++++++++++++++++++++++++--------------- |
| 1 file changed, 26 insertions(+), 15 deletions(-) |
| |
| diff --git a/fs/afs/write.c b/fs/afs/write.c |
| index 7fae9f8b38eb3..f28d85c38cd89 100644 |
| --- a/fs/afs/write.c |
| +++ b/fs/afs/write.c |
| @@ -135,23 +135,8 @@ try_again: |
| if (!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags) && |
| (to < f || from > t)) |
| goto flush_conflicting_write; |
| - if (from < f) |
| - f = from; |
| - if (to > t) |
| - t = to; |
| - } else { |
| - f = from; |
| - t = to; |
| } |
| |
| - priv = (unsigned long)t << AFS_PRIV_SHIFT; |
| - priv |= f; |
| - trace_afs_page_dirty(vnode, tracepoint_string("begin"), |
| - page->index, priv); |
| - if (PagePrivate(page)) |
| - set_page_private(page, priv); |
| - else |
| - attach_page_private(page, (void *)priv); |
| *_page = page; |
| _leave(" = 0"); |
| return 0; |
| @@ -185,6 +170,9 @@ int afs_write_end(struct file *file, struct address_space *mapping, |
| { |
| struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); |
| struct key *key = afs_file_key(file); |
| + unsigned long priv; |
| + unsigned int f, from = pos & (PAGE_SIZE - 1); |
| + unsigned int t, to = from + copied; |
| loff_t i_size, maybe_i_size; |
| int ret; |
| |
| @@ -216,6 +204,29 @@ int afs_write_end(struct file *file, struct address_space *mapping, |
| SetPageUptodate(page); |
| } |
| |
| + if (PagePrivate(page)) { |
| + priv = page_private(page); |
| + f = priv & AFS_PRIV_MAX; |
| + t = priv >> AFS_PRIV_SHIFT; |
| + if (from < f) |
| + f = from; |
| + if (to > t) |
| + t = to; |
| + priv = (unsigned long)t << AFS_PRIV_SHIFT; |
| + priv |= f; |
| + set_page_private(page, priv); |
| + trace_afs_page_dirty(vnode, tracepoint_string("dirty+"), |
| + page->index, priv); |
| + } else { |
| + f = from; |
| + t = to; |
| + priv = (unsigned long)t << AFS_PRIV_SHIFT; |
| + priv |= f; |
| + attach_page_private(page, (void *)priv); |
| + trace_afs_page_dirty(vnode, tracepoint_string("dirty"), |
| + page->index, priv); |
| + } |
| + |
| set_page_dirty(page); |
| if (PageDirty(page)) |
| _debug("dirtied"); |
| -- |
| 2.27.0 |
| |