diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/filemap.c | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index deae0b9ad90b..4a0f5fa79dbd 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1668,6 +1668,15 @@ find_page: | |||
1668 | index, last_index - index); | 1668 | index, last_index - index); |
1669 | } | 1669 | } |
1670 | if (!PageUptodate(page)) { | 1670 | if (!PageUptodate(page)) { |
1671 | /* | ||
1672 | * See comment in do_read_cache_page on why | ||
1673 | * wait_on_page_locked is used to avoid unnecessarily | ||
1674 | * serialisations and why it's safe. | ||
1675 | */ | ||
1676 | wait_on_page_locked_killable(page); | ||
1677 | if (PageUptodate(page)) | ||
1678 | goto page_ok; | ||
1679 | |||
1671 | if (inode->i_blkbits == PAGE_CACHE_SHIFT || | 1680 | if (inode->i_blkbits == PAGE_CACHE_SHIFT || |
1672 | !mapping->a_ops->is_partially_uptodate) | 1681 | !mapping->a_ops->is_partially_uptodate) |
1673 | goto page_not_up_to_date; | 1682 | goto page_not_up_to_date; |
@@ -2341,12 +2350,52 @@ filler: | |||
2341 | if (PageUptodate(page)) | 2350 | if (PageUptodate(page)) |
2342 | goto out; | 2351 | goto out; |
2343 | 2352 | ||
2353 | /* | ||
2354 | * Page is not up to date and may be locked due one of the following | ||
2355 | * case a: Page is being filled and the page lock is held | ||
2356 | * case b: Read/write error clearing the page uptodate status | ||
2357 | * case c: Truncation in progress (page locked) | ||
2358 | * case d: Reclaim in progress | ||
2359 | * | ||
2360 | * Case a, the page will be up to date when the page is unlocked. | ||
2361 | * There is no need to serialise on the page lock here as the page | ||
2362 | * is pinned so the lock gives no additional protection. Even if the | ||
2363 | * the page is truncated, the data is still valid if PageUptodate as | ||
2364 | * it's a race vs truncate race. | ||
2365 | * Case b, the page will not be up to date | ||
2366 | * Case c, the page may be truncated but in itself, the data may still | ||
2367 | * be valid after IO completes as it's a read vs truncate race. The | ||
2368 | * operation must restart if the page is not uptodate on unlock but | ||
2369 | * otherwise serialising on page lock to stabilise the mapping gives | ||
2370 | * no additional guarantees to the caller as the page lock is | ||
2371 | * released before return. | ||
2372 | * Case d, similar to truncation. If reclaim holds the page lock, it | ||
2373 | * will be a race with remove_mapping that determines if the mapping | ||
2374 | * is valid on unlock but otherwise the data is valid and there is | ||
2375 | * no need to serialise with page lock. | ||
2376 | * | ||
2377 | * As the page lock gives no additional guarantee, we optimistically | ||
2378 | * wait on the page to be unlocked and check if it's up to date and | ||
2379 | * use the page if it is. Otherwise, the page lock is required to | ||
2380 | * distinguish between the different cases. The motivation is that we | ||
2381 | * avoid spurious serialisations and wakeups when multiple processes | ||
2382 | * wait on the same page for IO to complete. | ||
2383 | */ | ||
2384 | wait_on_page_locked(page); | ||
2385 | if (PageUptodate(page)) | ||
2386 | goto out; | ||
2387 | |||
2388 | /* Distinguish between all the cases under the safety of the lock */ | ||
2344 | lock_page(page); | 2389 | lock_page(page); |
2390 | |||
2391 | /* Case c or d, restart the operation */ | ||
2345 | if (!page->mapping) { | 2392 | if (!page->mapping) { |
2346 | unlock_page(page); | 2393 | unlock_page(page); |
2347 | page_cache_release(page); | 2394 | page_cache_release(page); |
2348 | goto repeat; | 2395 | goto repeat; |
2349 | } | 2396 | } |
2397 | |||
2398 | /* Someone else locked and filled the page in a very small window */ | ||
2350 | if (PageUptodate(page)) { | 2399 | if (PageUptodate(page)) { |
2351 | unlock_page(page); | 2400 | unlock_page(page); |
2352 | goto out; | 2401 | goto out; |