Skip to content

Commit

Permalink
iovec: move memcpy_from/toiovecend to lib/iovec.c
Browse files Browse the repository at this point in the history
ERROR: "memcpy_fromiovecend" [drivers/vhost/vhost_scsi.ko] undefined!

commit 9f977ef
    vhost-scsi: Include prot_bytes into expected data transfer length
in target-pending makes drivers/vhost/scsi.c call memcpy_fromiovecend().
This function is not available when CONFIG_NET is not enabled.

socket.h already includes uio.h, so no callers need updating.

Reported-by: Randy Dunlap <[email protected]>
Cc: Stephen Rothwell <[email protected]>
Cc: "David S. Miller" <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
Signed-off-by: Michael S. Tsirkin <[email protected]>
Signed-off-by: Nicholas Bellinger <[email protected]>
  • Loading branch information
mstsirkin authored and Nicholas Bellinger committed Jun 27, 2014
1 parent 97c99b4 commit ac5ccdb
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 60 deletions.
4 changes: 0 additions & 4 deletions include/linux/socket.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,8 +305,6 @@ struct ucred {
/* IPX options */
#define IPX_TYPE 1

extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
int offset, int len);
extern int csum_partial_copy_fromiovecend(unsigned char *kdata,
struct iovec *iov,
int offset,
Expand All @@ -315,8 +313,6 @@ extern unsigned long iov_pages(const struct iovec *iov, int offset,
unsigned long nr_segs);

extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode);
extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
int offset, int len);
extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr);
extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);

Expand Down
5 changes: 4 additions & 1 deletion include/linux/uio.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count)

int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len);
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len);

int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
int offset, int len);
int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
int offset, int len);

#endif
55 changes: 55 additions & 0 deletions lib/iovec.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,58 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
return 0;
}
EXPORT_SYMBOL(memcpy_toiovec);

/*
* Copy kernel to iovec. Returns -EFAULT on error.
*/

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)
{
/* 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);
55 changes: 0 additions & 55 deletions net/core/iovec.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,61 +74,6 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a
return err;
}

/*
* Copy kernel to iovec. Returns -EFAULT on error.
*/

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)
{
/* 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);

/*
* And now for the all-in-one: copy and checksum from a user iovec
* directly to a datagram
Expand Down

0 comments on commit ac5ccdb

Please sign in to comment.