diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c index 45c69c4b14d4..51874fbbb25b 100644 --- a/sys/kern/uipc_sockbuf.c +++ b/sys/kern/uipc_sockbuf.c @@ -451,14 +451,78 @@ sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so, } int -sbreserve(struct sockbuf *sb, u_long cc, struct socket *so, - struct thread *td) +sbsetopt(struct socket *so, int cmd, u_long cc) { + struct sockbuf *sb; + short *flags; + u_int *hiwat, *lowat; int error; - SOCKBUF_LOCK(sb); - error = sbreserve_locked(sb, cc, so, td); - SOCKBUF_UNLOCK(sb); + SOCK_LOCK(so); + if (SOLISTENING(so)) { + switch (cmd) { + case SO_SNDLOWAT: + case SO_SNDBUF: + lowat = &so->sol_sbsnd_lowat; + hiwat = &so->sol_sbsnd_hiwat; + flags = &so->sol_sbsnd_flags; + break; + case SO_RCVLOWAT: + case SO_RCVBUF: + lowat = &so->sol_sbrcv_lowat; + hiwat = &so->sol_sbrcv_hiwat; + flags = &so->sol_sbrcv_flags; + break; + } + } else { + switch (cmd) { + case SO_SNDLOWAT: + case SO_SNDBUF: + sb = &so->so_snd; + break; + case SO_RCVLOWAT: + case SO_RCVBUF: + sb = &so->so_rcv; + break; + } + flags = &sb->sb_flags; + hiwat = &sb->sb_hiwat; + lowat = &sb->sb_lowat; + SOCKBUF_LOCK(sb); + } + + error = 0; + switch (cmd) { + case SO_SNDBUF: + case SO_RCVBUF: + if (SOLISTENING(so)) { + if (cc > sb_max_adj) { + error = ENOBUFS; + break; + } + *hiwat = cc; + if (*lowat > *hiwat) + *lowat = *hiwat; + } else { + if (!sbreserve_locked(sb, cc, so, curthread)) + error = ENOBUFS; + } + if (error == 0) + *flags &= ~SB_AUTOSIZE; + break; + case SO_SNDLOWAT: + case SO_RCVLOWAT: + /* + * Make sure the low-water is never greater than the + * high-water. + */ + *lowat = (cc > *hiwat) ? *hiwat : cc; + break; + } + + if (!SOLISTENING(so)) + SOCKBUF_UNLOCK(sb); + SOCK_UNLOCK(so); return (error); } diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c index 55f5cdcd6801..129a0a2842b2 100644 --- a/sys/kern/uipc_socket.c +++ b/sys/kern/uipc_socket.c @@ -461,12 +461,6 @@ sodealloc(struct socket *so) so->so_vnet->vnet_sockcnt--; #endif mtx_unlock(&so_global_mtx); - if (so->so_rcv.sb_hiwat) - (void)chgsbsize(so->so_cred->cr_uidinfo, - &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY); - if (so->so_snd.sb_hiwat) - (void)chgsbsize(so->so_cred->cr_uidinfo, - &so->so_snd.sb_hiwat, 0, RLIM_INFINITY); #ifdef MAC mac_socket_destroy(so); #endif @@ -478,6 +472,12 @@ sodealloc(struct socket *so) if (so->sol_accept_filter != NULL) accept_filt_setopt(so, NULL); } else { + if (so->so_rcv.sb_hiwat) + (void)chgsbsize(so->so_cred->cr_uidinfo, + &so->so_rcv.sb_hiwat, 0, RLIM_INFINITY); + if (so->so_snd.sb_hiwat) + (void)chgsbsize(so->so_cred->cr_uidinfo, + &so->so_snd.sb_hiwat, 0, RLIM_INFINITY); sx_destroy(&so->so_snd.sb_sx); sx_destroy(&so->so_rcv.sb_sx); SOCKBUF_LOCK_DESTROY(&so->so_snd); @@ -2834,38 +2834,7 @@ sosetopt(struct socket *so, struct sockopt *sopt) goto bad; } - switch (sopt->sopt_name) { - case SO_SNDBUF: - case SO_RCVBUF: - if (sbreserve(sopt->sopt_name == SO_SNDBUF ? - &so->so_snd : &so->so_rcv, (u_long)optval, - so, curthread) == 0) { - error = ENOBUFS; - goto bad; - } - (sopt->sopt_name == SO_SNDBUF ? &so->so_snd : - &so->so_rcv)->sb_flags &= ~SB_AUTOSIZE; - break; - - /* - * Make sure the low-water is never greater than the - * high-water. - */ - case SO_SNDLOWAT: - SOCKBUF_LOCK(&so->so_snd); - so->so_snd.sb_lowat = - (optval > so->so_snd.sb_hiwat) ? - so->so_snd.sb_hiwat : optval; - SOCKBUF_UNLOCK(&so->so_snd); - break; - case SO_RCVLOWAT: - SOCKBUF_LOCK(&so->so_rcv); - so->so_rcv.sb_lowat = - (optval > so->so_rcv.sb_hiwat) ? - so->so_rcv.sb_hiwat : optval; - SOCKBUF_UNLOCK(&so->so_rcv); - break; - } + error = sbsetopt(so, sopt->sopt_name, optval); break; case SO_SNDTIMEO: diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h index d22e3bce1645..a4ed33274d79 100644 --- a/sys/sys/sockbuf.h +++ b/sys/sys/sockbuf.h @@ -167,8 +167,7 @@ void sbflush_locked(struct sockbuf *sb); void sbrelease(struct sockbuf *sb, struct socket *so); void sbrelease_internal(struct sockbuf *sb, struct socket *so); void sbrelease_locked(struct sockbuf *sb, struct socket *so); -int sbreserve(struct sockbuf *sb, u_long cc, struct socket *so, - struct thread *td); +int sbsetopt(struct socket *so, int cmd, u_long cc); int sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so, struct thread *td); struct mbuf *