mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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: 31143d5d51
("AFS: implement basic file write support")
Reported-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: David Howells <dhowells@redhat.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
This commit is contained in:
parent
d383e346f9
commit
fa04a40b16
12
fs/afs/dir.c
12
fs/afs/dir.c
@ -281,8 +281,7 @@ retry:
|
||||
if (ret < 0)
|
||||
goto error;
|
||||
|
||||
set_page_private(req->pages[i], 1);
|
||||
SetPagePrivate(req->pages[i]);
|
||||
attach_page_private(req->pages[i], (void *)1);
|
||||
unlock_page(req->pages[i]);
|
||||
i++;
|
||||
} else {
|
||||
@ -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);
|
||||
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
detach_page_private(page);
|
||||
|
||||
/* The directory will need reloading. */
|
||||
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,
|
||||
afs_stat_v(dvnode, n_inval);
|
||||
|
||||
/* we clean up only if the entire page is being invalidated */
|
||||
if (offset == 0 && length == PAGE_SIZE) {
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
}
|
||||
if (offset == 0 && length == PAGE_SIZE)
|
||||
detach_page_private(page);
|
||||
}
|
||||
|
@ -243,10 +243,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
|
||||
index, gfp);
|
||||
if (!page)
|
||||
goto error;
|
||||
if (!PagePrivate(page)) {
|
||||
set_page_private(page, 1);
|
||||
SetPagePrivate(page);
|
||||
}
|
||||
if (!PagePrivate(page))
|
||||
attach_page_private(page, (void *)1);
|
||||
dir_page = kmap(page);
|
||||
}
|
||||
|
||||
|
@ -627,11 +627,9 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
|
||||
#endif
|
||||
|
||||
if (PagePrivate(page)) {
|
||||
priv = page_private(page);
|
||||
priv = (unsigned long)detach_page_private(page);
|
||||
trace_afs_page_dirty(vnode, tracepoint_string("inval"),
|
||||
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)
|
||||
#endif
|
||||
|
||||
if (PagePrivate(page)) {
|
||||
priv = page_private(page);
|
||||
priv = (unsigned long)detach_page_private(page);
|
||||
trace_afs_page_dirty(vnode, tracepoint_string("rel"),
|
||||
page->index, priv);
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
}
|
||||
|
||||
/* indicate that the page can be released */
|
||||
|
@ -151,8 +151,10 @@ try_again:
|
||||
priv |= f;
|
||||
trace_afs_page_dirty(vnode, tracepoint_string("begin"),
|
||||
page->index, priv);
|
||||
SetPagePrivate(page);
|
||||
set_page_private(page, priv);
|
||||
if (PagePrivate(page))
|
||||
set_page_private(page, priv);
|
||||
else
|
||||
attach_page_private(page, (void *)priv);
|
||||
_leave(" = 0");
|
||||
return 0;
|
||||
|
||||
@ -334,10 +336,9 @@ static void afs_pages_written_back(struct afs_vnode *vnode,
|
||||
ASSERTCMP(pv.nr, ==, count);
|
||||
|
||||
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"),
|
||||
pv.pages[loop]->index, priv);
|
||||
set_page_private(pv.pages[loop], 0);
|
||||
end_page_writeback(pv.pages[loop]);
|
||||
}
|
||||
first += count;
|
||||
@ -863,8 +864,10 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
|
||||
priv |= 0; /* From */
|
||||
trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"),
|
||||
vmf->page->index, priv);
|
||||
SetPagePrivate(vmf->page);
|
||||
set_page_private(vmf->page, priv);
|
||||
if (PagePrivate(vmf->page))
|
||||
set_page_private(vmf->page, priv);
|
||||
else
|
||||
attach_page_private(vmf->page, (void *)priv);
|
||||
file_update_time(file);
|
||||
|
||||
sb_end_pagefault(inode->i_sb);
|
||||
@ -926,10 +929,9 @@ int afs_launder_page(struct page *page)
|
||||
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"),
|
||||
page->index, priv);
|
||||
set_page_private(page, 0);
|
||||
ClearPagePrivate(page);
|
||||
|
||||
#ifdef CONFIG_AFS_FSCACHE
|
||||
if (PageFsCache(page)) {
|
||||
|
Loading…
Reference in New Issue
Block a user