diff options
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 3d4df44e4221..75572b5f2374 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -612,6 +612,19 @@ void __lock_page_nosync(struct page *page) | |||
612 | TASK_UNINTERRUPTIBLE); | 612 | TASK_UNINTERRUPTIBLE); |
613 | } | 613 | } |
614 | 614 | ||
615 | int __lock_page_or_retry(struct page *page, struct mm_struct *mm, | ||
616 | unsigned int flags) | ||
617 | { | ||
618 | if (!(flags & FAULT_FLAG_ALLOW_RETRY)) { | ||
619 | __lock_page(page); | ||
620 | return 1; | ||
621 | } else { | ||
622 | up_read(&mm->mmap_sem); | ||
623 | wait_on_page_locked(page); | ||
624 | return 0; | ||
625 | } | ||
626 | } | ||
627 | |||
615 | /** | 628 | /** |
616 | * find_get_page - find and get a page reference | 629 | * find_get_page - find and get a page reference |
617 | * @mapping: the address_space to search | 630 | * @mapping: the address_space to search |
@@ -1539,25 +1552,28 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1539 | * waiting for the lock. | 1552 | * waiting for the lock. |
1540 | */ | 1553 | */ |
1541 | do_async_mmap_readahead(vma, ra, file, page, offset); | 1554 | do_async_mmap_readahead(vma, ra, file, page, offset); |
1542 | lock_page(page); | ||
1543 | |||
1544 | /* Did it get truncated? */ | ||
1545 | if (unlikely(page->mapping != mapping)) { | ||
1546 | unlock_page(page); | ||
1547 | put_page(page); | ||
1548 | goto no_cached_page; | ||
1549 | } | ||
1550 | } else { | 1555 | } else { |
1551 | /* No page in the page cache at all */ | 1556 | /* No page in the page cache at all */ |
1552 | do_sync_mmap_readahead(vma, ra, file, offset); | 1557 | do_sync_mmap_readahead(vma, ra, file, offset); |
1553 | count_vm_event(PGMAJFAULT); | 1558 | count_vm_event(PGMAJFAULT); |
1554 | ret = VM_FAULT_MAJOR; | 1559 | ret = VM_FAULT_MAJOR; |
1555 | retry_find: | 1560 | retry_find: |
1556 | page = find_lock_page(mapping, offset); | 1561 | page = find_get_page(mapping, offset); |
1557 | if (!page) | 1562 | if (!page) |
1558 | goto no_cached_page; | 1563 | goto no_cached_page; |
1559 | } | 1564 | } |
1560 | 1565 | ||
1566 | if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) | ||
1567 | return ret | VM_FAULT_RETRY; | ||
1568 | |||
1569 | /* Did it get truncated? */ | ||
1570 | if (unlikely(page->mapping != mapping)) { | ||
1571 | unlock_page(page); | ||
1572 | put_page(page); | ||
1573 | goto retry_find; | ||
1574 | } | ||
1575 | VM_BUG_ON(page->index != offset); | ||
1576 | |||
1561 | /* | 1577 | /* |
1562 | * We have a locked page in the page cache, now we need to check | 1578 | * We have a locked page in the page cache, now we need to check |
1563 | * that it's up-to-date. If not, it is going to be due to an error. | 1579 | * that it's up-to-date. If not, it is going to be due to an error. |
@@ -2177,12 +2193,12 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
2177 | } | 2193 | } |
2178 | 2194 | ||
2179 | if (written > 0) { | 2195 | if (written > 0) { |
2180 | loff_t end = pos + written; | 2196 | pos += written; |
2181 | if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { | 2197 | if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { |
2182 | i_size_write(inode, end); | 2198 | i_size_write(inode, pos); |
2183 | mark_inode_dirty(inode); | 2199 | mark_inode_dirty(inode); |
2184 | } | 2200 | } |
2185 | *ppos = end; | 2201 | *ppos = pos; |
2186 | } | 2202 | } |
2187 | out: | 2203 | out: |
2188 | return written; | 2204 | return written; |