diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 53 |
1 files changed, 20 insertions, 33 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 5d5449f3d41c..462cda58a18e 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -1325,9 +1325,10 @@ struct page *filemap_nopage(struct vm_area_struct *area, | |||
1325 | unsigned long size, pgoff; | 1325 | unsigned long size, pgoff; |
1326 | int did_readaround = 0, majmin = VM_FAULT_MINOR; | 1326 | int did_readaround = 0, majmin = VM_FAULT_MINOR; |
1327 | 1327 | ||
1328 | BUG_ON(!(area->vm_flags & VM_CAN_INVALIDATE)); | ||
1329 | |||
1328 | pgoff = ((address-area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; | 1330 | pgoff = ((address-area->vm_start) >> PAGE_CACHE_SHIFT) + area->vm_pgoff; |
1329 | 1331 | ||
1330 | retry_all: | ||
1331 | size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 1332 | size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
1332 | if (pgoff >= size) | 1333 | if (pgoff >= size) |
1333 | goto outside_data_content; | 1334 | goto outside_data_content; |
@@ -1349,7 +1350,7 @@ retry_all: | |||
1349 | * Do we have something in the page cache already? | 1350 | * Do we have something in the page cache already? |
1350 | */ | 1351 | */ |
1351 | retry_find: | 1352 | retry_find: |
1352 | page = find_get_page(mapping, pgoff); | 1353 | page = find_lock_page(mapping, pgoff); |
1353 | if (!page) { | 1354 | if (!page) { |
1354 | unsigned long ra_pages; | 1355 | unsigned long ra_pages; |
1355 | 1356 | ||
@@ -1383,7 +1384,7 @@ retry_find: | |||
1383 | start = pgoff - ra_pages / 2; | 1384 | start = pgoff - ra_pages / 2; |
1384 | do_page_cache_readahead(mapping, file, start, ra_pages); | 1385 | do_page_cache_readahead(mapping, file, start, ra_pages); |
1385 | } | 1386 | } |
1386 | page = find_get_page(mapping, pgoff); | 1387 | page = find_lock_page(mapping, pgoff); |
1387 | if (!page) | 1388 | if (!page) |
1388 | goto no_cached_page; | 1389 | goto no_cached_page; |
1389 | } | 1390 | } |
@@ -1392,13 +1393,19 @@ retry_find: | |||
1392 | ra->mmap_hit++; | 1393 | ra->mmap_hit++; |
1393 | 1394 | ||
1394 | /* | 1395 | /* |
1395 | * Ok, found a page in the page cache, now we need to check | 1396 | * We have a locked page in the page cache, now we need to check |
1396 | * that it's up-to-date. | 1397 | * that it's up-to-date. If not, it is going to be due to an error. |
1397 | */ | 1398 | */ |
1398 | if (!PageUptodate(page)) | 1399 | if (unlikely(!PageUptodate(page))) |
1399 | goto page_not_uptodate; | 1400 | goto page_not_uptodate; |
1400 | 1401 | ||
1401 | success: | 1402 | /* Must recheck i_size under page lock */ |
1403 | size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
1404 | if (unlikely(pgoff >= size)) { | ||
1405 | unlock_page(page); | ||
1406 | goto outside_data_content; | ||
1407 | } | ||
1408 | |||
1402 | /* | 1409 | /* |
1403 | * Found the page and have a reference on it. | 1410 | * Found the page and have a reference on it. |
1404 | */ | 1411 | */ |
@@ -1440,6 +1447,7 @@ no_cached_page: | |||
1440 | return NOPAGE_SIGBUS; | 1447 | return NOPAGE_SIGBUS; |
1441 | 1448 | ||
1442 | page_not_uptodate: | 1449 | page_not_uptodate: |
1450 | /* IO error path */ | ||
1443 | if (!did_readaround) { | 1451 | if (!did_readaround) { |
1444 | majmin = VM_FAULT_MAJOR; | 1452 | majmin = VM_FAULT_MAJOR; |
1445 | count_vm_event(PGMAJFAULT); | 1453 | count_vm_event(PGMAJFAULT); |
@@ -1451,37 +1459,15 @@ page_not_uptodate: | |||
1451 | * because there really aren't any performance issues here | 1459 | * because there really aren't any performance issues here |
1452 | * and we need to check for errors. | 1460 | * and we need to check for errors. |
1453 | */ | 1461 | */ |
1454 | lock_page(page); | ||
1455 | |||
1456 | /* Somebody truncated the page on us? */ | ||
1457 | if (!page->mapping) { | ||
1458 | unlock_page(page); | ||
1459 | page_cache_release(page); | ||
1460 | goto retry_all; | ||
1461 | } | ||
1462 | |||
1463 | /* Somebody else successfully read it in? */ | ||
1464 | if (PageUptodate(page)) { | ||
1465 | unlock_page(page); | ||
1466 | goto success; | ||
1467 | } | ||
1468 | ClearPageError(page); | 1462 | ClearPageError(page); |
1469 | error = mapping->a_ops->readpage(file, page); | 1463 | error = mapping->a_ops->readpage(file, page); |
1470 | if (!error) { | 1464 | page_cache_release(page); |
1471 | wait_on_page_locked(page); | 1465 | |
1472 | if (PageUptodate(page)) | 1466 | if (!error || error == AOP_TRUNCATED_PAGE) |
1473 | goto success; | ||
1474 | } else if (error == AOP_TRUNCATED_PAGE) { | ||
1475 | page_cache_release(page); | ||
1476 | goto retry_find; | 1467 | goto retry_find; |
1477 | } | ||
1478 | 1468 | ||
1479 | /* | 1469 | /* Things didn't work out. Return zero to tell the mm layer so. */ |
1480 | * Things didn't work out. Return zero to tell the | ||
1481 | * mm layer so, possibly freeing the page cache page first. | ||
1482 | */ | ||
1483 | shrink_readahead_size_eio(file, ra); | 1470 | shrink_readahead_size_eio(file, ra); |
1484 | page_cache_release(page); | ||
1485 | return NOPAGE_SIGBUS; | 1471 | return NOPAGE_SIGBUS; |
1486 | } | 1472 | } |
1487 | EXPORT_SYMBOL(filemap_nopage); | 1473 | EXPORT_SYMBOL(filemap_nopage); |
@@ -1674,6 +1660,7 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
1674 | return -ENOEXEC; | 1660 | return -ENOEXEC; |
1675 | file_accessed(file); | 1661 | file_accessed(file); |
1676 | vma->vm_ops = &generic_file_vm_ops; | 1662 | vma->vm_ops = &generic_file_vm_ops; |
1663 | vma->vm_flags |= VM_CAN_INVALIDATE; | ||
1677 | return 0; | 1664 | return 0; |
1678 | } | 1665 | } |
1679 | 1666 | ||