diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 78 |
1 files changed, 53 insertions, 25 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 33a28bfde158..4ef24a397684 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -555,11 +555,12 @@ repeat: | |||
555 | page_cache_get(page); | 555 | page_cache_get(page); |
556 | if (TestSetPageLocked(page)) { | 556 | if (TestSetPageLocked(page)) { |
557 | read_unlock_irq(&mapping->tree_lock); | 557 | read_unlock_irq(&mapping->tree_lock); |
558 | lock_page(page); | 558 | __lock_page(page); |
559 | read_lock_irq(&mapping->tree_lock); | 559 | read_lock_irq(&mapping->tree_lock); |
560 | 560 | ||
561 | /* Has the page been truncated while we slept? */ | 561 | /* Has the page been truncated while we slept? */ |
562 | if (page->mapping != mapping || page->index != offset) { | 562 | if (unlikely(page->mapping != mapping || |
563 | page->index != offset)) { | ||
563 | unlock_page(page); | 564 | unlock_page(page); |
564 | page_cache_release(page); | 565 | page_cache_release(page); |
565 | goto repeat; | 566 | goto repeat; |
@@ -831,8 +832,13 @@ readpage: | |||
831 | /* Start the actual read. The read will unlock the page. */ | 832 | /* Start the actual read. The read will unlock the page. */ |
832 | error = mapping->a_ops->readpage(filp, page); | 833 | error = mapping->a_ops->readpage(filp, page); |
833 | 834 | ||
834 | if (unlikely(error)) | 835 | if (unlikely(error)) { |
836 | if (error == AOP_TRUNCATED_PAGE) { | ||
837 | page_cache_release(page); | ||
838 | goto find_page; | ||
839 | } | ||
835 | goto readpage_error; | 840 | goto readpage_error; |
841 | } | ||
836 | 842 | ||
837 | if (!PageUptodate(page)) { | 843 | if (!PageUptodate(page)) { |
838 | lock_page(page); | 844 | lock_page(page); |
@@ -1152,26 +1158,24 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset) | |||
1152 | { | 1158 | { |
1153 | struct address_space *mapping = file->f_mapping; | 1159 | struct address_space *mapping = file->f_mapping; |
1154 | struct page *page; | 1160 | struct page *page; |
1155 | int error; | 1161 | int ret; |
1156 | 1162 | ||
1157 | page = page_cache_alloc_cold(mapping); | 1163 | do { |
1158 | if (!page) | 1164 | page = page_cache_alloc_cold(mapping); |
1159 | return -ENOMEM; | 1165 | if (!page) |
1166 | return -ENOMEM; | ||
1167 | |||
1168 | ret = add_to_page_cache_lru(page, mapping, offset, GFP_KERNEL); | ||
1169 | if (ret == 0) | ||
1170 | ret = mapping->a_ops->readpage(file, page); | ||
1171 | else if (ret == -EEXIST) | ||
1172 | ret = 0; /* losing race to add is OK */ | ||
1160 | 1173 | ||
1161 | error = add_to_page_cache_lru(page, mapping, offset, GFP_KERNEL); | ||
1162 | if (!error) { | ||
1163 | error = mapping->a_ops->readpage(file, page); | ||
1164 | page_cache_release(page); | 1174 | page_cache_release(page); |
1165 | return error; | ||
1166 | } | ||
1167 | 1175 | ||
1168 | /* | 1176 | } while (ret == AOP_TRUNCATED_PAGE); |
1169 | * We arrive here in the unlikely event that someone | 1177 | |
1170 | * raced with us and added our page to the cache first | 1178 | return ret; |
1171 | * or we are out of memory for radix-tree nodes. | ||
1172 | */ | ||
1173 | page_cache_release(page); | ||
1174 | return error == -EEXIST ? 0 : error; | ||
1175 | } | 1179 | } |
1176 | 1180 | ||
1177 | #define MMAP_LOTSAMISS (100) | 1181 | #define MMAP_LOTSAMISS (100) |
@@ -1331,10 +1335,14 @@ page_not_uptodate: | |||
1331 | goto success; | 1335 | goto success; |
1332 | } | 1336 | } |
1333 | 1337 | ||
1334 | if (!mapping->a_ops->readpage(file, page)) { | 1338 | error = mapping->a_ops->readpage(file, page); |
1339 | if (!error) { | ||
1335 | wait_on_page_locked(page); | 1340 | wait_on_page_locked(page); |
1336 | if (PageUptodate(page)) | 1341 | if (PageUptodate(page)) |
1337 | goto success; | 1342 | goto success; |
1343 | } else if (error == AOP_TRUNCATED_PAGE) { | ||
1344 | page_cache_release(page); | ||
1345 | goto retry_find; | ||
1338 | } | 1346 | } |
1339 | 1347 | ||
1340 | /* | 1348 | /* |
@@ -1358,10 +1366,14 @@ page_not_uptodate: | |||
1358 | goto success; | 1366 | goto success; |
1359 | } | 1367 | } |
1360 | ClearPageError(page); | 1368 | ClearPageError(page); |
1361 | if (!mapping->a_ops->readpage(file, page)) { | 1369 | error = mapping->a_ops->readpage(file, page); |
1370 | if (!error) { | ||
1362 | wait_on_page_locked(page); | 1371 | wait_on_page_locked(page); |
1363 | if (PageUptodate(page)) | 1372 | if (PageUptodate(page)) |
1364 | goto success; | 1373 | goto success; |
1374 | } else if (error == AOP_TRUNCATED_PAGE) { | ||
1375 | page_cache_release(page); | ||
1376 | goto retry_find; | ||
1365 | } | 1377 | } |
1366 | 1378 | ||
1367 | /* | 1379 | /* |
@@ -1444,10 +1456,14 @@ page_not_uptodate: | |||
1444 | goto success; | 1456 | goto success; |
1445 | } | 1457 | } |
1446 | 1458 | ||
1447 | if (!mapping->a_ops->readpage(file, page)) { | 1459 | error = mapping->a_ops->readpage(file, page); |
1460 | if (!error) { | ||
1448 | wait_on_page_locked(page); | 1461 | wait_on_page_locked(page); |
1449 | if (PageUptodate(page)) | 1462 | if (PageUptodate(page)) |
1450 | goto success; | 1463 | goto success; |
1464 | } else if (error == AOP_TRUNCATED_PAGE) { | ||
1465 | page_cache_release(page); | ||
1466 | goto retry_find; | ||
1451 | } | 1467 | } |
1452 | 1468 | ||
1453 | /* | 1469 | /* |
@@ -1470,10 +1486,14 @@ page_not_uptodate: | |||
1470 | } | 1486 | } |
1471 | 1487 | ||
1472 | ClearPageError(page); | 1488 | ClearPageError(page); |
1473 | if (!mapping->a_ops->readpage(file, page)) { | 1489 | error = mapping->a_ops->readpage(file, page); |
1490 | if (!error) { | ||
1474 | wait_on_page_locked(page); | 1491 | wait_on_page_locked(page); |
1475 | if (PageUptodate(page)) | 1492 | if (PageUptodate(page)) |
1476 | goto success; | 1493 | goto success; |
1494 | } else if (error == AOP_TRUNCATED_PAGE) { | ||
1495 | page_cache_release(page); | ||
1496 | goto retry_find; | ||
1477 | } | 1497 | } |
1478 | 1498 | ||
1479 | /* | 1499 | /* |
@@ -1934,12 +1954,16 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | |||
1934 | status = a_ops->prepare_write(file, page, offset, offset+bytes); | 1954 | status = a_ops->prepare_write(file, page, offset, offset+bytes); |
1935 | if (unlikely(status)) { | 1955 | if (unlikely(status)) { |
1936 | loff_t isize = i_size_read(inode); | 1956 | loff_t isize = i_size_read(inode); |
1957 | |||
1958 | if (status != AOP_TRUNCATED_PAGE) | ||
1959 | unlock_page(page); | ||
1960 | page_cache_release(page); | ||
1961 | if (status == AOP_TRUNCATED_PAGE) | ||
1962 | continue; | ||
1937 | /* | 1963 | /* |
1938 | * prepare_write() may have instantiated a few blocks | 1964 | * prepare_write() may have instantiated a few blocks |
1939 | * outside i_size. Trim these off again. | 1965 | * outside i_size. Trim these off again. |
1940 | */ | 1966 | */ |
1941 | unlock_page(page); | ||
1942 | page_cache_release(page); | ||
1943 | if (pos + bytes > isize) | 1967 | if (pos + bytes > isize) |
1944 | vmtruncate(inode, isize); | 1968 | vmtruncate(inode, isize); |
1945 | break; | 1969 | break; |
@@ -1952,6 +1976,10 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, | |||
1952 | cur_iov, iov_base, bytes); | 1976 | cur_iov, iov_base, bytes); |
1953 | flush_dcache_page(page); | 1977 | flush_dcache_page(page); |
1954 | status = a_ops->commit_write(file, page, offset, offset+bytes); | 1978 | status = a_ops->commit_write(file, page, offset, offset+bytes); |
1979 | if (status == AOP_TRUNCATED_PAGE) { | ||
1980 | page_cache_release(page); | ||
1981 | continue; | ||
1982 | } | ||
1955 | if (likely(copied > 0)) { | 1983 | if (likely(copied > 0)) { |
1956 | if (!status) | 1984 | if (!status) |
1957 | status = copied; | 1985 | status = copied; |