Merge tag 'stable/for-linus-3.16-rc5-tag' of git://git.kernel.org/pub/scm/linux/kerne...
[firefly-linux-kernel-4.4.55.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  *      Note: this modifies the original iovec.
34  */
35
36 int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
37 {
38         while (len > 0) {
39                 if (iov->iov_len) {
40                         int copy = min_t(unsigned int, iov->iov_len, len);
41                         if (copy_to_user(iov->iov_base, kdata, copy))
42                                 return -EFAULT;
43                         kdata += copy;
44                         len -= copy;
45                         iov->iov_len -= copy;
46                         iov->iov_base += copy;
47                 }
48                 iov++;
49         }
50
51         return 0;
52 }
53 EXPORT_SYMBOL(memcpy_toiovec);
54
55 /*
56  *      Copy kernel to iovec. Returns -EFAULT on error.
57  */
58
59 int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata,
60                       int offset, int len)
61 {
62         int copy;
63         for (; len > 0; ++iov) {
64                 /* Skip over the finished iovecs */
65                 if (unlikely(offset >= iov->iov_len)) {
66                         offset -= iov->iov_len;
67                         continue;
68                 }
69                 copy = min_t(unsigned int, iov->iov_len - offset, len);
70                 if (copy_to_user(iov->iov_base + offset, kdata, copy))
71                         return -EFAULT;
72                 offset = 0;
73                 kdata += copy;
74                 len -= copy;
75         }
76
77         return 0;
78 }
79 EXPORT_SYMBOL(memcpy_toiovecend);
80
81 /*
82  *      Copy iovec to kernel. Returns -EFAULT on error.
83  */
84
85 int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
86                         int offset, int len)
87 {
88         /* Skip over the finished iovecs */
89         while (offset >= iov->iov_len) {
90                 offset -= iov->iov_len;
91                 iov++;
92         }
93
94         while (len > 0) {
95                 u8 __user *base = iov->iov_base + offset;
96                 int copy = min_t(unsigned int, len, iov->iov_len - offset);
97
98                 offset = 0;
99                 if (copy_from_user(kdata, base, copy))
100                         return -EFAULT;
101                 len -= copy;
102                 kdata += copy;
103                 iov++;
104         }
105
106         return 0;
107 }
108 EXPORT_SYMBOL(memcpy_fromiovecend);