]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - mm/filemap.c
fix braino in generic_file_read_iter()
[karo-tx-linux.git] / mm / filemap.c
index 416d563468a3abfa6649fe48717d073dede899ac..d6e67be1802ef5290a3d49ebbc8464eaf0353a90 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/compiler.h>
 #include <linux/dax.h>
 #include <linux/fs.h>
+#include <linux/sched/signal.h>
 #include <linux/uaccess.h>
 #include <linux/capability.h>
 #include <linux/kernel_stat.h>
@@ -1008,9 +1009,12 @@ void page_endio(struct page *page, bool is_write, int err)
                unlock_page(page);
        } else {
                if (err) {
+                       struct address_space *mapping;
+
                        SetPageError(page);
-                       if (page->mapping)
-                               mapping_set_error(page->mapping, err);
+                       mapping = page_mapping(page);
+                       if (mapping)
+                               mapping_set_error(mapping, err);
                }
                end_page_writeback(page);
        }
@@ -2029,7 +2033,6 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
        if (iocb->ki_flags & IOCB_DIRECT) {
                struct address_space *mapping = file->f_mapping;
                struct inode *inode = mapping->host;
-               struct iov_iter data = *iter;
                loff_t size;
 
                size = i_size_read(inode);
@@ -2040,11 +2043,12 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
 
                file_accessed(file);
 
-               retval = mapping->a_ops->direct_IO(iocb, &data);
+               retval = mapping->a_ops->direct_IO(iocb, iter);
                if (retval >= 0) {
                        iocb->ki_pos += retval;
-                       iov_iter_advance(iter, retval);
+                       count -= retval;
                }
+               iov_iter_revert(iter, count - iov_iter_count(iter));
 
                /*
                 * Btrfs can have a short DIO read if we encounter
@@ -2055,7 +2059,7 @@ generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter)
                 * the rest of the read.  Buffered reads will not work for
                 * DAX files, so don't bother trying.
                 */
-               if (retval < 0 || !iov_iter_count(iter) || iocb->ki_pos >= size ||
+               if (retval < 0 || !count || iocb->ki_pos >= size ||
                    IS_DAX(inode))
                        goto out;
        }
@@ -2169,7 +2173,6 @@ static void do_async_mmap_readahead(struct vm_area_struct *vma,
 
 /**
  * filemap_fault - read in file data for page fault handling
- * @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
@@ -2191,10 +2194,10 @@ static void do_async_mmap_readahead(struct vm_area_struct *vma,
  *
  * We never return with VM_FAULT_RETRY and a bit from VM_FAULT_ERROR set.
  */
-int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+int filemap_fault(struct vm_fault *vmf)
 {
        int error;
-       struct file *file = vma->vm_file;
+       struct file *file = vmf->vma->vm_file;
        struct address_space *mapping = file->f_mapping;
        struct file_ra_state *ra = &file->f_ra;
        struct inode *inode = mapping->host;
@@ -2216,12 +2219,12 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                 * We found the page, so try async readahead before
                 * waiting for the lock.
                 */
-               do_async_mmap_readahead(vma, ra, file, page, offset);
+               do_async_mmap_readahead(vmf->vma, ra, file, page, offset);
        } else if (!page) {
                /* No page in the page cache at all */
-               do_sync_mmap_readahead(vma, ra, file, offset);
+               do_sync_mmap_readahead(vmf->vma, ra, file, offset);
                count_vm_event(PGMAJFAULT);
-               mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT);
+               mem_cgroup_count_vm_event(vmf->vma->vm_mm, PGMAJFAULT);
                ret = VM_FAULT_MAJOR;
 retry_find:
                page = find_get_page(mapping, offset);
@@ -2229,7 +2232,7 @@ retry_find:
                        goto no_cached_page;
        }
 
-       if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) {
+       if (!lock_page_or_retry(page, vmf->vma->vm_mm, vmf->flags)) {
                put_page(page);
                return ret | VM_FAULT_RETRY;
        }
@@ -2396,14 +2399,14 @@ next:
 }
 EXPORT_SYMBOL(filemap_map_pages);
 
-int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
+int filemap_page_mkwrite(struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
-       struct inode *inode = file_inode(vma->vm_file);
+       struct inode *inode = file_inode(vmf->vma->vm_file);
        int ret = VM_FAULT_LOCKED;
 
        sb_start_pagefault(inode->i_sb);
-       file_update_time(vma->vm_file);
+       file_update_time(vmf->vma->vm_file);
        lock_page(page);
        if (page->mapping != inode->i_mapping) {
                unlock_page(page);
@@ -2701,7 +2704,6 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
        ssize_t         written;
        size_t          write_len;
        pgoff_t         end;
-       struct iov_iter data;
 
        write_len = iov_iter_count(from);
        end = (pos + write_len - 1) >> PAGE_SHIFT;
@@ -2730,8 +2732,7 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
                }
        }
 
-       data = *from;
-       written = mapping->a_ops->direct_IO(iocb, &data);
+       written = mapping->a_ops->direct_IO(iocb, from);
 
        /*
         * Finally, try again to invalidate clean pages which might have been
@@ -2748,13 +2749,14 @@ generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from)
 
        if (written > 0) {
                pos += written;
-               iov_iter_advance(from, written);
+               write_len -= written;
                if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) {
                        i_size_write(inode, pos);
                        mark_inode_dirty(inode);
                }
                iocb->ki_pos = pos;
        }
+       iov_iter_revert(from, write_len - iov_iter_count(from));
 out:
        return written;
 }