diff options
Diffstat (limited to 'lib/iov_iter.c')
| -rw-r--r-- | lib/iov_iter.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 9d96e283520c..75232ad0a5e7 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
| @@ -317,6 +317,32 @@ int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes) | |||
| 317 | } | 317 | } |
| 318 | EXPORT_SYMBOL(iov_iter_fault_in_readable); | 318 | EXPORT_SYMBOL(iov_iter_fault_in_readable); |
| 319 | 319 | ||
| 320 | /* | ||
| 321 | * Fault in one or more iovecs of the given iov_iter, to a maximum length of | ||
| 322 | * bytes. For each iovec, fault in each page that constitutes the iovec. | ||
| 323 | * | ||
| 324 | * Return 0 on success, or non-zero if the memory could not be accessed (i.e. | ||
| 325 | * because it is an invalid address). | ||
| 326 | */ | ||
| 327 | int iov_iter_fault_in_multipages_readable(struct iov_iter *i, size_t bytes) | ||
| 328 | { | ||
| 329 | size_t skip = i->iov_offset; | ||
| 330 | const struct iovec *iov; | ||
| 331 | int err; | ||
| 332 | struct iovec v; | ||
| 333 | |||
| 334 | if (!(i->type & (ITER_BVEC|ITER_KVEC))) { | ||
| 335 | iterate_iovec(i, bytes, v, iov, skip, ({ | ||
| 336 | err = fault_in_multipages_readable(v.iov_base, | ||
| 337 | v.iov_len); | ||
| 338 | if (unlikely(err)) | ||
| 339 | return err; | ||
| 340 | 0;})) | ||
| 341 | } | ||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | EXPORT_SYMBOL(iov_iter_fault_in_multipages_readable); | ||
| 345 | |||
| 320 | void iov_iter_init(struct iov_iter *i, int direction, | 346 | void iov_iter_init(struct iov_iter *i, int direction, |
| 321 | const struct iovec *iov, unsigned long nr_segs, | 347 | const struct iovec *iov, unsigned long nr_segs, |
| 322 | size_t count) | 348 | size_t count) |
| @@ -766,3 +792,60 @@ const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) | |||
| 766 | flags); | 792 | flags); |
| 767 | } | 793 | } |
| 768 | EXPORT_SYMBOL(dup_iter); | 794 | EXPORT_SYMBOL(dup_iter); |
| 795 | |||
| 796 | int import_iovec(int type, const struct iovec __user * uvector, | ||
| 797 | unsigned nr_segs, unsigned fast_segs, | ||
| 798 | struct iovec **iov, struct iov_iter *i) | ||
| 799 | { | ||
| 800 | ssize_t n; | ||
| 801 | struct iovec *p; | ||
| 802 | n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs, | ||
| 803 | *iov, &p); | ||
| 804 | if (n < 0) { | ||
| 805 | if (p != *iov) | ||
| 806 | kfree(p); | ||
| 807 | *iov = NULL; | ||
| 808 | return n; | ||
| 809 | } | ||
| 810 | iov_iter_init(i, type, p, nr_segs, n); | ||
| 811 | *iov = p == *iov ? NULL : p; | ||
| 812 | return 0; | ||
| 813 | } | ||
| 814 | EXPORT_SYMBOL(import_iovec); | ||
| 815 | |||
| 816 | #ifdef CONFIG_COMPAT | ||
| 817 | #include <linux/compat.h> | ||
| 818 | |||
| 819 | int compat_import_iovec(int type, const struct compat_iovec __user * uvector, | ||
| 820 | unsigned nr_segs, unsigned fast_segs, | ||
| 821 | struct iovec **iov, struct iov_iter *i) | ||
| 822 | { | ||
| 823 | ssize_t n; | ||
| 824 | struct iovec *p; | ||
| 825 | n = compat_rw_copy_check_uvector(type, uvector, nr_segs, fast_segs, | ||
| 826 | *iov, &p); | ||
| 827 | if (n < 0) { | ||
| 828 | if (p != *iov) | ||
| 829 | kfree(p); | ||
| 830 | *iov = NULL; | ||
| 831 | return n; | ||
| 832 | } | ||
| 833 | iov_iter_init(i, type, p, nr_segs, n); | ||
| 834 | *iov = p == *iov ? NULL : p; | ||
| 835 | return 0; | ||
| 836 | } | ||
| 837 | #endif | ||
| 838 | |||
| 839 | int import_single_range(int rw, void __user *buf, size_t len, | ||
| 840 | struct iovec *iov, struct iov_iter *i) | ||
| 841 | { | ||
| 842 | if (len > MAX_RW_COUNT) | ||
| 843 | len = MAX_RW_COUNT; | ||
| 844 | if (unlikely(!access_ok(!rw, buf, len))) | ||
| 845 | return -EFAULT; | ||
| 846 | |||
| 847 | iov->iov_base = buf; | ||
| 848 | iov->iov_len = len; | ||
| 849 | iov_iter_init(i, rw, iov, 1, len); | ||
| 850 | return 0; | ||
| 851 | } | ||
