Skip to content

Commit fa04a40

Browse files
committed
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: 31143d5 ("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>
1 parent d383e34 commit fa04a40

4 files changed

Lines changed: 18 additions & 26 deletions

File tree

fs/afs/dir.c

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,8 +281,7 @@ static struct afs_read *afs_read_dir(struct afs_vnode *dvnode, struct key *key)
281281
if (ret < 0)
282282
goto error;
283283

284-
set_page_private(req->pages[i], 1);
285-
SetPagePrivate(req->pages[i]);
284+
attach_page_private(req->pages[i], (void *)1);
286285
unlock_page(req->pages[i]);
287286
i++;
288287
} else {
@@ -1975,8 +1974,7 @@ static int afs_dir_releasepage(struct page *page, gfp_t gfp_flags)
19751974

19761975
_enter("{{%llx:%llu}[%lu]}", dvnode->fid.vid, dvnode->fid.vnode, page->index);
19771976

1978-
set_page_private(page, 0);
1979-
ClearPagePrivate(page);
1977+
detach_page_private(page);
19801978

19811979
/* The directory will need reloading. */
19821980
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,
20032001
afs_stat_v(dvnode, n_inval);
20042002

20052003
/* we clean up only if the entire page is being invalidated */
2006-
if (offset == 0 && length == PAGE_SIZE) {
2007-
set_page_private(page, 0);
2008-
ClearPagePrivate(page);
2009-
}
2004+
if (offset == 0 && length == PAGE_SIZE)
2005+
detach_page_private(page);
20102006
}

fs/afs/dir_edit.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,10 +243,8 @@ void afs_edit_dir_add(struct afs_vnode *vnode,
243243
index, gfp);
244244
if (!page)
245245
goto error;
246-
if (!PagePrivate(page)) {
247-
set_page_private(page, 1);
248-
SetPagePrivate(page);
249-
}
246+
if (!PagePrivate(page))
247+
attach_page_private(page, (void *)1);
250248
dir_page = kmap(page);
251249
}
252250

fs/afs/file.c

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -627,11 +627,9 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
627627
#endif
628628

629629
if (PagePrivate(page)) {
630-
priv = page_private(page);
630+
priv = (unsigned long)detach_page_private(page);
631631
trace_afs_page_dirty(vnode, tracepoint_string("inval"),
632632
page->index, priv);
633-
set_page_private(page, 0);
634-
ClearPagePrivate(page);
635633
}
636634
}
637635

@@ -661,11 +659,9 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
661659
#endif
662660

663661
if (PagePrivate(page)) {
664-
priv = page_private(page);
662+
priv = (unsigned long)detach_page_private(page);
665663
trace_afs_page_dirty(vnode, tracepoint_string("rel"),
666664
page->index, priv);
667-
set_page_private(page, 0);
668-
ClearPagePrivate(page);
669665
}
670666

671667
/* indicate that the page can be released */

fs/afs/write.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,10 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
151151
priv |= f;
152152
trace_afs_page_dirty(vnode, tracepoint_string("begin"),
153153
page->index, priv);
154-
SetPagePrivate(page);
155-
set_page_private(page, priv);
154+
if (PagePrivate(page))
155+
set_page_private(page, priv);
156+
else
157+
attach_page_private(page, (void *)priv);
156158
_leave(" = 0");
157159
return 0;
158160

@@ -334,10 +336,9 @@ static void afs_pages_written_back(struct afs_vnode *vnode,
334336
ASSERTCMP(pv.nr, ==, count);
335337

336338
for (loop = 0; loop < count; loop++) {
337-
priv = page_private(pv.pages[loop]);
339+
priv = (unsigned long)detach_page_private(pv.pages[loop]);
338340
trace_afs_page_dirty(vnode, tracepoint_string("clear"),
339341
pv.pages[loop]->index, priv);
340-
set_page_private(pv.pages[loop], 0);
341342
end_page_writeback(pv.pages[loop]);
342343
}
343344
first += count;
@@ -863,8 +864,10 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
863864
priv |= 0; /* From */
864865
trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"),
865866
vmf->page->index, priv);
866-
SetPagePrivate(vmf->page);
867-
set_page_private(vmf->page, priv);
867+
if (PagePrivate(vmf->page))
868+
set_page_private(vmf->page, priv);
869+
else
870+
attach_page_private(vmf->page, (void *)priv);
868871
file_update_time(file);
869872

870873
sb_end_pagefault(inode->i_sb);
@@ -926,10 +929,9 @@ int afs_launder_page(struct page *page)
926929
ret = afs_store_data(mapping, page->index, page->index, t, f, true);
927930
}
928931

932+
priv = (unsigned long)detach_page_private(page);
929933
trace_afs_page_dirty(vnode, tracepoint_string("laundered"),
930934
page->index, priv);
931-
set_page_private(page, 0);
932-
ClearPagePrivate(page);
933935

934936
#ifdef CONFIG_AFS_FSCACHE
935937
if (PageFsCache(page)) {

0 commit comments

Comments
 (0)