patch for 2.1.90 net/core/iovec et al

Bill Hawes (whawes@star.net)
Tue, 24 Mar 1998 12:19:40 -0500


This is a multi-part message in MIME format.
--------------3E43FD95B8505B29D64594FD
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

I've attached a patch to simplify the iovec code and do some error code cleanup
related to the various iovec calls.

The simplification to the iovec code removes redundant code for handling an
offset into the iovec; all that needs to be done is to skip over iovecs until
the offset is properly contained within the current length.

The remaining changes are mostly error code cleanups; it appears that at some
point the xxxiovec routines returned a remainder count rather than an (EFAULT)
error code.

Regards,
Bill
--------------3E43FD95B8505B29D64594FD
Content-Type: text/plain; charset=us-ascii; name="net_iovec90-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="net_iovec90-patch"

--- linux-2.1.90/net/core/iovec.c.old Sun Mar 22 11:30:41 1998
+++ linux-2.1.90/net/core/iovec.c Mon Mar 23 17:05:33 1998
@@ -30,7 +30,6 @@

/*
* 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.
@@ -79,22 +78,21 @@
}

/*
- * Copy kernel to iovec.
+ * Copy kernel to iovec. Returns -EFAULT on error.
*
* Note: this modifies the original iovec.
*/

int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len)
{
- int err;
+ int err = -EFAULT;

while(len>0)
{
if(iov->iov_len)
{
int copy = min(iov->iov_len, len);
- err = copy_to_user(iov->iov_base, kdata, copy);
- if (err)
+ if (copy_to_user(iov->iov_base, kdata, copy))
goto out;
kdata+=copy;
len-=copy;
@@ -109,7 +107,7 @@
}

/*
- * Copy iovec to kernel.
+ * Copy iovec to kernel. Returns -EFAULT on error.
*
* Note: this modifies the original iovec.
*/
@@ -147,35 +145,23 @@
{
int err = -EFAULT;

- while(offset>0)
+ /* Skip over the finished iovecs */
+ while(offset >= iov->iov_len)
{
- if (offset > iov->iov_len)
- {
- offset -= iov->iov_len;
- }
- else
- {
- u8 *base = iov->iov_base + offset;
- int copy = min(len, iov->iov_len - offset);
-
- offset = 0;
-
- if (copy_from_user(kdata, base, copy))
- goto out;
- len-=copy;
- kdata+=copy;
- }
+ offset -= iov->iov_len;
iov++;
}

- while (len>0)
+ while (len > 0)
{
- int copy = min(len, iov->iov_len);
+ u8 *base = iov->iov_base + offset;
+ int copy = min(len, iov->iov_len - offset);

- if (copy_from_user(kdata, iov->iov_base, copy))
+ offset = 0;
+ if (copy_from_user(kdata, base, copy))
goto out;
- len-=copy;
- kdata+=copy;
+ len -= copy;
+ kdata += copy;
iov++;
}
err = 0;
@@ -195,51 +181,22 @@
int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov,
int offset, unsigned int len, int *csump)
{
- int partial_cnt = 0;
- int err = 0;
- int csum;
-
- do {
- int copy = iov->iov_len - offset;
-
- if (copy > 0) {
- u8 *base = iov->iov_base + offset;
-
- /* Normal case (single iov component) is fastly detected */
- if (len <= copy) {
- *csump = csum_and_copy_from_user(base, kdata,
- len, *csump, &err);
- goto out;
- }
+ int csum = *csump;
+ int partial_cnt = 0, err = 0;

- partial_cnt = copy % 4;
- if (partial_cnt) {
- copy -= partial_cnt;
- if (copy_from_user(kdata + copy, base + copy,
- partial_cnt))
- goto out_fault;
- }
-
- *csump = csum_and_copy_from_user(base, kdata, copy,
- *csump, &err);
- if (err)
- goto out;
- len -= copy + partial_cnt;
- kdata += copy + partial_cnt;
- iov++;
- break;
- }
+ /* Skip over the finished iovecs */
+ while (offset >= iov->iov_len)
+ {
+ offset -= iov->iov_len;
iov++;
- offset = -copy;
- } while (offset > 0);
-
- csum = *csump;
+ }

while (len > 0)
{
- u8 *base = iov->iov_base;
- unsigned int copy = min(len, iov->iov_len);
+ u8 *base = iov->iov_base + offset;
+ unsigned int copy = min(len, iov->iov_len - offset);

+ offset = 0;
/* There is a remnant from previous iov. */
if (partial_cnt)
{
--- linux-2.1.90/net/core/datagram.c.old Sat Mar 7 11:32:22 1998
+++ linux-2.1.90/net/core/datagram.c Mon Mar 23 16:54:29 1998
@@ -132,15 +132,13 @@
unsigned long flags;
save_flags(flags);
cli();
- skb=skb_peek(&sk->receive_queue);
+ skb = skb_peek(&sk->receive_queue);
if(skb!=NULL)
atomic_inc(&skb->users);
restore_flags(flags);
- if(skb==NULL) /* shouldn't happen but .. */
- goto restart;
- return skb;
- }
- skb = skb_dequeue(&sk->receive_queue);
+ } else
+ skb = skb_dequeue(&sk->receive_queue);
+
if (!skb) /* Avoid race if someone beats us to the data */
goto restart;
return skb;
@@ -163,30 +161,23 @@

int skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size)
{
- int err;
- err = copy_to_user(to, skb->h.raw+offset, size);
- if (err)
- {
- err = -EFAULT;
- }
+ int err = -EFAULT;
+
+ if (!copy_to_user(to, skb->h.raw + offset, size))
+ err = 0;
return err;
}


/*
* Copy a datagram to an iovec.
+ * Note: the iovec is modified during the copy.
*/

int skb_copy_datagram_iovec(struct sk_buff *skb, int offset, struct iovec *to,
int size)
{
- int err;
- err = memcpy_toiovec(to, skb->h.raw+offset, size);
- if (err)
- {
- err = -EFAULT;
- }
- return err;
+ return memcpy_toiovec(to, skb->h.raw + offset, size);
}

/*
--- linux-2.1.90/net/socket.c.old Sun Mar 22 11:30:44 1998
+++ linux-2.1.90/net/socket.c Mon Mar 23 17:17:05 1998
@@ -1141,19 +1142,21 @@
char address[MAX_SOCK_ADDR];
struct iovec iov[UIO_FASTIOV];
unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */
- struct msghdr msg_sys;
- int err= -EINVAL;
- int total_len;
unsigned char *ctl_buf = ctl;
+ struct msghdr msg_sys;
+ int err, total_len;

lock_kernel();

- err=-EFAULT;
+ err = -EFAULT;
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
goto out;
+
/* do not move before msg_sys is valid */
- if (msg_sys.msg_iovlen>UIO_MAXIOV)
+ err = -EINVAL;
+ if (msg_sys.msg_iovlen > UIO_MAXIOV)
goto out;
+
/* This will also move the address data into kernel space */
err = verify_iovec(&msg_sys, iov, address, VERIFY_READ);
if (err < 0)
@@ -1163,7 +1166,7 @@

sock = sockfd_lookup(fd, &err);
if (!sock)
- goto out;
+ goto out_freeiov;

if (msg_sys.msg_controllen)
{
@@ -1197,9 +1200,10 @@
if (ctl_buf != ctl)
sock_kfree_s(sock->sk, ctl_buf, msg_sys.msg_controllen);
failed2:
+ sockfd_put(sock);
+out_freeiov:
if (msg_sys.msg_iov != iov)
kfree(msg_sys.msg_iov);
- sockfd_put(sock);
out:
unlock_kernel();
return err;
@@ -1228,16 +1232,13 @@
int *uaddr_len;

lock_kernel();
+ err=-EFAULT;
if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr)))
- {
- err=-EFAULT;
goto out;
- }
- if (msg_sys.msg_iovlen>UIO_MAXIOV)
- {
- err=-EINVAL;
+
+ err=-EINVAL;
+ if (msg_sys.msg_iovlen > UIO_MAXIOV)
goto out;
- }

/*
* Save the user-mode address (verify_iovec will change the
--- linux-2.1.90/net/unix/af_unix.c.old Sun Mar 22 11:30:44 1998
+++ linux-2.1.90/net/unix/af_unix.c Mon Mar 23 23:56:25 1998
@@ -687,17 +687,19 @@

skb=sock_alloc_send_skb(sk, len, 0, nonblock, &err); /* Marker object */
if(skb==NULL)
- return err;
+ goto out;
memcpy(&UNIXCB(skb), cmsg, sizeof(*cmsg));
- if (len)
- memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ if (len) {
+ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov,
+ len);
+ if (err)
+ goto out_free;
+ }
+
sk->state=TCP_CLOSE;
other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err);
if(other==NULL)
- {
- kfree_skb(skb);
- return err;
- }
+ goto out_free;
other->ack_backlog++;
unix_peer(sk)=other;
skb_queue_tail(&other->receive_queue,skb);
@@ -738,6 +740,11 @@
if (!sk->protinfo.af_unix.addr)
unix_autobind(sock);
return 0;
+
+out_free:
+ kfree_skb(skb);
+out:
+ return err;
}


@@ -908,8 +915,8 @@
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
- unix_socket *other;
struct sockaddr_un *sunaddr=msg->msg_name;
+ unix_socket *other;
int namelen = 0; /* fake GCC */
int err;
unsigned hash;
@@ -935,9 +942,8 @@
unix_autobind(sock);

skb = sock_alloc_send_skb(sk, len, 0, msg->msg_flags&MSG_DONTWAIT, &err);
-
if (skb==NULL)
- return err;
+ goto out;

memcpy(UNIXCREDS(skb), &scm->creds, sizeof(struct ucred));
UNIXCB(skb).attr = msg->msg_flags;
@@ -945,7 +951,9 @@
unix_attach_fds(scm, skb);

skb->h.raw = skb->data;
- memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
+ if (err)
+ goto out_free;

other = unix_peer(sk);
if (other && other->dead)
@@ -957,26 +965,18 @@
unix_unlock(other);
unix_peer(sk)=NULL;
other = NULL;
- if (sunaddr == NULL) {
- kfree_skb(skb);
- return -ECONNRESET;
- }
+ err = -ECONNRESET;
+ if (sunaddr == NULL)
+ goto out_free;
}
if (!other)
{
other = unix_find_other(sunaddr, namelen, sk->type, hash, &err);
-
if (other==NULL)
- {
- kfree_skb(skb);
- return err;
- }
+ goto out_free;
+ err = -EINVAL;
if (!unix_may_send(sk, other))
- {
- unix_unlock(other);
- kfree_skb(skb);
- return -EINVAL;
- }
+ goto out_unlock;
}

skb_queue_tail(&other->receive_queue, skb);
@@ -985,6 +985,13 @@
if (!unix_peer(sk))
unix_unlock(other);
return len;
+
+out_unlock:
+ unix_unlock(other);
+out_free:
+ kfree_skb(skb);
+out:
+ return err;
}


@@ -1265,9 +1272,7 @@
}

chunk = min(skb->len, size);
- /* N.B. This could fail with a non-zero value (which means -EFAULT
- * and the non-zero value is the number of bytes not copied).
- */
+ /* N.B. This could fail with -EFAULT */
memcpy_toiovec(msg->msg_iov, skb->data, chunk);
copied += chunk;
size -= chunk;
--- linux-2.1.90/net/packet/af_packet.c.old Sun Mar 22 11:30:44 1998
+++ linux-2.1.90/net/packet/af_packet.c Tue Mar 24 11:22:33 1998
@@ -262,9 +262,9 @@
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
+ struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
struct sk_buff *skb;
struct device *dev;
- struct sockaddr_pkt *saddr=(struct sockaddr_pkt *)msg->msg_name;
unsigned short proto=0;
int err;

@@ -309,6 +309,7 @@
return -EMSGSIZE;

dev_lock_list();
+ err = -ENOBUFS;
skb = sock_wmalloc(sk, len+dev->hard_header_len+15, 0, GFP_KERNEL);

/*
@@ -318,10 +319,7 @@
*/

if (skb == NULL)
- {
- dev_unlock_list();
- return(-ENOBUFS);
- }
+ goto out_unlock;

/*
* Fill it in
@@ -339,36 +337,32 @@
skb->data -= dev->hard_header_len;
skb->tail -= dev->hard_header_len;
}
+
+ /* Returns -EFAULT on error */
err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->priority;
- dev_unlock_list();
+ if (err)
+ goto out_free;
+
+ err = -ENETDOWN;
+ if (!(dev->flags & IFF_UP))
+ goto out_free;

/*
* Now send it
*/

- if (err)
- {
- err = -EFAULT;
- }
- else
- {
- if (!(dev->flags & IFF_UP))
- {
- err = -ENETDOWN;
- }
- }
-
- if (err)
- {
- kfree_skb(skb);
- return err;
- }
-
+ dev_unlock_list();
dev_queue_xmit(skb);
return(len);
+
+out_free:
+ kfree_skb(skb);
+out_unlock:
+ dev_unlock_list();
+ return err;
}
#endif

@@ -434,13 +428,12 @@
struct scm_cookie *scm)
{
struct sock *sk = sock->sk;
+ struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
struct sk_buff *skb;
struct device *dev;
- struct sockaddr_ll *saddr=(struct sockaddr_ll *)msg->msg_name;
unsigned short proto;
- int ifindex;
- int err;
- int reserve = 0;
+ unsigned char *addr;
+ int ifindex, err, reserve = 0;

/*
* Check the flags.
@@ -454,13 +447,15 @@
*/

if (saddr == NULL) {
- ifindex = sk->protinfo.af_packet->ifindex;
- proto = sk->num;
+ ifindex = sk->protinfo.af_packet->ifindex;
+ proto = sk->num;
+ addr = NULL;
} else {
if (msg->msg_namelen < sizeof(struct sockaddr_ll))
return -EINVAL;
- ifindex = saddr->sll_ifindex;
- proto = saddr->sll_protocol;
+ ifindex = saddr->sll_ifindex;
+ proto = saddr->sll_protocol;
+ addr = saddr->sll_addr;
}

dev = dev_get_by_index(ifindex);
@@ -474,55 +469,50 @@

dev_lock_list();

- skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0, msg->msg_flags&MSG_DONTWAIT, &err);
-
- if (skb==NULL) {
- dev_unlock_list();
- return err;
- }
+ skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 0,
+ msg->msg_flags & MSG_DONTWAIT, &err);
+ if (skb==NULL)
+ goto out_unlock;

skb_reserve(skb, (dev->hard_header_len+15)&~15);
skb->nh.raw = skb->data;

if (dev->hard_header) {
- if (dev->hard_header(skb, dev, ntohs(proto),
- saddr ? saddr->sll_addr : NULL,
- NULL, len) < 0
- && sock->type == SOCK_DGRAM) {
- kfree_skb(skb);
- dev_unlock_list();
- return -EINVAL;
- }
+ int res;
+ err = -EINVAL;
+ res = dev->hard_header(skb, dev, ntohs(proto), addr, NULL, len);
if (sock->type != SOCK_DGRAM) {
skb->tail = skb->data;
skb->len = 0;
- }
+ } else if (res < 0)
+ goto out_free;
}

+ /* Returns -EFAULT on error */
err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
skb->protocol = proto;
skb->dev = dev;
skb->priority = sk->priority;
- dev_unlock_list();
+ if (err)
+ goto out_free;
+
+ err = -ENETDOWN;
+ if (!(dev->flags & IFF_UP))
+ goto out_free;

/*
* Now send it
*/

- if (err) {
- err = -EFAULT;
- } else {
- if (!(dev->flags & IFF_UP))
- err = -ENETDOWN;
- }
-
- if (err) {
- kfree_skb(skb);
- return err;
- }
-
+ dev_unlock_list();
dev_queue_xmit(skb);
return(len);
+
+out_free:
+ kfree_skb(skb);
+out_unlock:
+ dev_unlock_list();
+ return err;
}

static void packet_destroy_timer(unsigned long data)
@@ -699,6 +689,7 @@
static int packet_create(struct socket *sock, int protocol)
{
struct sock *sk;
+ int err;

if (!suser())
return -EPERM;
@@ -711,27 +702,23 @@

sock->state = SS_UNCONNECTED;
MOD_INC_USE_COUNT;
+
+ err = -ENOBUFS;
sk = sk_alloc(AF_PACKET, GFP_KERNEL, 1);
- if (sk == NULL) {
- MOD_DEC_USE_COUNT;
- return -ENOBUFS;
- }
+ if (sk == NULL)
+ goto out;

sk->reuse = 1;
+ sock->ops = &packet_ops;
#ifdef CONFIG_SOCK_PACKET
if (sock->type == SOCK_PACKET)
sock->ops = &packet_ops_spkt;
- else
#endif
- sock->ops = &packet_ops;
sock_init_data(sock,sk);

sk->protinfo.af_packet = kmalloc(sizeof(struct packet_opt), GFP_KERNEL);
- if (sk->protinfo.af_packet == NULL) {
- sk_free(sk);
- MOD_DEC_USE_COUNT;
- return -ENOBUFS;
- }
+ if (sk->protinfo.af_packet == NULL)
+ goto out_free;
memset(sk->protinfo.af_packet, 0, sizeof(struct packet_opt));
sk->zapped=0;
sk->family = AF_PACKET;
@@ -741,13 +728,11 @@
* Attach a protocol block
*/

+ sk->protinfo.af_packet->prot_hook.func = packet_rcv;
#ifdef CONFIG_SOCK_PACKET
if (sock->type == SOCK_PACKET)
sk->protinfo.af_packet->prot_hook.func = packet_rcv_spkt;
- else
#endif
- sk->protinfo.af_packet->prot_hook.func = packet_rcv;
-
sk->protinfo.af_packet->prot_hook.data = (void *)sk;

if (protocol) {
@@ -758,6 +743,12 @@

sklist_insert_socket(&packet_sklist, sk);
return(0);
+
+out_free:
+ sk_free(sk);
+out:
+ MOD_DEC_USE_COUNT;
+ return err;
}

/*
@@ -832,10 +823,8 @@

/* We can't use skb_copy_datagram here */
err = memcpy_toiovec(msg->msg_iov, skb->data, copied);
- if (err) {
- err = -EFAULT;
+ if (err)
goto out_free;
- }
sk->stamp=skb->stamp;

if (msg->msg_name)
@@ -932,37 +921,39 @@

static int packet_mc_add(struct sock *sk, struct packet_mreq *mreq)
{
- int err;
struct packet_mclist *ml, *i;
struct device *dev;
+ int err;

rtnl_shlock();

- dev = dev_get_by_index(mreq->mr_ifindex);
-
- i = NULL;
err = -ENODEV;
+ dev = dev_get_by_index(mreq->mr_ifindex);
if (!dev)
goto done;
+
err = -EINVAL;
if (mreq->mr_alen > dev->addr_len)
goto done;

+ err = -ENOBUFS;
i = (struct packet_mclist *)kmalloc(sizeof(*i), GFP_KERNEL);
+ if (i == NULL)
+ goto done;

+ err = 0;
for (ml=sk->protinfo.af_packet->mclist; ml; ml=ml->next) {
if (ml->ifindex == mreq->mr_ifindex &&
ml->type == mreq->mr_type &&
ml->alen == mreq->mr_alen &&
memcmp(ml->addr, mreq->mr_address, ml->alen) == 0) {
ml->count++;
- err = 0;
+ /* Free the new element ... */
+ kfree(i);
goto done;
}
}
- err = -ENOBUFS;
- if (i == NULL)
- goto done;
+
i->type = mreq->mr_type;
i->ifindex = mreq->mr_ifindex;
i->alen = mreq->mr_alen;
@@ -971,13 +962,9 @@
i->next = sk->protinfo.af_packet->mclist;
sk->protinfo.af_packet->mclist = i;
packet_dev_mc(dev, i, +1);
- i = NULL;
- err = 0;

done:
rtnl_shunlock();
- if (i)
- kfree(i);
return err;
}

@@ -1109,13 +1096,12 @@
case FIOGETOWN:
case SIOCGPGRP:
return put_user(sk->proc, (int *)arg);
- return(0);
case SIOCGSTAMP:
if(sk->stamp.tv_sec==0)
return -ENOENT;
- err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval));
- if (err)
- err = -EFAULT;
+ err = -EFAULT;
+ if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)))
+ err = 0;
return err;
case SIOCGIFFLAGS:
#ifndef CONFIG_INET

--------------3E43FD95B8505B29D64594FD--

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu