aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/uio.h14
-rw-r--r--lib/iov_iter.c57
2 files changed, 71 insertions, 0 deletions
diff --git a/include/linux/uio.h b/include/linux/uio.h
index 71880299ed48..1f4a37f1f025 100644
--- a/include/linux/uio.h
+++ b/include/linux/uio.h
@@ -139,4 +139,18 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)
139size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); 139size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
140size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); 140size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i);
141 141
142int import_iovec(int type, const struct iovec __user * uvector,
143 unsigned nr_segs, unsigned fast_segs,
144 struct iovec **iov, struct iov_iter *i);
145
146#ifdef CONFIG_COMPAT
147struct compat_iovec;
148int compat_import_iovec(int type, const struct compat_iovec __user * uvector,
149 unsigned nr_segs, unsigned fast_segs,
150 struct iovec **iov, struct iov_iter *i);
151#endif
152
153int import_single_range(int type, void __user *buf, size_t len,
154 struct iovec *iov, struct iov_iter *i);
155
142#endif 156#endif
diff --git a/lib/iov_iter.c b/lib/iov_iter.c
index 9d96e283520c..fc6e33f6b7f3 100644
--- a/lib/iov_iter.c
+++ b/lib/iov_iter.c
@@ -766,3 +766,60 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags)
766 flags); 766 flags);
767} 767}
768EXPORT_SYMBOL(dup_iter); 768EXPORT_SYMBOL(dup_iter);
769
770int import_iovec(int type, const struct iovec __user * uvector,
771 unsigned nr_segs, unsigned fast_segs,
772 struct iovec **iov, struct iov_iter *i)
773{
774 ssize_t n;
775 struct iovec *p;
776 n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
777 *iov, &p);
778 if (n < 0) {
779 if (p != *iov)
780 kfree(p);
781 *iov = NULL;
782 return n;
783 }
784 iov_iter_init(i, type, p, nr_segs, n);
785 *iov = p == *iov ? NULL : p;
786 return 0;
787}
788EXPORT_SYMBOL(import_iovec);
789
790#ifdef CONFIG_COMPAT
791#include <linux/compat.h>
792
793int compat_import_iovec(int type, const struct compat_iovec __user * uvector,
794 unsigned nr_segs, unsigned fast_segs,
795 struct iovec **iov, struct iov_iter *i)
796{
797 ssize_t n;
798 struct iovec *p;
799 n = compat_rw_copy_check_uvector(type, uvector, nr_segs, fast_segs,
800 *iov, &p);
801 if (n < 0) {
802 if (p != *iov)
803 kfree(p);
804 *iov = NULL;
805 return n;
806 }
807 iov_iter_init(i, type, p, nr_segs, n);
808 *iov = p == *iov ? NULL : p;
809 return 0;
810}
811#endif
812
813int import_single_range(int rw, void __user *buf, size_t len,
814 struct iovec *iov, struct iov_iter *i)
815{
816 if (len > MAX_RW_COUNT)
817 len = MAX_RW_COUNT;
818 if (unlikely(!access_ok(!rw, buf, len)))
819 return -EFAULT;
820
821 iov->iov_base = buf;
822 iov->iov_len = len;
823 iov_iter_init(i, rw, iov, 1, len);
824 return 0;
825}