Commit fa04a40b authored by David Howells's avatar David Howells

afs: Fix to take ref on page when PG_private is set

Fix afs to take a ref on a page when it sets PG_private on it and to drop
the ref when removing the flag.

Note that in afs_write_begin(), a lot of the time, PG_private is already
set on a page to which we're going to add some data.  In such a case, we
leave the bit set and mustn't increment the page count.

As suggested by Matthew Wilcox, use attach/detach_page_private() where
possible.

Fixes: 31143d5d ("AFS: implement basic file write support")
Reported-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
Reviewed-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
parent d383e346
...@@ -281,8 +281,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key) ...@@ -281,8 +281,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
if (ret < 0) if (ret < 0)
goto error; goto error;
set_page_private(req->pages[i], 1); attach_page_private(req->pages[i], (void *)1);
SetPagePrivate(req->pages[i]);
unlock_page(req->pages[i]); unlock_page(req->pages[i]);
i++; i++;
} else { } else {
...@@ -1975,8 +1974,7 @@ static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags) ...@@ -1975,8 +1974,7 @@ static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags)
_enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index); _enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index);
set_page_private(page, 0); detach_page_private(page);
ClearPagePrivate(page);
/* The directory will need reloading. */ /* The directory will need reloading. */
if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags)) if (test_and_clear_bit(AFS_VNODE_DIR_VALID, &dvnode->flags))
...@@ -2003,8 +2001,6 @@ static void afs_dir_invalidatepage(struct page *page, unsigned int offset, ...@@ -2003,8 +2001,6 @@ static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
afs_stat_v(dvnode, n_inval); afs_stat_v(dvnode, n_inval);
/* we clean up only if the entire page is being invalidated */ /* we clean up only if the entire page is being invalidated */
if (offset == 0 && length == PAGE_SIZE) { if (offset == 0 && length == PAGE_SIZE)
set_page_private(page, 0); detach_page_private(page);
ClearPagePrivate(page);
}
} }
...@@ -243,10 +243,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode, ...@@ -243,10 +243,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
index, gfp); index, gfp);
if (!page) if (!page)
goto error; goto error;
if (!PagePrivate(page)) { if (!PagePrivate(page))
set_page_private(page, 1); attach_page_private(page, (void *)1);
SetPagePrivate(page);
}
dir_page = kmap(page); dir_page = kmap(page);
} }
......
...@@ -627,11 +627,9 @@ static void afs_invalidatepage(struct page *page, unsigned int offset, ...@@ -627,11 +627,9 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
#endif #endif
if (PagePrivate(page)) { if (PagePrivate(page)) {
priv = page_private(page); priv = (unsigned long)detach_page_private(page);
trace_afs_page_dirty(vnode, tracepoint_string("inval"), trace_afs_page_dirty(vnode, tracepoint_string("inval"),
page->index, priv); page->index, priv);
set_page_private(page, 0);
ClearPagePrivate(page);
} }
} }
...@@ -661,11 +659,9 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags) ...@@ -661,11 +659,9 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
#endif #endif
if (PagePrivate(page)) { if (PagePrivate(page)) {
priv = page_private(page); priv = (unsigned long)detach_page_private(page);
trace_afs_page_dirty(vnode, tracepoint_string("rel"), trace_afs_page_dirty(vnode, tracepoint_string("rel"),
page->index, priv); page->index, priv);
set_page_private(page, 0);
ClearPagePrivate(page);
} }
/* indicate that the page can be released */ /* indicate that the page can be released */
......
...@@ -151,8 +151,10 @@ int afs_write_begin(struct file *file, struct address_space *mapping, ...@@ -151,8 +151,10 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
priv |= f; priv |= f;
trace_afs_page_dirty(vnode, tracepoint_string("begin"), trace_afs_page_dirty(vnode, tracepoint_string("begin"),
page->index, priv); page->index, priv);
SetPagePrivate(page); if (PagePrivate(page))
set_page_private(page, priv); set_page_private(page, priv);
else
attach_page_private(page, (void *)priv);
_leave(" = 0"); _leave(" = 0");
return 0; return 0;
...@@ -334,10 +336,9 @@ static void afs_pages_written_back(struct afs_vnode *vnode, ...@@ -334,10 +336,9 @@ static void afs_pages_written_back(struct afs_vnode *vnode,
ASSERTCMP(pv.nr, ==, count); ASSERTCMP(pv.nr, ==, count);
for (loop = 0; loop < count; loop++) { for (loop = 0; loop < count; loop++) {
priv = page_private(pv.pages[loop]); priv = (unsigned long)detach_page_private(pv.pages[loop]);
trace_afs_page_dirty(vnode, tracepoint_string("clear"), trace_afs_page_dirty(vnode, tracepoint_string("clear"),
pv.pages[loop]->index, priv); pv.pages[loop]->index, priv);
set_page_private(pv.pages[loop], 0);
end_page_writeback(pv.pages[loop]); end_page_writeback(pv.pages[loop]);
} }
first += count; first += count;
...@@ -863,8 +864,10 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) ...@@ -863,8 +864,10 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
priv |= 0; /* From */ priv |= 0; /* From */
trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"), trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"),
vmf->page->index, priv); vmf->page->index, priv);
SetPagePrivate(vmf->page); if (PagePrivate(vmf->page))
set_page_private(vmf->page, priv); set_page_private(vmf->page, priv);
else
attach_page_private(vmf->page, (void *)priv);
file_update_time(file); file_update_time(file);
sb_end_pagefault(inode->i_sb); sb_end_pagefault(inode->i_sb);
...@@ -926,10 +929,9 @@ int afs_launder_page(struct page *page) ...@@ -926,10 +929,9 @@ int afs_launder_page(struct page *page)
ret = afs_store_data(mapping, page->index, page->index, t, f, true); ret = afs_store_data(mapping, page->index, page->index, t, f, true);
} }
priv = (unsigned long)detach_page_private(page);
trace_afs_page_dirty(vnode, tracepoint_string("laundered"), trace_afs_page_dirty(vnode, tracepoint_string("laundered"),
page->index, priv); page->index, priv);
set_page_private(page, 0);
ClearPagePrivate(page);
#ifdef CONFIG_AFS_FSCACHE #ifdef CONFIG_AFS_FSCACHE
if (PageFsCache(page)) { if (PageFsCache(page)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment