Messages in this thread Patch in this message | | | Date | Mon, 06 Apr 1998 11:48:18 -0700 | From | Bill Hawes <> | Subject | patch for 2.1.92 net/socket.c et al |
| |
The attached patch to fixes a few problems in net/socket.c and related code.
In socket.c I've changed the allocation of iovecs (when necessary) to use the sock_malloc() call, as suggested by Alexey. This provides a consistent way of tracking auxiliary memory used by a socket, and keeps the allocation and cleanup at the client level.The corresponding kmalloc() calls in net/core/iovec.c have been removed.
I've also removed a useless test for a negative unsigned quantity, and simplified the code used to call kill_fasync().
In net/core/sock.c I've simplified the implementation of sock_wspace() a bit, as there's no need for two atomic reads. In sock_alloc_send_skb the xchg getting the sk->err field has been replaced with sock_error(), as the sign of the error must be inverted. I've also simplified the logic of allocating with a fallback size.
Regards, Bill--- linux-2.1.92/net/socket.c.old Fri Apr 3 19:30:04 1998 +++ linux-2.1.92/net/socket.c Sun Apr 5 14:20:55 1998 @@ -547,20 +547,19 @@ return -1; switch (how) { - case 0: - kill_fasync(sock->fasync_list, SIGIO); - break; - case 1: - if (!(sock->flags & SO_WAITDATA)) - kill_fasync(sock->fasync_list, SIGIO); - break; - case 2: - if (sock->flags & SO_NOSPACE) - { - kill_fasync(sock->fasync_list, SIGIO); - sock->flags &= ~SO_NOSPACE; - } + case 1: + if (sock->flags & SO_WAITDATA) break; + goto call_kill; + case 2: + if (!(sock->flags & SO_NOSPACE)) + break; + sock->flags &= ~SO_NOSPACE; + /* fall through */ + case 0: + call_kill: + kill_fasync(sock->fasync_list, SIGIO); + break; } return 0; } @@ -827,6 +826,7 @@ sys_close(err); goto restart; } + /* N.B. Should check for errors here */ move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen); } @@ -912,13 +912,13 @@ { struct socket *sock; char address[MAX_SOCK_ADDR]; - int len; - int err; + int len, err; lock_kernel(); if ((sock = sockfd_lookup(fd, &err))!=NULL) { - if((err=sock->ops->getname(sock, (struct sockaddr *)address, &len, 1))==0) + err = sock->ops->getname(sock, (struct sockaddr *)address, &len, 1); + if (!err) err=move_addr_to_user(address,len, usockaddr, usockaddr_len); sockfd_put(sock); } @@ -940,28 +940,22 @@ lock_kernel(); sock = sockfd_lookup(fd, &err); - if (!sock) - goto out; - err = -EINVAL; - if (len < 0) - goto out_put; - - iov.iov_base=buff; - iov.iov_len=len; - msg.msg_name=NULL; - msg.msg_namelen=0; - msg.msg_iov=&iov; - msg.msg_iovlen=1; - msg.msg_control=NULL; - msg.msg_controllen=0; - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - msg.msg_flags = flags; - err = sock_sendmsg(sock, &msg, len); + if (sock) { + iov.iov_base=buff; + iov.iov_len=len; + msg.msg_name=NULL; + msg.msg_namelen=0; + msg.msg_iov=&iov; + msg.msg_iovlen=1; + msg.msg_control=NULL; + msg.msg_controllen=0; + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + msg.msg_flags = flags; + err = sock_sendmsg(sock, &msg, len); -out_put: - sockfd_put(sock); -out: + sockfd_put(sock); + } unlock_kernel(); return err; } @@ -1140,11 +1134,11 @@ { struct socket *sock; char address[MAX_SOCK_ADDR]; - struct iovec iov[UIO_FASTIOV]; + struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; unsigned char ctl[sizeof(struct cmsghdr) + 20]; /* 20 is size of ipv6_pktinfo */ unsigned char *ctl_buf = ctl; struct msghdr msg_sys; - int err, ctl_len, total_len; + int err, ctl_len, iov_size, total_len; lock_kernel(); @@ -1152,20 +1146,29 @@ if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) goto out; + sock = sockfd_lookup(fd, &err); + if (!sock) + goto out; + /* do not move before msg_sys is valid */ err = -EINVAL; if (msg_sys.msg_iovlen > UIO_MAXIOV) - goto out; + goto out_put; + + /* Check whether to allocate the iovec area*/ + err = -ENOMEM; + iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); + if (msg_sys.msg_iovlen > 1 /* UIO_FASTIOV */) { + iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); + if (!iov) + goto out_put; + } /* This will also move the address data into kernel space */ err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); if (err < 0) - goto out; - total_len=err; - - sock = sockfd_lookup(fd, &err); - if (!sock) goto out_freeiov; + total_len = err; ctl_len = msg_sys.msg_controllen; if (ctl_len) @@ -1181,7 +1184,7 @@ err = -ENOBUFS; ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); if (ctl_buf == NULL) - goto out_put; + goto out_freeiov; } err = -EFAULT; if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len)) @@ -1197,11 +1200,11 @@ out_freectl: if (ctl_buf != ctl) sock_kfree_s(sock->sk, ctl_buf, ctl_len); +out_freeiov: + if (iov != iovstack) + sock_kfree_s(sock->sk, iov, iov_size); out_put: sockfd_put(sock); -out_freeiov: - if (msg_sys.msg_iov != iov) - kfree(msg_sys.msg_iov); out: unlock_kernel(); return err; @@ -1218,9 +1221,7 @@ struct iovec *iov=iovstack; struct msghdr msg_sys; unsigned long cmsg_ptr; - int err; - int total_len; - int len = 0; + int err, iov_size, total_len, len; /* kernel mode address */ char addr[MAX_SOCK_ADDR]; @@ -1234,10 +1235,23 @@ if (copy_from_user(&msg_sys,msg,sizeof(struct msghdr))) goto out; - err=-EINVAL; - if (msg_sys.msg_iovlen > UIO_MAXIOV) + sock = sockfd_lookup(fd, &err); + if (!sock) goto out; + + err = -EINVAL; + if (msg_sys.msg_iovlen > UIO_MAXIOV) + goto out_put; + /* Check whether to allocate the iovec area*/ + err = -ENOMEM; + iov_size = msg_sys.msg_iovlen * sizeof(struct iovec); + if (msg_sys.msg_iovlen > UIO_FASTIOV) { + iov = sock_kmalloc(sock->sk, iov_size, GFP_KERNEL); + if (!iov) + goto out_put; + } + /* * Save the user-mode address (verify_iovec will change the * kernel msghdr to use the kernel address space) @@ -1245,41 +1259,43 @@ uaddr = msg_sys.msg_name; uaddr_len = &msg->msg_namelen; - err=verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); - if (err<0) - goto out; - + err = verify_iovec(&msg_sys, iov, addr, VERIFY_WRITE); + if (err < 0) + goto out_freeiov; total_len=err; cmsg_ptr = (unsigned long)msg_sys.msg_control; msg_sys.msg_flags = 0; - if ((sock = sockfd_lookup(fd, &err))!=NULL) - { - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - err=sock_recvmsg(sock, &msg_sys, total_len, flags); - if(err>=0) - len=err; - sockfd_put(sock); - } - if (msg_sys.msg_iov != iov) - kfree(msg_sys.msg_iov); + if (sock->file->f_flags & O_NONBLOCK) + flags |= MSG_DONTWAIT; + err = sock_recvmsg(sock, &msg_sys, total_len, flags); + if (err < 0) + goto out_freeiov; + len = err; - if (uaddr != NULL && err>=0) + if (uaddr != NULL) { err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len); - if (err < 0) - goto out; + if (err < 0) + goto out_freeiov; + } err = __put_user(msg_sys.msg_flags, &msg->msg_flags); if (err) - goto out; + goto out_freeiov; err = __put_user((unsigned long)msg_sys.msg_control-cmsg_ptr, &msg->msg_controllen); + if (err) + goto out_freeiov; + err = len; + +out_freeiov: + if (iov != iovstack) + sock_kfree_s(sock->sk, iov, iov_size); +out_put: + sockfd_put(sock); out: unlock_kernel(); - if(err<0) - return err; - return len; + return err; } @@ -1462,10 +1478,13 @@ sk_init(); +#ifdef SLAB_SKB /* * Initialize skbuff SLAB cache */ skb_init(); +#endif + /* * Wan router layer. --- linux-2.1.92/net/core/sock.c.old Fri Apr 3 19:27:11 1998 +++ linux-2.1.92/net/core/sock.c Sun Apr 5 17:24:14 1998 @@ -589,38 +589,37 @@ */ unsigned long sock_rspace(struct sock *sk) { - int amt; + int amt = 0; if (sk != NULL) { - /* This used to have some bizzare complications that + /* This used to have some bizarre complications that * to attempt to reserve some amount of space. This doesn't * make sense, since the number returned here does not * actually reflect allocated space, but rather the amount * of space we committed to. We gamble that we won't * run out of memory, and returning a smaller number does - * not change the gamble. If we loose the gamble tcp still + * not change the gamble. If we lose the gamble tcp still * works, it may just slow down for retransmissions. */ amt = sk->rcvbuf - atomic_read(&sk->rmem_alloc); if (amt < 0) - return(0); - return(amt); + amt = 0; } - return(0); + return amt; } /* FIXME: this is also insane. See above comment */ unsigned long sock_wspace(struct sock *sk) { - if (sk != NULL) { - if (sk->shutdown & SEND_SHUTDOWN) - return(0); - if (atomic_read(&sk->wmem_alloc) >= sk->sndbuf) - return(0); - return sk->sndbuf - atomic_read(&sk->wmem_alloc); + int amt = 0; + + if (sk != NULL && !(sk->shutdown & SEND_SHUTDOWN)) { + amt = sk->sndbuf - atomic_read(&sk->wmem_alloc); + if (amt < 0) + amt = 0; } - return(0); + return amt; } /* It is almost wait_for_tcp_memory minus release_sock/lock_sock. @@ -653,13 +652,17 @@ * Generic send/receive buffer handlers */ -struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, unsigned long fallback, int noblock, int *errcode) +struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, + unsigned long fallback, int noblock, int *errcode) { int err; struct sk_buff *skb; - do { - if ((err = xchg(&sk->err,0)) != 0) + while (1) { + unsigned long try_size = size; + + err = sock_error(sk); + if (err != 0) goto failure; /* @@ -676,33 +679,32 @@ if (sk->shutdown&SEND_SHUTDOWN) goto failure; - if (!fallback) - skb = sock_wmalloc(sk, size, 0, sk->allocation); - else { - /* The buffer get won't block, or use the atomic queue. It does - produce annoying no free page messages still.... */ + if (fallback) { + /* The buffer get won't block, or use the atomic queue. + * It does produce annoying no free page messages still. + */ skb = sock_wmalloc(sk, size, 0, GFP_BUFFER); - if (!skb) - skb=sock_wmalloc(sk, fallback, 0, sk->allocation); + if (skb) + break; + try_size = fallback; } + skb = sock_wmalloc(sk, try_size, 0, sk->allocation); + if (skb) + break; /* * This means we have too many buffers for this socket already. */ - /* The following code is stolen "as is" from tcp.c */ - - if (skb==NULL) { - sk->socket->flags |= SO_NOSPACE; - err = -EAGAIN; - if (noblock) - goto failure; - err = -ERESTARTSYS; - if (signal_pending(current)) - goto failure; - sock_wait_for_wmem(sk); - } - } while (skb==NULL); + sk->socket->flags |= SO_NOSPACE; + err = -EAGAIN; + if (noblock) + goto failure; + err = -ERESTARTSYS; + if (signal_pending(current)) + goto failure; + sock_wait_for_wmem(sk); + } return skb; --- linux-2.1.92/net/core/iovec.c.old Fri Apr 3 19:27:11 1998 +++ linux-2.1.92/net/core/iovec.c Sun Apr 5 14:26:02 1998 @@ -29,7 +29,8 @@ #include <net/checksum.h> /* - * Verify iovec + * Verify iovec. The caller must ensure that the iovec is big enough + * to hold the message iovec. * * Save time not doing verify_area. copy_*_user will make this work * in any case. @@ -37,8 +38,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) { - int size = m->msg_iovlen * sizeof(struct iovec); - int err, ct; + int size, err, ct; if(m->msg_namelen) { @@ -53,28 +53,16 @@ } else m->msg_name = NULL; - if (m->msg_iovlen > UIO_FASTIOV) - { - err = -ENOMEM; - iov = kmalloc(size, GFP_KERNEL); - if (!iov) - goto out; - } - + err = -EFAULT; + size = m->msg_iovlen * sizeof(struct iovec); if (copy_from_user(iov, m->msg_iov, size)) - goto out_free; + goto out; m->msg_iov=iov; for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) err += iov[ct].iov_len; out: return err; - -out_free: - err = -EFAULT; - if (m->msg_iovlen > UIO_FASTIOV) - kfree(iov); - goto out; } /*
| |