mm: merge populate and nopage into fault (fixes nonlinear)
[deliverable/linux.git] / mm / shmem.c
index 5808fadd39445ff4b49917afcb3aa51f717d0f10..6b44440f1b24d59af0ee3845fd65a6b88b16d147 100644 (file)
@@ -83,7 +83,7 @@ enum sgp_type {
        SGP_READ,       /* don't exceed i_size, don't allocate page */
        SGP_CACHE,      /* don't exceed i_size, may allocate page */
        SGP_WRITE,      /* may exceed i_size, may allocate page */
-       SGP_NOPAGE,     /* same as SGP_CACHE, return with page locked */
+       SGP_FAULT,      /* same as SGP_CACHE, return with page locked */
 };
 
 static int shmem_getpage(struct inode *inode, unsigned long idx,
@@ -1101,6 +1101,10 @@ static int shmem_getpage(struct inode *inode, unsigned long idx,
 
        if (idx >= SHMEM_MAX_INDEX)
                return -EFBIG;
+
+       if (type)
+               *type = VM_FAULT_MINOR;
+
        /*
         * Normally, filepage is NULL on entry, and either found
         * uptodate immediately, or allocated and zeroed, or read
@@ -1291,7 +1295,7 @@ repeat:
 done:
        if (*pagep != filepage) {
                *pagep = filepage;
-               if (sgp != SGP_NOPAGE)
+               if (sgp != SGP_FAULT)
                        unlock_page(filepage);
 
        }
@@ -1305,76 +1309,31 @@ failed:
        return error;
 }
 
-static struct page *shmem_nopage(struct vm_area_struct *vma,
-                                unsigned long address, int *type)
+static struct page *shmem_fault(struct vm_area_struct *vma,
+                                       struct fault_data *fdata)
 {
        struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
        struct page *page = NULL;
-       unsigned long idx;
        int error;
 
        BUG_ON(!(vma->vm_flags & VM_CAN_INVALIDATE));
 
-       idx = (address - vma->vm_start) >> PAGE_SHIFT;
-       idx += vma->vm_pgoff;
-       idx >>= PAGE_CACHE_SHIFT - PAGE_SHIFT;
-       if (((loff_t) idx << PAGE_CACHE_SHIFT) >= i_size_read(inode))
-               return NOPAGE_SIGBUS;
+       if (((loff_t)fdata->pgoff << PAGE_CACHE_SHIFT) >= i_size_read(inode)) {
+               fdata->type = VM_FAULT_SIGBUS;
+               return NULL;
+       }
 
-       error = shmem_getpage(inode, idx, &page, SGP_NOPAGE, type);
-       if (error)
-               return (error == -ENOMEM)? NOPAGE_OOM: NOPAGE_SIGBUS;
+       error = shmem_getpage(inode, fdata->pgoff, &page,
+                                               SGP_FAULT, &fdata->type);
+       if (error) {
+               fdata->type = ((error == -ENOMEM)?VM_FAULT_OOM:VM_FAULT_SIGBUS);
+               return NULL;
+       }
 
        mark_page_accessed(page);
        return page;
 }
 
-static int shmem_populate(struct vm_area_struct *vma,
-       unsigned long addr, unsigned long len,
-       pgprot_t prot, unsigned long pgoff, int nonblock)
-{
-       struct inode *inode = vma->vm_file->f_path.dentry->d_inode;
-       struct mm_struct *mm = vma->vm_mm;
-       enum sgp_type sgp = nonblock? SGP_QUICK: SGP_CACHE;
-       unsigned long size;
-
-       size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       if (pgoff >= size || pgoff + (len >> PAGE_SHIFT) > size)
-               return -EINVAL;
-
-       while ((long) len > 0) {
-               struct page *page = NULL;
-               int err;
-               /*
-                * Will need changing if PAGE_CACHE_SIZE != PAGE_SIZE
-                */
-               err = shmem_getpage(inode, pgoff, &page, sgp, NULL);
-               if (err)
-                       return err;
-               /* Page may still be null, but only if nonblock was set. */
-               if (page) {
-                       mark_page_accessed(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++;
-       }
-       return 0;
-}
-
 #ifdef CONFIG_NUMA
 int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *new)
 {
@@ -1419,7 +1378,7 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
 {
        file_accessed(file);
        vma->vm_ops = &shmem_vm_ops;
-       vma->vm_flags |= VM_CAN_INVALIDATE;
+       vma->vm_flags |= VM_CAN_INVALIDATE | VM_CAN_NONLINEAR;
        return 0;
 }
 
@@ -2465,8 +2424,7 @@ static const struct super_operations shmem_ops = {
 };
 
 static struct vm_operations_struct shmem_vm_ops = {
-       .nopage         = shmem_nopage,
-       .populate       = shmem_populate,
+       .fault          = shmem_fault,
 #ifdef CONFIG_NUMA
        .set_policy     = shmem_set_policy,
        .get_policy     = shmem_get_policy,
This page took 0.067155 seconds and 5 git commands to generate.