@@ -757,7 +757,7 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
struct page *page;
unsigned long offset; /* Offset into pagecache page */
unsigned long bytes; /* Bytes to write to page */
- size_t copied; /* Bytes copied from user */
+ loff_t copied; /* Bytes copied from user */
offset = offset_in_page(pos);
bytes = min_t(unsigned long, PAGE_SIZE - offset,
@@ -791,6 +791,12 @@ iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data,
copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
+ if (copied < 0) {
+ unlock_page(page);
+ put_page(page);
+ return copied;
+ }
+
copied = iomap_write_end(inode, pos, bytes, copied, page, iomap,
srcmap);
@@ -111,7 +111,7 @@ static inline struct iovec iov_iter_iovec(const struct iov_iter *iter)
};
}
-size_t iov_iter_copy_from_user_atomic(struct page *page,
+loff_t iov_iter_copy_from_user_atomic(struct page *page,
struct iov_iter *i, unsigned long offset, size_t bytes);
void iov_iter_advance(struct iov_iter *i, size_t bytes);
void iov_iter_revert(struct iov_iter *i, size_t bytes);
@@ -16,13 +16,18 @@
#define PIPE_PARANOIA /* for now */
#define iterate_iovec(i, n, __v, __p, skip, STEP) { \
- size_t left; \
+ loff_t left; \
size_t wanted = n; \
__p = i->iov; \
__v.iov_len = min(n, __p->iov_len - skip); \
if (likely(__v.iov_len)) { \
__v.iov_base = __p->iov_base + skip; \
left = (STEP); \
+ if (left < 0) { \
+ wanted = left; \
+ n = 0; \
+ goto err; \
+ } \
__v.iov_len -= left; \
skip += __v.iov_len; \
n -= __v.iov_len; \
@@ -36,10 +41,16 @@
continue; \
__v.iov_base = __p->iov_base; \
left = (STEP); \
+ if (left < 0) { \
+ wanted = left; \
+ n = 0; \
+ break; \
+ } \
__v.iov_len -= left; \
skip = __v.iov_len; \
n -= __v.iov_len; \
} \
+err: \
n = wanted - n; \
}
@@ -975,7 +986,7 @@ size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
}
EXPORT_SYMBOL(iov_iter_zero);
-size_t iov_iter_copy_from_user_atomic(struct page *page,
+loff_t iov_iter_copy_from_user_atomic(struct page *page,
struct iov_iter *i, unsigned long offset, size_t bytes)
{
char *kaddr = kmap_atomic(page), *p = kaddr + offset;