]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
iov_iter: ii_iovec_copy_to_user should pre-fault user pages
authorDave Kleikamp <dave.kleikamp@oracle.com>
Fri, 14 Jun 2013 20:54:12 +0000 (15:54 -0500)
committerDave Kleikamp <dave.kleikamp@oracle.com>
Fri, 9 Aug 2013 21:43:31 +0000 (16:43 -0500)
This duplicates the optimization in file_read_actor as a later patch
will replace it with a call to __iov_iter_copy_to_user().

Signed-off-by: Dave Kleikamp <dave.kleikamp@oracle.com>
fs/iov-iter.c

index 6cb6be0f18e811b08d3b25b57956f9e86f2b25a6..59f9556ac4d2a33d89e7125b99c5c10582286b10 100644 (file)
@@ -80,17 +80,32 @@ static size_t ii_iovec_copy_to_user(struct page *page,
                        return 0;
        }
 
-       kaddr = kmap(page);
        if (likely(i->nr_segs == 1)) {
                int left;
                char __user *buf = iov->iov_base + i->iov_offset;
+               /*
+                * Faults on the destination of a read are common, so do it
+                * before taking the kmap.
+                */
+               if (!fault_in_pages_writeable(buf, bytes)) {
+                       kaddr = kmap_atomic(page);
+                       left = __copy_to_user_inatomic(buf, kaddr + offset,
+                                                    bytes);
+                       kunmap_atomic(kaddr);
+                       if (left == 0)
+                               goto success;
+               }
+               kaddr = kmap(page);
                left = copy_to_user(buf, kaddr + offset, bytes);
+               kunmap(page);
+success:
                copied = bytes - left;
        } else {
+               kaddr = kmap(page);
                copied = __iovec_copy_to_user(kaddr + offset, iov,
                                              i->iov_offset, bytes, 0);
+               kunmap(page);
        }
-       kunmap(page);
        return copied;
 }