diff options
| -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 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) | |||
| 139 | size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); | 139 | size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); |
| 140 | size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); | 140 | size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); |
| 141 | 141 | ||
| 142 | int 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 | ||
| 147 | struct compat_iovec; | ||
| 148 | int 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 | |||
| 153 | int 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 | } |
| 768 | EXPORT_SYMBOL(dup_iter); | 768 | EXPORT_SYMBOL(dup_iter); |
| 769 | |||
| 770 | int 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 | } | ||
| 788 | EXPORT_SYMBOL(import_iovec); | ||
| 789 | |||
| 790 | #ifdef CONFIG_COMPAT | ||
| 791 | #include <linux/compat.h> | ||
| 792 | |||
| 793 | int 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 | |||
| 813 | int 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 | } | ||
