diff options
Diffstat (limited to 'net/core/iovec.c')
-rw-r--r-- | net/core/iovec.c | 55 |
1 files changed, 28 insertions, 27 deletions
diff --git a/net/core/iovec.c b/net/core/iovec.c index 6db6ac3e9..9bc21ffc5 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -11,7 +11,8 @@ * Andrew Lunn : Errors in iovec copying. * Pedro Roque : Added memcpy_fromiovecend and * csum_..._fromiovecend. - * Andi Kleen : fixed error handling for 2.1 + * Andi Kleen : fixed error handling for 2.1 + * Alexey Kuznetsov: 2.1 optimisations */ @@ -19,6 +20,7 @@ #include <linux/sched.h> #include <linux/kernel.h> #include <linux/mm.h> +#include <linux/malloc.h> #include <linux/net.h> #include <linux/in6.h> #include <asm/uaccess.h> @@ -34,6 +36,9 @@ extern inline int min(int x, int y) /* * Verify iovec * verify area does a simple check for completly bogus addresses + * + * Save time not doing verify_area. copy_*_user will make this work + * in any case. */ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) @@ -42,42 +47,38 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) int len=0; int ct; - if(m->msg_name!=NULL) + if(m->msg_namelen) { if(mode==VERIFY_READ) { err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - } - else - { - err=verify_area(mode, m->msg_name, m->msg_namelen); + if(err<0) + return err; } - if(err<0) - return err; m->msg_name = address; + } else + m->msg_name = NULL; + + if (m->msg_iovlen > UIO_FASTIOV) + { + iov = kmalloc(m->msg_iovlen*sizeof(struct iovec), GFP_KERNEL); + if (!iov) + return -ENOMEM; } - if(m->msg_control!=NULL) + err = copy_from_user(iov, m->msg_iov, sizeof(struct iovec)*m->msg_iovlen); + if (err) { - err=verify_area(mode, m->msg_control, m->msg_controllen); - if(err) - return err; + if (m->msg_iovlen > UIO_FASTIOV) + kfree(iov); + return -EFAULT; } - + for(ct=0;ct<m->msg_iovlen;ct++) - { - err = copy_from_user(&iov[ct], &m->msg_iov[ct], - sizeof(struct iovec)); - if (err) - return err; - - err = verify_area(mode, iov[ct].iov_base, iov[ct].iov_len); - if(err) - return err; len+=iov[ct].iov_len; - } - m->msg_iov=&iov[0]; + + m->msg_iov=iov; return len; } @@ -121,7 +122,7 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) err = copy_from_user(kdata, iov->iov_base, copy); if (err) { - return err; + return -EFAULT; } len-=copy; kdata+=copy; @@ -161,7 +162,7 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, err = copy_from_user(kdata, base, copy); if (err) { - return err; + return -EFAULT; } len-=copy; kdata+=copy; @@ -175,7 +176,7 @@ int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, err = copy_from_user(kdata, iov->iov_base, copy); if (err) { - return err; + return -EFAULT; } len-=copy; kdata+=copy; |