iov_iter: Introduce fault_in_iov_iter_writeable
[linux-2.6-microblaze.git] / lib / iov_iter.c
index ce3d4f6..ac9a87e 100644 (file)
@@ -467,6 +467,45 @@ size_t fault_in_iov_iter_readable(const struct iov_iter *i, size_t size)
 }
 EXPORT_SYMBOL(fault_in_iov_iter_readable);
 
+/*
+ * fault_in_iov_iter_writeable - fault in iov iterator for writing
+ * @i: iterator
+ * @size: maximum length
+ *
+ * Faults in the iterator using get_user_pages(), i.e., without triggering
+ * hardware page faults.  This is primarily useful when we already know that
+ * some or all of the pages in @i aren't in memory.
+ *
+ * Returns the number of bytes not faulted in, like copy_to_user() and
+ * copy_from_user().
+ *
+ * Always returns 0 for non-user-space iterators.
+ */
+size_t fault_in_iov_iter_writeable(const struct iov_iter *i, size_t size)
+{
+       if (iter_is_iovec(i)) {
+               size_t count = min(size, iov_iter_count(i));
+               const struct iovec *p;
+               size_t skip;
+
+               size -= count;
+               for (p = i->iov, skip = i->iov_offset; count; p++, skip = 0) {
+                       size_t len = min(count, p->iov_len - skip);
+                       size_t ret;
+
+                       if (unlikely(!len))
+                               continue;
+                       ret = fault_in_safe_writeable(p->iov_base + skip, len);
+                       count -= len - ret;
+                       if (ret)
+                               break;
+               }
+               return count + size;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(fault_in_iov_iter_writeable);
+
 void iov_iter_init(struct iov_iter *i, unsigned int direction,
                        const struct iovec *iov, unsigned long nr_segs,
                        size_t count)