|
@@ -1302,8 +1302,8 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset)
|
|
|
|
|
|
/**
|
|
/**
|
|
* filemap_fault - read in file data for page fault handling
|
|
* filemap_fault - read in file data for page fault handling
|
|
- * @vma: user vma (not used)
|
|
|
|
- * @fdata: the applicable fault_data
|
|
|
|
|
|
+ * @vma: vma in which the fault was taken
|
|
|
|
+ * @vmf: struct vm_fault containing details of the fault
|
|
*
|
|
*
|
|
* filemap_fault() is invoked via the vma operations vector for a
|
|
* filemap_fault() is invoked via the vma operations vector for a
|
|
* mapped memory region to read in file data during a page fault.
|
|
* mapped memory region to read in file data during a page fault.
|
|
@@ -1312,7 +1312,7 @@ static int fastcall page_cache_read(struct file * file, unsigned long offset)
|
|
* it in the page cache, and handles the special cases reasonably without
|
|
* it in the page cache, and handles the special cases reasonably without
|
|
* having a lot of duplicated code.
|
|
* having a lot of duplicated code.
|
|
*/
|
|
*/
|
|
-struct page *filemap_fault(struct vm_area_struct *vma, struct fault_data *fdata)
|
|
|
|
|
|
+int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|
{
|
|
{
|
|
int error;
|
|
int error;
|
|
struct file *file = vma->vm_file;
|
|
struct file *file = vma->vm_file;
|
|
@@ -1322,13 +1322,12 @@ struct page *filemap_fault(struct vm_area_struct *vma, struct fault_data *fdata)
|
|
struct page *page;
|
|
struct page *page;
|
|
unsigned long size;
|
|
unsigned long size;
|
|
int did_readaround = 0;
|
|
int did_readaround = 0;
|
|
|
|
+ int ret;
|
|
|
|
|
|
- fdata->type = VM_FAULT_MINOR;
|
|
|
|
-
|
|
|
|
- BUG_ON(!(vma->vm_flags & VM_CAN_INVALIDATE));
|
|
|
|
|
|
+ ret = VM_FAULT_MINOR;
|
|
|
|
|
|
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
- if (fdata->pgoff >= size)
|
|
|
|
|
|
+ if (vmf->pgoff >= size)
|
|
goto outside_data_content;
|
|
goto outside_data_content;
|
|
|
|
|
|
/* If we don't want any read-ahead, don't bother */
|
|
/* If we don't want any read-ahead, don't bother */
|
|
@@ -1342,18 +1341,18 @@ struct page *filemap_fault(struct vm_area_struct *vma, struct fault_data *fdata)
|
|
* For sequential accesses, we use the generic readahead logic.
|
|
* For sequential accesses, we use the generic readahead logic.
|
|
*/
|
|
*/
|
|
if (VM_SequentialReadHint(vma))
|
|
if (VM_SequentialReadHint(vma))
|
|
- page_cache_readahead(mapping, ra, file, fdata->pgoff, 1);
|
|
|
|
|
|
+ page_cache_readahead(mapping, ra, file, vmf->pgoff, 1);
|
|
|
|
|
|
/*
|
|
/*
|
|
* Do we have something in the page cache already?
|
|
* Do we have something in the page cache already?
|
|
*/
|
|
*/
|
|
retry_find:
|
|
retry_find:
|
|
- page = find_lock_page(mapping, fdata->pgoff);
|
|
|
|
|
|
+ page = find_lock_page(mapping, vmf->pgoff);
|
|
if (!page) {
|
|
if (!page) {
|
|
unsigned long ra_pages;
|
|
unsigned long ra_pages;
|
|
|
|
|
|
if (VM_SequentialReadHint(vma)) {
|
|
if (VM_SequentialReadHint(vma)) {
|
|
- handle_ra_miss(mapping, ra, fdata->pgoff);
|
|
|
|
|
|
+ handle_ra_miss(mapping, ra, vmf->pgoff);
|
|
goto no_cached_page;
|
|
goto no_cached_page;
|
|
}
|
|
}
|
|
ra->mmap_miss++;
|
|
ra->mmap_miss++;
|
|
@@ -1370,7 +1369,7 @@ retry_find:
|
|
* check did_readaround, as this is an inner loop.
|
|
* check did_readaround, as this is an inner loop.
|
|
*/
|
|
*/
|
|
if (!did_readaround) {
|
|
if (!did_readaround) {
|
|
- fdata->type = VM_FAULT_MAJOR;
|
|
|
|
|
|
+ ret = VM_FAULT_MAJOR;
|
|
count_vm_event(PGMAJFAULT);
|
|
count_vm_event(PGMAJFAULT);
|
|
}
|
|
}
|
|
did_readaround = 1;
|
|
did_readaround = 1;
|
|
@@ -1378,11 +1377,11 @@ retry_find:
|
|
if (ra_pages) {
|
|
if (ra_pages) {
|
|
pgoff_t start = 0;
|
|
pgoff_t start = 0;
|
|
|
|
|
|
- if (fdata->pgoff > ra_pages / 2)
|
|
|
|
- start = fdata->pgoff - ra_pages / 2;
|
|
|
|
|
|
+ if (vmf->pgoff > ra_pages / 2)
|
|
|
|
+ start = vmf->pgoff - ra_pages / 2;
|
|
do_page_cache_readahead(mapping, file, start, ra_pages);
|
|
do_page_cache_readahead(mapping, file, start, ra_pages);
|
|
}
|
|
}
|
|
- page = find_lock_page(mapping, fdata->pgoff);
|
|
|
|
|
|
+ page = find_lock_page(mapping, vmf->pgoff);
|
|
if (!page)
|
|
if (!page)
|
|
goto no_cached_page;
|
|
goto no_cached_page;
|
|
}
|
|
}
|
|
@@ -1399,7 +1398,7 @@ retry_find:
|
|
|
|
|
|
/* Must recheck i_size under page lock */
|
|
/* Must recheck i_size under page lock */
|
|
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
- if (unlikely(fdata->pgoff >= size)) {
|
|
|
|
|
|
+ if (unlikely(vmf->pgoff >= size)) {
|
|
unlock_page(page);
|
|
unlock_page(page);
|
|
goto outside_data_content;
|
|
goto outside_data_content;
|
|
}
|
|
}
|
|
@@ -1408,24 +1407,24 @@ retry_find:
|
|
* Found the page and have a reference on it.
|
|
* Found the page and have a reference on it.
|
|
*/
|
|
*/
|
|
mark_page_accessed(page);
|
|
mark_page_accessed(page);
|
|
- return page;
|
|
|
|
|
|
+ vmf->page = page;
|
|
|
|
+ return ret | FAULT_RET_LOCKED;
|
|
|
|
|
|
outside_data_content:
|
|
outside_data_content:
|
|
/*
|
|
/*
|
|
* An external ptracer can access pages that normally aren't
|
|
* An external ptracer can access pages that normally aren't
|
|
* accessible..
|
|
* accessible..
|
|
*/
|
|
*/
|
|
- if (vma->vm_mm == current->mm) {
|
|
|
|
- fdata->type = VM_FAULT_SIGBUS;
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ if (vma->vm_mm == current->mm)
|
|
|
|
+ return VM_FAULT_SIGBUS;
|
|
|
|
+
|
|
/* Fall through to the non-read-ahead case */
|
|
/* Fall through to the non-read-ahead case */
|
|
no_cached_page:
|
|
no_cached_page:
|
|
/*
|
|
/*
|
|
* We're only likely to ever get here if MADV_RANDOM is in
|
|
* We're only likely to ever get here if MADV_RANDOM is in
|
|
* effect.
|
|
* effect.
|
|
*/
|
|
*/
|
|
- error = page_cache_read(file, fdata->pgoff);
|
|
|
|
|
|
+ error = page_cache_read(file, vmf->pgoff);
|
|
|
|
|
|
/*
|
|
/*
|
|
* The page we want has now been added to the page cache.
|
|
* The page we want has now been added to the page cache.
|
|
@@ -1441,15 +1440,13 @@ no_cached_page:
|
|
* to schedule I/O.
|
|
* to schedule I/O.
|
|
*/
|
|
*/
|
|
if (error == -ENOMEM)
|
|
if (error == -ENOMEM)
|
|
- fdata->type = VM_FAULT_OOM;
|
|
|
|
- else
|
|
|
|
- fdata->type = VM_FAULT_SIGBUS;
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ return VM_FAULT_OOM;
|
|
|
|
+ return VM_FAULT_SIGBUS;
|
|
|
|
|
|
page_not_uptodate:
|
|
page_not_uptodate:
|
|
/* IO error path */
|
|
/* IO error path */
|
|
if (!did_readaround) {
|
|
if (!did_readaround) {
|
|
- fdata->type = VM_FAULT_MAJOR;
|
|
|
|
|
|
+ ret = VM_FAULT_MAJOR;
|
|
count_vm_event(PGMAJFAULT);
|
|
count_vm_event(PGMAJFAULT);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1468,206 +1465,10 @@ page_not_uptodate:
|
|
|
|
|
|
/* Things didn't work out. Return zero to tell the mm layer so. */
|
|
/* Things didn't work out. Return zero to tell the mm layer so. */
|
|
shrink_readahead_size_eio(file, ra);
|
|
shrink_readahead_size_eio(file, ra);
|
|
- fdata->type = VM_FAULT_SIGBUS;
|
|
|
|
- return NULL;
|
|
|
|
|
|
+ return VM_FAULT_SIGBUS;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(filemap_fault);
|
|
EXPORT_SYMBOL(filemap_fault);
|
|
|
|
|
|
-/*
|
|
|
|
- * filemap_nopage and filemap_populate are legacy exports that are not used
|
|
|
|
- * in tree. Scheduled for removal.
|
|
|
|
- */
|
|
|
|
-struct page *filemap_nopage(struct vm_area_struct *area,
|
|
|
|
- unsigned long address, int *type)
|
|
|
|
-{
|
|
|
|
- struct page *page;
|
|
|
|
- struct fault_data fdata;
|
|
|
|
- fdata.address = address;
|
|
|
|
- fdata.pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT)
|
|
|
|
- + area->vm_pgoff;
|
|
|
|
- fdata.flags = 0;
|
|
|
|
-
|
|
|
|
- page = filemap_fault(area, &fdata);
|
|
|
|
- if (type)
|
|
|
|
- *type = fdata.type;
|
|
|
|
-
|
|
|
|
- return page;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL(filemap_nopage);
|
|
|
|
-
|
|
|
|
-static struct page * filemap_getpage(struct file *file, unsigned long pgoff,
|
|
|
|
- int nonblock)
|
|
|
|
-{
|
|
|
|
- struct address_space *mapping = file->f_mapping;
|
|
|
|
- struct page *page;
|
|
|
|
- int error;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Do we have something in the page cache already?
|
|
|
|
- */
|
|
|
|
-retry_find:
|
|
|
|
- page = find_get_page(mapping, pgoff);
|
|
|
|
- if (!page) {
|
|
|
|
- if (nonblock)
|
|
|
|
- return NULL;
|
|
|
|
- goto no_cached_page;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Ok, found a page in the page cache, now we need to check
|
|
|
|
- * that it's up-to-date.
|
|
|
|
- */
|
|
|
|
- if (!PageUptodate(page)) {
|
|
|
|
- if (nonblock) {
|
|
|
|
- page_cache_release(page);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
- goto page_not_uptodate;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-success:
|
|
|
|
- /*
|
|
|
|
- * Found the page and have a reference on it.
|
|
|
|
- */
|
|
|
|
- mark_page_accessed(page);
|
|
|
|
- return page;
|
|
|
|
-
|
|
|
|
-no_cached_page:
|
|
|
|
- error = page_cache_read(file, pgoff);
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * The page we want has now been added to the page cache.
|
|
|
|
- * In the unlikely event that someone removed it in the
|
|
|
|
- * meantime, we'll just come back here and read it again.
|
|
|
|
- */
|
|
|
|
- if (error >= 0)
|
|
|
|
- goto retry_find;
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * An error return from page_cache_read can result if the
|
|
|
|
- * system is low on memory, or a problem occurs while trying
|
|
|
|
- * to schedule I/O.
|
|
|
|
- */
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
-page_not_uptodate:
|
|
|
|
- lock_page(page);
|
|
|
|
-
|
|
|
|
- /* Did it get truncated while we waited for it? */
|
|
|
|
- if (!page->mapping) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- goto err;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Did somebody else get it up-to-date? */
|
|
|
|
- if (PageUptodate(page)) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- goto success;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- error = mapping->a_ops->readpage(file, page);
|
|
|
|
- if (!error) {
|
|
|
|
- wait_on_page_locked(page);
|
|
|
|
- if (PageUptodate(page))
|
|
|
|
- goto success;
|
|
|
|
- } else if (error == AOP_TRUNCATED_PAGE) {
|
|
|
|
- page_cache_release(page);
|
|
|
|
- goto retry_find;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Umm, take care of errors if the page isn't up-to-date.
|
|
|
|
- * Try to re-read it _once_. We do this synchronously,
|
|
|
|
- * because there really aren't any performance issues here
|
|
|
|
- * and we need to check for errors.
|
|
|
|
- */
|
|
|
|
- lock_page(page);
|
|
|
|
-
|
|
|
|
- /* Somebody truncated the page on us? */
|
|
|
|
- if (!page->mapping) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- goto err;
|
|
|
|
- }
|
|
|
|
- /* Somebody else successfully read it in? */
|
|
|
|
- if (PageUptodate(page)) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- goto success;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ClearPageError(page);
|
|
|
|
- error = mapping->a_ops->readpage(file, page);
|
|
|
|
- if (!error) {
|
|
|
|
- wait_on_page_locked(page);
|
|
|
|
- if (PageUptodate(page))
|
|
|
|
- goto success;
|
|
|
|
- } else if (error == AOP_TRUNCATED_PAGE) {
|
|
|
|
- page_cache_release(page);
|
|
|
|
- goto retry_find;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /*
|
|
|
|
- * Things didn't work out. Return zero to tell the
|
|
|
|
- * mm layer so, possibly freeing the page cache page first.
|
|
|
|
- */
|
|
|
|
-err:
|
|
|
|
- page_cache_release(page);
|
|
|
|
-
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-int filemap_populate(struct vm_area_struct *vma, unsigned long addr,
|
|
|
|
- unsigned long len, pgprot_t prot, unsigned long pgoff,
|
|
|
|
- int nonblock)
|
|
|
|
-{
|
|
|
|
- struct file *file = vma->vm_file;
|
|
|
|
- struct address_space *mapping = file->f_mapping;
|
|
|
|
- struct inode *inode = mapping->host;
|
|
|
|
- unsigned long size;
|
|
|
|
- struct mm_struct *mm = vma->vm_mm;
|
|
|
|
- struct page *page;
|
|
|
|
- int err;
|
|
|
|
-
|
|
|
|
- if (!nonblock)
|
|
|
|
- force_page_cache_readahead(mapping, vma->vm_file,
|
|
|
|
- pgoff, len >> PAGE_CACHE_SHIFT);
|
|
|
|
-
|
|
|
|
-repeat:
|
|
|
|
- size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
|
|
|
|
- if (pgoff + (len >> PAGE_CACHE_SHIFT) > size)
|
|
|
|
- return -EINVAL;
|
|
|
|
-
|
|
|
|
- page = filemap_getpage(file, pgoff, nonblock);
|
|
|
|
-
|
|
|
|
- /* XXX: This is wrong, a filesystem I/O error may have happened. Fix that as
|
|
|
|
- * done in shmem_populate calling shmem_getpage */
|
|
|
|
- if (!page && !nonblock)
|
|
|
|
- return -ENOMEM;
|
|
|
|
-
|
|
|
|
- if (page) {
|
|
|
|
- err = install_page(mm, vma, addr, page, prot);
|
|
|
|
- if (err) {
|
|
|
|
- page_cache_release(page);
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
- } else if (vma->vm_flags & VM_NONLINEAR) {
|
|
|
|
- /* No page was found just because we can't read it in now (being
|
|
|
|
- * here implies nonblock != 0), but the page may exist, so set
|
|
|
|
- * the PTE to fault it in later. */
|
|
|
|
- err = install_file_pte(mm, vma, addr, pgoff, prot);
|
|
|
|
- if (err)
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- len -= PAGE_SIZE;
|
|
|
|
- addr += PAGE_SIZE;
|
|
|
|
- pgoff++;
|
|
|
|
- if (len)
|
|
|
|
- goto repeat;
|
|
|
|
-
|
|
|
|
- return 0;
|
|
|
|
-}
|
|
|
|
-EXPORT_SYMBOL(filemap_populate);
|
|
|
|
-
|
|
|
|
struct vm_operations_struct generic_file_vm_ops = {
|
|
struct vm_operations_struct generic_file_vm_ops = {
|
|
.fault = filemap_fault,
|
|
.fault = filemap_fault,
|
|
};
|
|
};
|
|
@@ -1682,7 +1483,7 @@ int generic_file_mmap(struct file * file, struct vm_area_struct * vma)
|
|
return -ENOEXEC;
|
|
return -ENOEXEC;
|
|
file_accessed(file);
|
|
file_accessed(file);
|
|
vma->vm_ops = &generic_file_vm_ops;
|
|
vma->vm_ops = &generic_file_vm_ops;
|
|
- vma->vm_flags |= VM_CAN_INVALIDATE | VM_CAN_NONLINEAR;
|
|
|
|
|
|
+ vma->vm_flags |= VM_CAN_NONLINEAR;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|