summaryrefslogtreecommitdiff
path: root/mm
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 /mm
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.
Diffstat (limited to 'mm')
-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;