diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-12 02:26:51 (GMT) |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-04-12 02:26:51 (GMT) |
commit | 36e9f6535f398952772df5238b23e795a2810f86 (patch) | |
tree | ee06829309dbe7ff87ed953f6e7dc7433f48cc85 | |
parent | a96114fa1acaabca1091a27aacebd945a5733075 (diff) | |
parent | bc917be8105993c256338ad1189650364a741483 (diff) | |
download | linux-36e9f6535f398952772df5238b23e795a2810f86.tar.xz |
Merge branch 'iov_iter' into for-next
-rw-r--r-- | include/linux/uio.h | 14 | ||||
-rw-r--r-- | lib/iov_iter.c | 57 |
2 files changed, 71 insertions, 0 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h index a69ed25..15f11fb 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -140,4 +140,18 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count) size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); +int import_iovec(int type, const struct iovec __user * uvector, + unsigned nr_segs, unsigned fast_segs, + struct iovec **iov, struct iov_iter *i); + +#ifdef CONFIG_COMPAT +struct compat_iovec; +int compat_import_iovec(int type, const struct compat_iovec __user * uvector, + unsigned nr_segs, unsigned fast_segs, + struct iovec **iov, struct iov_iter *i); +#endif + +int import_single_range(int type, void __user *buf, size_t len, + struct iovec *iov, struct iov_iter *i); + #endif diff --git a/lib/iov_iter.c b/lib/iov_iter.c index b80f843..75232ad 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -792,3 +792,60 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) flags); } EXPORT_SYMBOL(dup_iter); + +int import_iovec(int type, const struct iovec __user * uvector, + unsigned nr_segs, unsigned fast_segs, + struct iovec **iov, struct iov_iter *i) +{ + ssize_t n; + struct iovec *p; + n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs, + *iov, &p); + if (n < 0) { + if (p != *iov) + kfree(p); + *iov = NULL; + return n; + } + iov_iter_init(i, type, p, nr_segs, n); + *iov = p == *iov ? NULL : p; + return 0; +} +EXPORT_SYMBOL(import_iovec); + +#ifdef CONFIG_COMPAT +#include <linux/compat.h> + +int compat_import_iovec(int type, const struct compat_iovec __user * uvector, + unsigned nr_segs, unsigned fast_segs, + struct iovec **iov, struct iov_iter *i) +{ + ssize_t n; + struct iovec *p; + n = compat_rw_copy_check_uvector(type, uvector, nr_segs, fast_segs, + *iov, &p); + if (n < 0) { + if (p != *iov) + kfree(p); + *iov = NULL; + return n; + } + iov_iter_init(i, type, p, nr_segs, n); + *iov = p == *iov ? NULL : p; + return 0; +} +#endif + +int import_single_range(int rw, void __user *buf, size_t len, + struct iovec *iov, struct iov_iter *i) +{ + if (len > MAX_RW_COUNT) + len = MAX_RW_COUNT; + if (unlikely(!access_ok(!rw, buf, len))) + return -EFAULT; + + iov->iov_base = buf; + iov->iov_len = len; + iov_iter_init(i, rw, iov, 1, len); + return 0; +} |