net: add sock_no_linger
Add a helper to directly set the SO_LINGER sockopt from kernel space with onoff set to true and a linger time of 0 without going through a fake uaccess. Signed-off-by: Christoph Hellwig <hch@lst.de> Acked-by: Sagi Grimberg <sagi@grimberg.me> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b58f0e8f38
commit
c433594c07
|
@ -1313,7 +1313,6 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
|
||||||
{
|
{
|
||||||
struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
|
struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
|
||||||
struct nvme_tcp_queue *queue = &ctrl->queues[qid];
|
struct nvme_tcp_queue *queue = &ctrl->queues[qid];
|
||||||
struct linger sol = { .l_onoff = 1, .l_linger = 0 };
|
|
||||||
int ret, opt, rcv_pdu_size;
|
int ret, opt, rcv_pdu_size;
|
||||||
|
|
||||||
queue->ctrl = ctrl;
|
queue->ctrl = ctrl;
|
||||||
|
@ -1361,13 +1360,7 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl,
|
||||||
* close. This is done to prevent stale data from being sent should
|
* close. This is done to prevent stale data from being sent should
|
||||||
* the network connection be restored before TCP times out.
|
* the network connection be restored before TCP times out.
|
||||||
*/
|
*/
|
||||||
ret = kernel_setsockopt(queue->sock, SOL_SOCKET, SO_LINGER,
|
sock_no_linger(queue->sock->sk);
|
||||||
(char *)&sol, sizeof(sol));
|
|
||||||
if (ret) {
|
|
||||||
dev_err(nctrl->device,
|
|
||||||
"failed to set SO_LINGER sock opt %d\n", ret);
|
|
||||||
goto err_sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (so_priority > 0) {
|
if (so_priority > 0) {
|
||||||
ret = kernel_setsockopt(queue->sock, SOL_SOCKET, SO_PRIORITY,
|
ret = kernel_setsockopt(queue->sock, SOL_SOCKET, SO_PRIORITY,
|
||||||
|
|
|
@ -1429,7 +1429,6 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
|
||||||
{
|
{
|
||||||
struct socket *sock = queue->sock;
|
struct socket *sock = queue->sock;
|
||||||
struct inet_sock *inet = inet_sk(sock->sk);
|
struct inet_sock *inet = inet_sk(sock->sk);
|
||||||
struct linger sol = { .l_onoff = 1, .l_linger = 0 };
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = kernel_getsockname(sock,
|
ret = kernel_getsockname(sock,
|
||||||
|
@ -1447,10 +1446,7 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
|
||||||
* close. This is done to prevent stale data from being sent should
|
* close. This is done to prevent stale data from being sent should
|
||||||
* the network connection be restored before TCP times out.
|
* the network connection be restored before TCP times out.
|
||||||
*/
|
*/
|
||||||
ret = kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
sock_no_linger(sock->sk);
|
||||||
(char *)&sol, sizeof(sol));
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (so_priority > 0) {
|
if (so_priority > 0) {
|
||||||
ret = kernel_setsockopt(sock, SOL_SOCKET, SO_PRIORITY,
|
ret = kernel_setsockopt(sock, SOL_SOCKET, SO_PRIORITY,
|
||||||
|
|
|
@ -2688,6 +2688,7 @@ static inline bool sk_dev_equal_l3scope(struct sock *sk, int dif)
|
||||||
|
|
||||||
void sock_def_readable(struct sock *sk);
|
void sock_def_readable(struct sock *sk);
|
||||||
|
|
||||||
|
void sock_no_linger(struct sock *sk);
|
||||||
void sock_set_reuseaddr(struct sock *sk);
|
void sock_set_reuseaddr(struct sock *sk);
|
||||||
|
|
||||||
#endif /* _SOCK_H */
|
#endif /* _SOCK_H */
|
||||||
|
|
|
@ -720,6 +720,15 @@ void sock_set_reuseaddr(struct sock *sk)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(sock_set_reuseaddr);
|
EXPORT_SYMBOL(sock_set_reuseaddr);
|
||||||
|
|
||||||
|
void sock_no_linger(struct sock *sk)
|
||||||
|
{
|
||||||
|
lock_sock(sk);
|
||||||
|
sk->sk_lingertime = 0;
|
||||||
|
sock_set_flag(sk, SOCK_LINGER);
|
||||||
|
release_sock(sk);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(sock_no_linger);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is meant for all protocols to use and covers goings on
|
* This is meant for all protocols to use and covers goings on
|
||||||
* at the socket level. Everything here is generic.
|
* at the socket level. Everything here is generic.
|
||||||
|
|
|
@ -73,7 +73,6 @@ void rds_tcp_listen_data_ready(struct sock *sk);
|
||||||
int rds_tcp_accept_one(struct socket *sock);
|
int rds_tcp_accept_one(struct socket *sock);
|
||||||
int rds_tcp_keepalive(struct socket *sock);
|
int rds_tcp_keepalive(struct socket *sock);
|
||||||
void *rds_tcp_listen_sock_def_readable(struct net *net);
|
void *rds_tcp_listen_sock_def_readable(struct net *net);
|
||||||
void rds_tcp_set_linger(struct socket *sock);
|
|
||||||
|
|
||||||
/* tcp_recv.c */
|
/* tcp_recv.c */
|
||||||
int rds_tcp_recv_init(void);
|
int rds_tcp_recv_init(void);
|
||||||
|
|
|
@ -207,7 +207,7 @@ void rds_tcp_conn_path_shutdown(struct rds_conn_path *cp)
|
||||||
|
|
||||||
if (sock) {
|
if (sock) {
|
||||||
if (rds_destroy_pending(cp->cp_conn))
|
if (rds_destroy_pending(cp->cp_conn))
|
||||||
rds_tcp_set_linger(sock);
|
sock_no_linger(sock->sk);
|
||||||
sock->ops->shutdown(sock, RCV_SHUTDOWN | SEND_SHUTDOWN);
|
sock->ops->shutdown(sock, RCV_SHUTDOWN | SEND_SHUTDOWN);
|
||||||
lock_sock(sock->sk);
|
lock_sock(sock->sk);
|
||||||
rds_tcp_restore_callbacks(sock, tc); /* tc->tc_sock = NULL */
|
rds_tcp_restore_callbacks(sock, tc); /* tc->tc_sock = NULL */
|
||||||
|
|
|
@ -111,17 +111,6 @@ struct rds_tcp_connection *rds_tcp_accept_one_path(struct rds_connection *conn)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rds_tcp_set_linger(struct socket *sock)
|
|
||||||
{
|
|
||||||
struct linger no_linger = {
|
|
||||||
.l_onoff = 1,
|
|
||||||
.l_linger = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
|
||||||
(char *)&no_linger, sizeof(no_linger));
|
|
||||||
}
|
|
||||||
|
|
||||||
int rds_tcp_accept_one(struct socket *sock)
|
int rds_tcp_accept_one(struct socket *sock)
|
||||||
{
|
{
|
||||||
struct socket *new_sock = NULL;
|
struct socket *new_sock = NULL;
|
||||||
|
@ -241,7 +230,7 @@ rst_nsk:
|
||||||
* be pending on it. By setting linger, we achieve the side-effect
|
* be pending on it. By setting linger, we achieve the side-effect
|
||||||
* of avoiding TIME_WAIT state on new_sock.
|
* of avoiding TIME_WAIT state on new_sock.
|
||||||
*/
|
*/
|
||||||
rds_tcp_set_linger(new_sock);
|
sock_no_linger(new_sock->sk);
|
||||||
kernel_sock_shutdown(new_sock, SHUT_RDWR);
|
kernel_sock_shutdown(new_sock, SHUT_RDWR);
|
||||||
ret = 0;
|
ret = 0;
|
||||||
out:
|
out:
|
||||||
|
|
|
@ -323,17 +323,9 @@ static int svc_tcp_has_wspace(struct svc_xprt *xprt)
|
||||||
|
|
||||||
static void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt)
|
static void svc_tcp_kill_temp_xprt(struct svc_xprt *xprt)
|
||||||
{
|
{
|
||||||
struct svc_sock *svsk;
|
struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
||||||
struct socket *sock;
|
|
||||||
struct linger no_linger = {
|
|
||||||
.l_onoff = 1,
|
|
||||||
.l_linger = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
svsk = container_of(xprt, struct svc_sock, sk_xprt);
|
sock_no_linger(svsk->sk_sock->sk);
|
||||||
sock = svsk->sk_sock;
|
|
||||||
kernel_setsockopt(sock, SOL_SOCKET, SO_LINGER,
|
|
||||||
(char *)&no_linger, sizeof(no_linger));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in New Issue