Diff below moves the socket lock "above" sosetopt(), sogetopt() and
sosplice(). While this adds a lot of lock/unlock dances in NFS, they
will be merge in a later diff.
sosetopt() modifies a socket fields so it needs the lock. sogetopt()
do not always need it, but it makes the code simpler to always grab
it and the code section is really small anyway.
ok?
Index: kern/uipc_socket.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_socket.c,v
retrieving revision 1.198
diff -u -p -r1.198 uipc_socket.c
--- kern/uipc_socket.c 27 Jul 2017 12:05:36 -0000 1.198
+++ kern/uipc_socket.c 2 Aug 2017 08:21:45 -0000
@@ -1073,7 +1073,9 @@ sosplice(struct socket *so, int fd, off_
struct file *fp;
struct socket *sosp;
struct sosplice *sp;
- int s, error = 0;
+ int error = 0;
+
+ soassertlocked(so);
if (sosplice_taskq == NULL)
sosplice_taskq = taskq_create("sosplice", 1, IPL_SOFTNET, 0);
@@ -1097,17 +1099,14 @@ sosplice(struct socket *so, int fd, off_
/* If no fd is given, unsplice by removing existing link. */
if (fd < 0) {
- s = solock(so);
/* Lock receive buffer. */
if ((error = sblock(so, &so->so_rcv,
(so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK)) != 0) {
- sounlock(s);
return (error);
}
if (so->so_sp->ssp_socket)
sounsplice(so, so->so_sp->ssp_socket, 1);
sbunlock(&so->so_rcv);
- sounlock(s);
return (0);
}
@@ -1129,17 +1128,14 @@ sosplice(struct socket *so, int fd, off_
pool_put(&sosplice_pool, sp);
}
- s = solock(so);
/* Lock both receive and send buffer. */
if ((error = sblock(so, &so->so_rcv,
(so->so_state & SS_NBIO) ? M_NOWAIT : M_WAITOK)) != 0) {
- sounlock(s);
FRELE(fp, curproc);
return (error);
}
if ((error = sblock(so, &sosp->so_snd, M_WAITOK)) != 0) {
sbunlock(&so->so_rcv);
- sounlock(s);
FRELE(fp, curproc);
return (error);
}
@@ -1185,7 +1181,6 @@ sosplice(struct socket *so, int fd, off_
release:
sbunlock(&sosp->so_snd);
sbunlock(&so->so_rcv);
- sounlock(s);
FRELE(fp, curproc);
return (error);
}
@@ -1565,15 +1560,15 @@ sowwakeup(struct socket *so)
int
sosetopt(struct socket *so, int level, int optname, struct mbuf *m0)
{
- int s, error = 0;
+ int error = 0;
struct mbuf *m = m0;
+ soassertlocked(so);
+
if (level != SOL_SOCKET) {
if (so->so_proto && so->so_proto->pr_ctloutput) {
- s = solock(so);
error = (*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so,
level, optname, m0);
- sounlock(s);
return (error);
}
error = ENOPROTOOPT;
@@ -1647,14 +1642,11 @@ sosetopt(struct socket *so, int level, i
error = EINVAL;
goto bad;
}
- s = solock(so);
if (sbcheckreserve(cnt, so->so_snd.sb_wat) ||
sbreserve(so, &so->so_snd, cnt)) {
- sounlock(s);
error = ENOBUFS;
goto bad;
}
- sounlock(s);
so->so_snd.sb_wat = cnt;
break;
@@ -1663,14 +1655,11 @@ sosetopt(struct socket *so, int level, i
error = EINVAL;
goto bad;
}
- s = solock(so);
if (sbcheckreserve(cnt, so->so_rcv.sb_wat) ||
sbreserve(so, &so->so_rcv, cnt)) {
- sounlock(s);
error = ENOBUFS;
goto bad;
}
- sounlock(s);
so->so_rcv.sb_wat = cnt;
break;
@@ -1724,10 +1713,8 @@ sosetopt(struct socket *so, int level, i
struct domain *dom = so->so_proto->pr_domain;
level = dom->dom_protosw->pr_protocol;
- s = solock(so);
error = (*so->so_proto->pr_ctloutput)
(PRCO_SETOPT, so, level, optname, m0);
- sounlock(s);
return (error);
}
error = ENOPROTOOPT;
@@ -1756,10 +1743,8 @@ sosetopt(struct socket *so, int level, i
break;
}
if (error == 0 && so->so_proto && so->so_proto->pr_ctloutput) {
- s = solock(so);
(*so->so_proto->pr_ctloutput)(PRCO_SETOPT, so,
level, optname, m0);
- sounlock(s);
m = NULL; /* freed by protocol */
}
}
@@ -1772,18 +1757,18 @@ bad:
int
sogetopt(struct socket *so, int level, int optname, struct mbuf **mp)
{
- int s, error = 0;
+ int error = 0;
struct mbuf *m;
+ soassertlocked(so);
+
if (level != SOL_SOCKET) {
if (so->so_proto && so->so_proto->pr_ctloutput) {
m = m_get(M_WAIT, MT_SOOPTS);
m->m_len = 0;
- s = solock(so);
error = (*so->so_proto->pr_ctloutput)(PRCO_GETOPT, so,
level, optname, m);
- sounlock(s);
if (error) {
m_free(m);
return (error);
@@ -1869,10 +1854,8 @@ sogetopt(struct socket *so, int level, i
struct domain *dom = so->so_proto->pr_domain;
level = dom->dom_protosw->pr_protocol;
- s = solock(so);
error = (*so->so_proto->pr_ctloutput)
(PRCO_GETOPT, so, level, optname, m);
- sounlock(s);
if (error) {
(void)m_free(m);
return (error);
@@ -1886,13 +1869,10 @@ sogetopt(struct socket *so, int level, i
case SO_SPLICE:
{
off_t len;
- int s;
- s = solock(so);
m->m_len = sizeof(off_t);
len = so->so_sp ? so->so_sp->ssp_len : 0;
memcpy(mtod(m, off_t *), &len, sizeof(off_t));
- sounlock(s);
break;
}
#endif /* SOCKET_SPLICE */
Index: kern/uipc_syscalls.c
===================================================================
RCS file: /cvs/src/sys/kern/uipc_syscalls.c,v
retrieving revision 1.156
diff -u -p -r1.156 uipc_syscalls.c
--- kern/uipc_syscalls.c 24 Jul 2017 15:07:39 -0000 1.156
+++ kern/uipc_syscalls.c 2 Aug 2017 08:17:41 -0000
@@ -940,7 +940,8 @@ sys_setsockopt(struct proc *p, void *v,
} */ *uap = v;
struct file *fp;
struct mbuf *m = NULL;
- int error;
+ struct socket *so;
+ int s, error;
if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
@@ -972,7 +973,10 @@ sys_setsockopt(struct proc *p, void *v,
}
m->m_len = SCARG(uap, valsize);
}
- error = sosetopt(fp->f_data, SCARG(uap, level), SCARG(uap, name), m);
+ so = fp->f_data;
+ s = solock(so);
+ error = sosetopt(so, SCARG(uap, level), SCARG(uap, name), m);
+ sounlock(s);
m = NULL;
bad:
m_freem(m);
@@ -993,7 +997,8 @@ sys_getsockopt(struct proc *p, void *v,
struct file *fp;
struct mbuf *m = NULL;
socklen_t valsize;
- int error;
+ struct socket *so;
+ int s, error;
if ((error = getsock(p, SCARG(uap, s), &fp)) != 0)
return (error);
@@ -1007,9 +1012,11 @@ sys_getsockopt(struct proc *p, void *v,
goto out;
} else
valsize = 0;
- if ((error = sogetopt(fp->f_data, SCARG(uap, level),
- SCARG(uap, name), &m)) == 0 && SCARG(uap, val) && valsize &&
- m != NULL) {
+ so = fp->f_data;
+ s = solock(so);
+ error = sogetopt(so, SCARG(uap, level), SCARG(uap, name), &m);
+ sounlock(s);
+ if (error == 0 && SCARG(uap, val) && valsize && m != NULL) {
if (valsize > m->m_len)
valsize = m->m_len;
error = copyout(mtod(m, caddr_t), SCARG(uap, val), valsize);
Index: nfs/krpc_subr.c
===================================================================
RCS file: /cvs/src/sys/nfs/krpc_subr.c,v
retrieving revision 1.29
diff -u -p -r1.29 krpc_subr.c
--- nfs/krpc_subr.c 24 Aug 2015 14:00:29 -0000 1.29
+++ nfs/krpc_subr.c 2 Aug 2017 08:17:41 -0000
@@ -211,7 +211,7 @@ krpc_call(struct sockaddr_in *sa, u_int
struct rpc_call *call;
struct rpc_reply *reply;
struct uio auio;
- int error, rcvflg, timo, secs, len;
+ int s, error, rcvflg, timo, secs, len;
static u_int32_t xid = 0;
char addr[INET_ADDRSTRLEN];
int *ip;
@@ -239,7 +239,10 @@ krpc_call(struct sockaddr_in *sa, u_int
tv.tv_usec = 0;
memcpy(mtod(m, struct timeval *), &tv, sizeof tv);
m->m_len = sizeof(tv);
- if ((error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m)))
+ s = solock(so);
+ error = sosetopt(so, SOL_SOCKET, SO_RCVTIMEO, m);
+ sounlock(s);
+ if (error)
goto out;
/*
@@ -251,7 +254,10 @@ krpc_call(struct sockaddr_in *sa, u_int
on = mtod(m, int32_t *);
m->m_len = sizeof(*on);
*on = 1;
- if ((error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m)))
+ s = solock(so);
+ error = sosetopt(so, SOL_SOCKET, SO_BROADCAST, m);
+ sounlock(s);
+ if (error)
goto out;
}
@@ -264,7 +270,9 @@ krpc_call(struct sockaddr_in *sa, u_int
mopt->m_len = sizeof(int);
ip = mtod(mopt, int *);
*ip = IP_PORTRANGE_LOW;
+ s = solock(so);
error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
+ sounlock(s);
if (error)
goto out;
@@ -286,7 +294,9 @@ krpc_call(struct sockaddr_in *sa, u_int
mopt->m_len = sizeof(int);
ip = mtod(mopt, int *);
*ip = IP_PORTRANGE_DEFAULT;
+ s = solock(so);
error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
+ sounlock(s);
if (error)
goto out;
Index: nfs/nfs_socket.c
===================================================================
RCS file: /cvs/src/sys/nfs/nfs_socket.c,v
retrieving revision 1.120
diff -u -p -r1.120 nfs_socket.c
--- nfs/nfs_socket.c 24 Jul 2017 15:07:39 -0000 1.120
+++ nfs/nfs_socket.c 2 Aug 2017 08:17:41 -0000
@@ -262,7 +262,9 @@ nfs_connect(struct nfsmount *nmp, struct
mopt->m_len = sizeof(int);
ip = mtod(mopt, int *);
*ip = IP_PORTRANGE_LOW;
+ s = solock(so);
error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
+ sounlock(s);
if (error)
goto bad;
@@ -282,7 +284,9 @@ nfs_connect(struct nfsmount *nmp, struct
mopt->m_len = sizeof(int);
ip = mtod(mopt, int *);
*ip = IP_PORTRANGE_DEFAULT;
+ s = solock(so);
error = sosetopt(so, IPPROTO_IP, IP_PORTRANGE, mopt);
+ sounlock(s);
if (error)
goto bad;
}
@@ -331,6 +335,7 @@ nfs_connect(struct nfsmount *nmp, struct
* Always set receive timeout to detect server crash and reconnect.
* Otherwise, we can get stuck in soreceive forever.
*/
+ s = solock(so);
so->so_rcv.sb_timeo = (5 * hz);
if (nmp->nm_flag & (NFSMNT_SOFT | NFSMNT_INT))
so->so_snd.sb_timeo = (5 * hz);
@@ -364,7 +369,6 @@ nfs_connect(struct nfsmount *nmp, struct
rcvreserve = (nmp->nm_rsize + NFS_MAXPKTHDR +
sizeof (u_int32_t)) * 2;
}
- s = solock(so);
error = soreserve(so, sndreserve, rcvreserve);
sounlock(s);
if (error)
Index: nfs/nfs_syscalls.c
===================================================================
RCS file: /cvs/src/sys/nfs/nfs_syscalls.c,v
retrieving revision 1.109
diff -u -p -r1.109 nfs_syscalls.c
--- nfs/nfs_syscalls.c 27 Jun 2017 12:02:43 -0000 1.109
+++ nfs/nfs_syscalls.c 2 Aug 2017 08:17:41 -0000
@@ -249,8 +249,8 @@ nfssvc_addsock(struct file *fp, struct m
siz = NFS_MAXPACKET;
s = solock(so);
error = soreserve(so, siz, siz);
- sounlock(s);
if (error) {
+ sounlock(s);
m_freem(mynam);
return (error);
}
@@ -277,11 +277,11 @@ nfssvc_addsock(struct file *fp, struct m
so->so_rcv.sb_timeo = 0;
so->so_snd.sb_flags &= ~SB_NOINTR;
so->so_snd.sb_timeo = 0;
+ sounlock(s);
if (tslp)
slp = tslp;
else {
- slp = malloc(sizeof(*slp), M_NFSSVC,
- M_WAITOK|M_ZERO);
+ slp = malloc(sizeof(*slp), M_NFSSVC, M_WAITOK|M_ZERO);
TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
}
slp->ns_so = so;