Blame view

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