Merge branch 'timecounter-next'
[cascardo/linux.git] / lib / iovec.c
1 #include <linux/uaccess.h>
2 #include <linux/export.h>
3 #include <linux/uio.h>
4
5 /*
6  *      Copy iovec to kernel. Returns -EFAULT on error.
7  *
8  *      Note: this modifies the original iovec.
9  */
10
11 int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
12 {
13         while (len > 0) {
14                 if (iov->iov_len) {
15                         int copy = min_t(unsigned int, len, iov->iov_len);
16                         if (copy_from_user(kdata, iov->iov_base, copy))
17                                 return -EFAULT;
18                         len -= copy;
19                         kdata += copy;
20                         iov->iov_base += copy;
21                         iov->iov_len -= copy;
22                 }
23                 iov++;
24         }
25
26         return 0;
27 }
28 EXPORT_SYMBOL(memcpy_fromiovec);
29
30 /*
31  *      Copy kernel to iovec. Returns -EFAULT on error.
32  */
33
34 int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
35                       int offset, int len)
36 {
37         int copy;
38         for (; len > 0; ++iov) {
39                 /* Skip over the finished iovecs */
40                 if (unlikely(offset >= iov->iov_len)) {
41                         offset -= iov->iov_len;
42                         continue;
43                 }
44                 copy = min_t(unsigned int, iov->iov_len - offset, len);
45                 if (copy_to_user(iov->iov_base + offset, kdata, copy))
46                         return -EFAULT;
47                 offset = 0;
48                 kdata += copy;
49                 len -= copy;
50         }
51
52         return 0;
53 }
54 EXPORT_SYMBOL(memcpy_toiovecend);
55
56 /*
57  *      Copy iovec to kernel. Returns -EFAULT on error.
58  */
59
60 int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
61                         int offset, int len)
62 {
63         /* No data? Done! */
64         if (len == 0)
65                 return 0;
66
67         /* Skip over the finished iovecs */
68         while (offset >= iov->iov_len) {
69                 offset -= iov->iov_len;
70                 iov++;
71         }
72
73         while (len > 0) {
74                 u8 __user *base = iov->iov_base + offset;
75                 int copy = min_t(unsigned int, len, iov->iov_len - offset);
76
77                 offset = 0;
78                 if (copy_from_user(kdata, base, copy))
79                         return -EFAULT;
80                 len -= copy;
81                 kdata += copy;
82                 iov++;
83         }
84
85         return 0;
86 }
87 EXPORT_SYMBOL(memcpy_fromiovecend);