summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Morton <akpm@zip.com.au>2002-07-04 08:31:56 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-07-04 08:31:56 -0700
commitea66b69c3ec03a6762c0949af67123d8a278f49d (patch)
treeed3bb16144de5a0ff2fe93eac9239304d9ef5786
parent8b00e4fac18298dce49b78d25c5ea2399aeb6fa2 (diff)
[PATCH] fix invalidate_inode_pages2() race
Fix a buglet in invalidate_list_pages2(): there is a small window in which writeback could start against the page before this function locks it. The patch closes the race by performing the PageWriteback test inside PageLocked. Testing PageWriteback inside PageLocked is "definitive" - when a page is locked, writeback cannot start against it.
-rw-r--r--mm/filemap.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/mm/filemap.c b/mm/filemap.c
index bcbe3e71e0ef..319392662ab5 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -367,16 +367,18 @@ static int invalidate_list_pages2(struct address_space * mapping,
while (curr != head) {
page = list_entry(curr, struct page, list);
- if (PageWriteback(page)) {
- write_unlock(&mapping->page_lock);
- wait_on_page_writeback(page);
- unlocked = 1;
- write_lock(&mapping->page_lock);
- goto restart;
- }
if (!TestSetPageLocked(page)) {
int __unlocked;
+ if (PageWriteback(page)) {
+ write_unlock(&mapping->page_lock);
+ wait_on_page_writeback(page);
+ unlocked = 1;
+ write_lock(&mapping->page_lock);
+ unlock_page(page);
+ goto restart;
+ }
+
__unlocked = invalidate_this_page2(mapping, page, curr, head);
unlock_page(page);
unlocked |= __unlocked;