This is the mail archive of the
ecos-patches@sources.redhat.com
mailing list for the eCos project.
Net stack serialization fix
- From: Nick Garnett <nickg at ecoscentric dot com>
- To: ecos-patches at sources dot redhat dot com
- Date: 06 Nov 2002 19:24:15 +0000
- Subject: Net stack serialization fix
This patch fixes the network stack problems I mentioned here:
http://sources.redhat.com/ml/ecos-discuss/2002-10/msg00734.html
This ought to be checked over for sensibility, particularly by Gary.
It probably errs on the side of caution in some places.
Index: ChangeLog
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/bsd_tcpip/current/ChangeLog,v
retrieving revision 1.10
diff -u -5 -r1.10 ChangeLog
--- ChangeLog 4 Nov 2002 20:23:24 -0000 1.10
+++ ChangeLog 6 Nov 2002 19:14:50 -0000
@@ -1,5 +1,13 @@
+2002-11-06 Nick Garnett <nickg@ecoscentric.com>
+
+ * src/sys/kern/sockio.c: Added calls to splsoftnet() and
+ splx() to various functions. These are intended to avoid race
+ conditions between threads that are making simultaneous calls on
+ the same socket. This should duplicate the conditions that the
+ code expects in the BSD kernel.
+
2002-11-04 Gary Thomas <gthomas@ecoscentric.com>
* src/sys/net/if.c (if_attach): Moved check for ifq_maxlen to
this function since it can't be checked until the device comes
online, which may not be a sysinit time for PCMCIA devices.
Index: src/sys/kern/sockio.c
===================================================================
RCS file: /cvs/ecos/ecos-opt/net/net/bsd_tcpip/current/src/sys/kern/sockio.c,v
retrieving revision 1.2
diff -u -5 -r1.2 sockio.c
--- src/sys/kern/sockio.c 3 Nov 2002 19:49:44 -0000 1.2
+++ src/sys/kern/sockio.c 6 Nov 2002 19:15:00 -0000
@@ -212,10 +212,11 @@
static int
bsd_socket(cyg_nstab_entry *nste, int domain, int type,
int protocol, cyg_file *file)
{
+ register int s = splsoftnet();
int error = 0;
struct socket *so;
error = socreate(domain, &so, type, protocol, (struct proc *)&proc0);
@@ -231,10 +232,11 @@
file->f_offset = 0;
file->f_data = (CYG_ADDRWORD)so;
file->f_xops = (CYG_ADDRWORD)&bsd_sockops;
}
+ splx(s);
return error;
}
//==========================================================================
@@ -243,38 +245,45 @@
// -------------------------------------------------------------------------
static int
bsd_bind(cyg_file *fp, const sockaddr *sa, socklen_t len)
{
+ register int s = splsoftnet();
int error;
error = sobind((struct socket *)fp->f_data, (sockaddr *)sa, 0);
+
+ splx(s);
return error;
}
// -------------------------------------------------------------------------
static int
bsd_connect(cyg_file *fp, const sockaddr *sa, socklen_t len)
{
+ register int s = splsoftnet();
struct socket *so;
- int error, s;
+ int error;
so = (struct socket *)fp->f_data;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING))
+ {
+ splx(s);
return (EALREADY);
+ }
error = soconnect(so, (struct sockaddr *)sa, 0);
if (error)
goto bad;
if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
+ splx(s);
return (EINPROGRESS);
}
- s = splsoftnet();
while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
error = tsleep((caddr_t)&so->so_timeo, PSOCK | PCATCH,
"netcon", 0);
if (error)
break;
@@ -283,15 +292,15 @@
if (error == 0) {
error = so->so_error;
so->so_error = 0;
}
- splx(s);
-
bad:
so->so_state &= ~SS_ISCONNECTING;
+ splx(s);
+
return error;
}
// -------------------------------------------------------------------------
@@ -454,18 +463,22 @@
// -------------------------------------------------------------------------
static int
bsd_listen(cyg_file *fp, int backlog)
{
- return (solisten((struct socket *)fp->f_data, backlog, 0));
+ register int s = splsoftnet();
+ int err = (solisten((struct socket *)fp->f_data, backlog, 0));
+ splx(s);
+ return err;
}
// -------------------------------------------------------------------------
static int
bsd_getname(cyg_file *fp, sockaddr *asa, socklen_t *alen, int peer)
{
+ register int s = splsoftnet();
struct socket *so;
socklen_t len = 0;
int error;
sockaddr *sa;
@@ -475,10 +488,11 @@
so = (struct socket *)fp->f_data;
sa = 0;
if (peer) {
// getpeername()
if ((so->so_state & (SS_ISCONNECTED|SS_ISCONFIRMING)) == 0) {
+ splx(s);
return (ENOTCONN);
}
error = (*so->so_proto->pr_usrreqs->pru_peeraddr)(so, &sa);
} else {
// getsockname()
@@ -499,27 +513,32 @@
gotnothing:
*alen = len;
bad:
if (sa)
FREE(sa, M_SONAME);
+ splx(s);
return (error);
}
// -------------------------------------------------------------------------
static int
bsd_shutdown(cyg_file *fp, int how)
{
- return (soshutdown((struct socket *)fp->f_data, how));
+ register int s = splsoftnet();
+ int err = (soshutdown((struct socket *)fp->f_data, how));
+ splx(s);
+ return err;
}
// -------------------------------------------------------------------------
static int
bsd_getsockopt(cyg_file *fp, int level, int optname,
void *optval, socklen_t *optlen)
{
+ register int s = splsoftnet();
socklen_t valsize = 0;
int error;
struct sockopt opt;
if( optval != NULL && optlen != NULL)
@@ -534,29 +553,34 @@
error = sogetopt((struct socket *)fp->f_data, &opt);
if (error == 0) {
*optlen = opt.sopt_valsize;
}
+ splx(s);
return (error);
}
// -------------------------------------------------------------------------
static int
bsd_setsockopt(cyg_file *fp, int level, int optname,
const void *optval, socklen_t optlen)
{
+ register int s = splsoftnet();
+ int err;
struct sockopt opt;
opt.sopt_dir = SOPT_SET;
opt.sopt_level = level;
opt.sopt_name = optname;
opt.sopt_val = (void *)optval;
opt.sopt_valsize = optlen;
opt.sopt_p = 0;
- return sosetopt((struct socket *)fp->f_data, &opt);
+ err = sosetopt((struct socket *)fp->f_data, &opt);
+ splx(s);
+ return err;
}
// -------------------------------------------------------------------------
static int
@@ -579,21 +603,27 @@
// -------------------------------------------------------------------------
static int
bsd_read(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
- return (soreceive((struct socket *)fp->f_data, (struct sockaddr **)0,
- uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
+ register int s = splsoftnet();
+ int err = (soreceive((struct socket *)fp->f_data, (struct sockaddr **)0,
+ uio, (struct mbuf **)0, (struct mbuf **)0, (int *)0));
+ splx(s);
+ return err;
}
// -------------------------------------------------------------------------
static int
bsd_write(struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio)
{
- return (sosend((struct socket *)fp->f_data, (struct sockaddr *)0,
- uio, (struct mbuf *)0, (struct mbuf *)0, 0, 0));
+ register int s = splsoftnet();
+ int err = (sosend((struct socket *)fp->f_data, (struct sockaddr *)0,
+ uio, (struct mbuf *)0, (struct mbuf *)0, 0, 0));
+ splx(s);
+ return err;
}
// -------------------------------------------------------------------------
static int
@@ -605,20 +635,23 @@
// -------------------------------------------------------------------------
static int
bsd_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd, CYG_ADDRWORD data)
{
+ register int s = splsoftnet();
+ int err = 0;
struct socket *so = (struct socket *)fp->f_data;
void *p = 0;
switch (cmd) {
case FIONBIO:
if (*(int *)data)
so->so_state |= SS_NBIO;
else
so->so_state &= ~SS_NBIO;
+ splx(s);
return (0);
case FIOASYNC:
if (*(int *)data) {
so->so_state |= SS_ASYNC;
@@ -627,30 +660,37 @@
} else {
so->so_state &= ~SS_ASYNC;
so->so_rcv.sb_flags &= ~SB_ASYNC;
so->so_snd.sb_flags &= ~SB_ASYNC;
}
+ splx(s);
return (0);
case FIONREAD:
*(int *)data = so->so_rcv.sb_cc;
+ splx(s);
return (0);
case SIOCATMARK:
*(int *)data = (so->so_state&SS_RCVATMARK) != 0;
+ splx(s);
return (0);
}
/*
* Interface/routing/protocol specific ioctls:
* interface and routing ioctls should have a
* different entry since a socket's unnecessary
*/
if (IOCGROUP(cmd) == 'i')
- return (ifioctl(so, (u_long)cmd, (caddr_t)data, p));
+ err = (ifioctl(so, (u_long)cmd, (caddr_t)data, p));
if (IOCGROUP(cmd) == 'r')
- return (rtioctl((u_long)cmd, (caddr_t)data, p));
- return ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, (caddr_t)data, 0, 0));
+ err = (rtioctl((u_long)cmd, (caddr_t)data, p));
+ else
+ err = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, (caddr_t)data, 0, 0));
+
+ splx(s);
+ return err;
}
#if 0 // DEBUG support
static int
bsd_ioctl(struct CYG_FILE_TAG *fp, CYG_ADDRWORD cmd, CYG_ADDRWORD data)
@@ -715,32 +755,38 @@
// -------------------------------------------------------------------------
static int
bsd_close(struct CYG_FILE_TAG *fp)
{
+ register int s = splsoftnet();
int error = 0;
if (fp->f_data)
error = soclose((struct socket *)fp->f_data);
fp->f_data = 0;
+ splx(s);
return (error);
}
// -------------------------------------------------------------------------
static int
bsd_fstat(struct CYG_FILE_TAG *fp, struct stat *buf)
{
+ register int s = splsoftnet();
register struct socket *so = (struct socket *)fp->f_data;
-
+ int err;
+
bzero((caddr_t)buf, sizeof (*buf));
// Mark socket as a fifo for now. We need to add socket types to
// sys/stat.h.
buf->st_mode = __stat_mode_FIFO;
- return ((*so->so_proto->pr_usrreqs->pru_sense)(so, buf));
+ err = ((*so->so_proto->pr_usrreqs->pru_sense)(so, buf));
+ splx(s);
+ return err;
}
// -------------------------------------------------------------------------
static int
@@ -836,10 +882,11 @@
// recvit() function is uipc_syscalls.c.
static int
bsd_recvit(cyg_file *fp, struct msghdr *mp, socklen_t *namelenp, ssize_t *retsize)
{
+ register int s = splsoftnet();
struct uio auio;
struct iovec *iov;
int i;
size_t len;
int error;
@@ -857,10 +904,11 @@
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
/* Don't allow sum > SSIZE_MAX */
if (iov->iov_len > SSIZE_MAX ||
(auio.uio_resid += iov->iov_len) > SSIZE_MAX)
+ splx(s);
return (EINVAL);
}
len = auio.uio_resid;
so = (struct socket *)fp->f_data;
@@ -953,10 +1001,11 @@
out:
if (fromsa)
FREE(fromsa, M_SONAME);
if (control)
m_freem(control);
+ splx(s);
return (error);
}
// -------------------------------------------------------------------------
// sendit()
@@ -964,10 +1013,11 @@
// synonymous function is uipc_syscalls.c.
static int
bsd_sendit(cyg_file *fp, const struct msghdr *mp, int flags, ssize_t *retsize)
{
+ register int s = splsoftnet();
struct uio auio;
register struct iovec *iov;
register int i;
struct mbuf *control;
struct sockaddr *to;
@@ -983,15 +1033,17 @@
iov = mp->msg_iov;
for (i = 0; i < mp->msg_iovlen; i++, iov++) {
/* Don't allow sum > SSIZE_MAX */
if (iov->iov_len > SSIZE_MAX ||
(auio.uio_resid += iov->iov_len) > SSIZE_MAX)
+ splx(s);
return (EINVAL);
}
if (mp->msg_name) {
error = getsockaddr(&to, mp->msg_name, mp->msg_namelen);
if (error) {
+ splx(s);
return (error);
}
} else {
to = 0;
}
@@ -1038,10 +1090,11 @@
if (error == 0)
*retsize = len - auio.uio_resid;
bad:
if (to)
FREE(to, M_SONAME);
+ splx(s);
return (error);
}
static int
getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len)
--
Nick Garnett - eCos Kernel Architect
http://www.eCosCentric.com/