From: Geliang Tang <[email protected]>

To handle accepted sockets, this patch adds struct nvmet_tcp_proto to
hold accept socket operations (no_linger, set_priority, set_tos, ops).
A proto field is added to struct nvmet_tcp_queue, which points to the
appropriate protocol structure. A TCP version is defined and assigned
to queue->proto for TCP connections.

Also modify nvmet_tcp_set_queue_sock() and nvmet_tcp_done_recv_pdu()
to use queue->proto for socket operations and fabrics callbacks.

Cc: Hannes Reinecke <[email protected]>
Cc: John Meneghini <[email protected]>
Cc: Randy Jennings <[email protected]>
Cc: Nilay Shroff <[email protected]>
Co-developed-by: zhenwei pi <[email protected]>
Signed-off-by: zhenwei pi <[email protected]>
Co-developed-by: Hui Zhu <[email protected]>
Signed-off-by: Hui Zhu <[email protected]>
Co-developed-by: Gang Yan <[email protected]>
Signed-off-by: Gang Yan <[email protected]>
Signed-off-by: Geliang Tang <[email protected]>
---
 drivers/nvme/target/tcp.c | 40 +++++++++++++++++++++++++++++++++------
 1 file changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 20f150d17a96..01c23fb15b79 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -145,6 +145,13 @@ enum nvmet_tcp_queue_state {
        NVMET_TCP_Q_FAILED,
 };
 
+struct nvmet_tcp_proto {
+       void (*no_linger)(struct sock *sk);
+       void (*set_priority)(struct sock *sk, u32 priority);
+       void (*set_tos)(struct sock *sk);
+       const struct nvmet_fabrics_ops *ops;
+};
+
 struct nvmet_tcp_queue {
        struct socket           *sock;
        struct nvmet_tcp_port   *port;
@@ -196,6 +203,7 @@ struct nvmet_tcp_queue {
        void (*data_ready)(struct sock *);
        void (*state_change)(struct sock *);
        void (*write_space)(struct sock *);
+       const struct nvmet_tcp_proto *proto;
 };
 
 struct nvmet_tcp_port {
@@ -1081,7 +1089,8 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue 
*queue)
        req = &queue->cmd->req;
        memcpy(req->cmd, nvme_cmd, sizeof(*nvme_cmd));
 
-       if (unlikely(!nvmet_req_init(req, &queue->nvme_sq, &nvmet_tcp_ops))) {
+       if (unlikely(!nvmet_req_init(req, &queue->nvme_sq,
+                                    queue->proto->ops))) {
                pr_err("failed cmd %p id %d opcode %d, data_len: %d, status: 
%04x\n",
                        req->cmd, req->cmd->common.command_id,
                        req->cmd->common.opcode,
@@ -1698,7 +1707,6 @@ static void nvmet_tcp_state_change(struct sock *sk)
 static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
 {
        struct socket *sock = queue->sock;
-       struct inet_sock *inet = inet_sk(sock->sk);
        int ret;
 
        ret = kernel_getsockname(sock,
@@ -1716,14 +1724,13 @@ static int nvmet_tcp_set_queue_sock(struct 
nvmet_tcp_queue *queue)
         * close. This is done to prevent stale data from being sent should
         * the network connection be restored before TCP times out.
         */
-       sock_no_linger(sock->sk);
+       queue->proto->no_linger(sock->sk);
 
        if (so_priority > 0)
-               sock_set_priority(sock->sk, so_priority);
+               queue->proto->set_priority(sock->sk, so_priority);
 
        /* Set socket type of service */
-       if (inet->rcv_tos > 0)
-               ip_sock_set_tos(sock->sk, inet->rcv_tos);
+       queue->proto->set_tos(sock->sk);
 
        ret = 0;
        write_lock_bh(&sock->sk->sk_callback_lock);
@@ -1906,6 +1913,21 @@ static int nvmet_tcp_tls_handshake(struct 
nvmet_tcp_queue *queue)
 static void nvmet_tcp_tls_handshake_timeout(struct work_struct *w) {}
 #endif
 
+static void tcp_sock_set_tos(struct sock *sk)
+{
+       struct inet_sock *inet = inet_sk(sk);
+
+       if (inet->rcv_tos > 0)
+               ip_sock_set_tos(sk, inet->rcv_tos);
+}
+
+static const struct nvmet_tcp_proto nvmet_tcp_proto = {
+       .no_linger      = sock_no_linger,
+       .set_priority   = sock_set_priority,
+       .set_tos        = tcp_sock_set_tos,
+       .ops            = &nvmet_tcp_ops,
+};
+
 static void nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
                struct socket *newsock)
 {
@@ -1923,6 +1945,12 @@ static void nvmet_tcp_alloc_queue(struct nvmet_tcp_port 
*port,
        INIT_WORK(&queue->io_work, nvmet_tcp_io_work);
        kref_init(&queue->kref);
        queue->sock = newsock;
+       if (newsock->sk->sk_protocol == IPPROTO_TCP) {
+               queue->proto = &nvmet_tcp_proto;
+       } else {
+               ret = -EINVAL;
+               goto out_free_queue;
+       }
        queue->port = port;
        queue->nr_cmds = 0;
        spin_lock_init(&queue->state_lock);
-- 
2.53.0


Reply via email to