get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.1/patches/2229704/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2229704,
    "url": "http://patchwork.ozlabs.org/api/1.1/patches/2229704/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260428155759.226368-2-henrique.carvalho@suse.com/",
    "project": {
        "id": 12,
        "url": "http://patchwork.ozlabs.org/api/1.1/projects/12/?format=api",
        "name": "Linux CIFS Client",
        "link_name": "linux-cifs-client",
        "list_id": "linux-cifs.vger.kernel.org",
        "list_email": "linux-cifs@vger.kernel.org",
        "web_url": "",
        "scm_url": "",
        "webscm_url": ""
    },
    "msgid": "<20260428155759.226368-2-henrique.carvalho@suse.com>",
    "date": "2026-04-28T15:57:55",
    "name": "[v2,06/11] smb: server: add shared transport helpers in preparation for QUIC",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "5aef8af5e005520443f594e4a2c113f1a4c2f7b9",
    "submitter": {
        "id": 89563,
        "url": "http://patchwork.ozlabs.org/api/1.1/people/89563/?format=api",
        "name": "Henrique Carvalho",
        "email": "henrique.carvalho@suse.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/linux-cifs-client/patch/20260428155759.226368-2-henrique.carvalho@suse.com/mbox/",
    "series": [
        {
            "id": 501886,
            "url": "http://patchwork.ozlabs.org/api/1.1/series/501886/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=501886",
            "date": "2026-04-28T15:55:41",
            "name": "smb: implement SMB over QUIC",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/501886/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2229704/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2229704/checks/",
    "tags": {},
    "headers": {
        "Return-Path": "\n <linux-cifs+bounces-11232-incoming=patchwork.ozlabs.org@vger.kernel.org>",
        "X-Original-To": [
            "incoming@patchwork.ozlabs.org",
            "linux-cifs@vger.kernel.org"
        ],
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=suse.com header.i=@suse.com header.a=rsa-sha256\n header.s=google header.b=DZy0Az63;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=linux-cifs+bounces-11232-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)",
            "smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com\n header.b=\"DZy0Az63\"",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.128.54",
            "smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=suse.com",
            "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=suse.com"
        ],
        "Received": [
            "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g4lqt2fcFz1yJH\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 02:14:18 +1000 (AEST)",
            "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 1B655311734E\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 28 Apr 2026 16:01:53 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id D24DF44BCB0;\n\tTue, 28 Apr 2026 15:58:11 +0000 (UTC)",
            "from mail-wm1-f54.google.com (mail-wm1-f54.google.com\n [209.85.128.54])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id D2B9C44B695\n\tfor <linux-cifs@vger.kernel.org>; Tue, 28 Apr 2026 15:58:09 +0000 (UTC)",
            "by mail-wm1-f54.google.com with SMTP id\n 5b1f17b1804b1-488af96f6b2so153206485e9.0\n        for <linux-cifs@vger.kernel.org>;\n Tue, 28 Apr 2026 08:58:09 -0700 (PDT)",
            "from precision ([2a01:4b00:c007:bb00:be9d:a3c4:18b1:4a25])\n        by smtp.gmail.com with ESMTPSA id\n 5b1f17b1804b1-48a7b560a84sm3409255e9.4.2026.04.28.08.58.07\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Tue, 28 Apr 2026 08:58:07 -0700 (PDT)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777391891; cv=none;\n b=lxao9h3YKgRv/PlIzc73l9Nz+HSP5l5XH0AcxZqSNj1LpMNWTVcxPndiMfAr3yevPeofn7cC72FVQALR8McJ9UoVp7/RNdW44CO/eWGsCO6REx3UBHaBNgLvOViS0fHwXPdeTMgiR5i1kOn95iKDIb4bWHkSeqSoY2rqsYd4l/0=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777391891; c=relaxed/simple;\n\tbh=jAOuX9dpwzMx7Akp2cQbJrd5q2Lz2mSKiMfiFBm7Qz4=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=AYzHvf8wU+1z2fgIJuG/HYYo+ubjoRW8zRawVqOcI/TcSiBDpfqB5pl7Qw7ePrJPoE5ev5CDTtYP/8kNJ8GvjUEL7VmGktkCzfijEqvQoj0/xiuux2nZ4sVurFuPb9fr2WEGo057MeOYlwebUZBAqovDwXzvw1M+b2iYTWSNLzc=",
        "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=quarantine dis=none) header.from=suse.com;\n spf=pass smtp.mailfrom=suse.com;\n dkim=pass (2048-bit key) header.d=suse.com header.i=@suse.com\n header.b=DZy0Az63; arc=none smtp.client-ip=209.85.128.54",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=suse.com; s=google; t=1777391888; x=1777996688;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=eXSup0OYn4CuueYI1U5YMs8zAmzWfq3Ux8UxQSH2V6w=;\n        b=DZy0Az63YBvMTVFHjEyW7KJQXUIa1pN7naJPthDzeRXZCOdNuIzlbLNm7/Oi435qKr\n         C1INBZJD06v/eOa/jjMqPdDpW1MhIxRnnlRTWqHnx63qoTiNETw3MXUmwMWo+nxyfESG\n         l3Uegi2KVeu+GqLQw8em/i/AHjhYxUHdiBIveLtj1rhgNleBrsniDRebSXMIijU8b+Fm\n         yNtcKZs/zJuoUrvDp87MVFpv3VCESqIqV4Dv5rR0v1sZty+Lgfv8coEKxd2fKzrNPWNZ\n         iqdc6BbVdViBtVcfkZUGMSIlCQAzLJX6mrdyZu72XSkRpwBHXdRqr+MY08kAQ7M13i+J\n         Iryw==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1777391888; x=1777996688;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=eXSup0OYn4CuueYI1U5YMs8zAmzWfq3Ux8UxQSH2V6w=;\n        b=BHMGkoCkUL8w/AK4TTBTpAMI9Xgfhf+r/VlJR+tCRAMUKPP+rXhDPcoR4PcIqGec6P\n         u1jbQMAN6LdfiDWUtO3st7IlZxjZh3C/M1mnlUyBAcM/xbK79lIeBY0YK0w7HwymjqWG\n         0L5cO58kGMbF2q3955apEGnyJwMr/nPhJjpoJDjsHPdA2jkXSoUZ74fIltJyOCWyMpE3\n         pC3pM4e3NdGaYIoKcejePIwRj40qZROlXk7NIyKUO8l5TVZFAbOHbKD3viKlGWyTJdNL\n         PnbbZG+vrCqdba5b1vtpmondleAUThlh966x8uSkldOa2/7pIOdYvUJVXhXdiqpjn9Go\n         TpZQ==",
        "X-Gm-Message-State": "AOJu0Yx6ShklNVPavUQba3yCuTC/foc/HeKZPAfPq85nUWQlS9J+clPc\n\tegOWpqAsj7zQYfKWo3bYUPyjBRVykzl4nT4TRRbzzNzUct/zZdoMPi8aIRQrYXp+pOUtW2YLqdc\n\t8xwuJokjW2w==",
        "X-Gm-Gg": "AeBDievrpHG7p3iCHjmCtww9JdC+7bXeMlFFyMlGpn5+lVj9omnNNt4DPUpg7w2Ut8x\n\tZ8SPdNd3gmBFBuR1y6JOaLRVcoQKeWSgJ1u7FJI6z0Lrul+iTNCEqDLGX8/P3Taj2k90HHnmn0t\n\t4zUBNGcWdRRNtpnww94m/F9lS1y0RZSNYu7CZFxZVQ/kVBdT+ygOE0UfwV17qC9HaLRxncGEjcL\n\t06p7tzfXnlrZZe0qIxTfPJg3BOnhV8fut7Bso1+MZc24x1tG97F7ivCl+RSIqI2Tlz5cU2td44w\n\t7lM3AEMe3KR/moPZn39aIWlyEWVeSCqDK8pc3VIHXRzD8YaRxalJTTNPMl3UPtY8khoyYreOv9J\n\tVlidKAMP5P0utXLgzBgDlUdPsjEiKIHs/jmru2nopn1ioq0/BbEjl6ixOQqEEY1fGiXTJBtW9vp\n\tahfXoiNukKXQvS8D56hRUWrg8nKa1l6ZGE/vO8Zs2brYi9",
        "X-Received": "by 2002:a05:600c:1c1b:b0:483:2c98:4368 with SMTP id\n 5b1f17b1804b1-48a77b0a516mr57355225e9.18.1777391887837;\n        Tue, 28 Apr 2026 08:58:07 -0700 (PDT)",
        "From": "Henrique Carvalho <henrique.carvalho@suse.com>",
        "To": "linux-cifs@vger.kernel.org",
        "Cc": "linkinjeon@kernel.org,\n\tsfrench@samba.org,\n\tmetze@samba.org,\n\tsenozhatsky@chromium.org,\n\ttom@talpey.com,\n\tematsumiya@suse.de,\n\tHenrique Carvalho <henrique.carvalho@suse.com>",
        "Subject": "[PATCH v2 06/11] smb: server: add shared transport helpers in\n preparation for QUIC",
        "Date": "Tue, 28 Apr 2026 12:57:55 -0300",
        "Message-ID": "<20260428155759.226368-2-henrique.carvalho@suse.com>",
        "X-Mailer": "git-send-email 2.53.0",
        "In-Reply-To": "<20260428155759.226368-1-henrique.carvalho@suse.com>",
        "References": "<20260428155759.226368-1-henrique.carvalho@suse.com>",
        "Precedence": "bulk",
        "X-Mailing-List": "linux-cifs@vger.kernel.org",
        "List-Id": "<linux-cifs.vger.kernel.org>",
        "List-Subscribe": "<mailto:linux-cifs+subscribe@vger.kernel.org>",
        "List-Unsubscribe": "<mailto:linux-cifs+unsubscribe@vger.kernel.org>",
        "MIME-Version": "1.0",
        "Content-Transfer-Encoding": "8bit"
    },
    "content": "Move the generic transport functions out of the TCP transport code into\na shared transport layer. This keeps the common socket setup and checks,\naccepted-connection initialization, and receive helpers in one place\ninstead of open-coding them in the individual transport implementation.\n\nSigned-off-by: Henrique Carvalho <henrique.carvalho@suse.com>\n---\n fs/smb/server/Makefile        |   3 +-\n fs/smb/server/connection.c    |   1 +\n fs/smb/server/connection.h    |   5 -\n fs/smb/server/transport.c     | 344 ++++++++++++++++++++++++++++++++++\n fs/smb/server/transport.h     |  40 ++++\n fs/smb/server/transport_tcp.c |   1 +\n 6 files changed, 388 insertions(+), 6 deletions(-)\n create mode 100644 fs/smb/server/transport.c\n create mode 100644 fs/smb/server/transport.h",
    "diff": "diff --git a/fs/smb/server/Makefile b/fs/smb/server/Makefile\nindex 7bd6501bfdc9..89a9955f607d 100644\n--- a/fs/smb/server/Makefile\n+++ b/fs/smb/server/Makefile\n@@ -8,7 +8,8 @@ ksmbd-y :=\tunicode.o auth.o vfs.o vfs_cache.o server.o ndr.o \\\n \t\tmisc.o oplock.o connection.o ksmbd_work.o crypto_ctx.o \\\n \t\tmgmt/ksmbd_ida.o mgmt/user_config.o mgmt/share_config.o \\\n \t\tmgmt/tree_connect.o mgmt/user_session.o smb_common.o \\\n-\t\tinterface.o transport_tcp.o transport_ipc.o smbacl.o smb2pdu.o \\\n+\t\ttransport.o transport_tcp.o transport_ipc.o interface.o \\\n+\t\tsmbacl.o smb2pdu.o \\\n \t\tsmb2ops.o smb2misc.o ksmbd_spnego_negtokeninit.asn1.o \\\n \t\tksmbd_spnego_negtokentarg.asn1.o asn1.o\n \ndiff --git a/fs/smb/server/connection.c b/fs/smb/server/connection.c\nindex 7465b364c35c..07bbf4eb7b05 100644\n--- a/fs/smb/server/connection.c\n+++ b/fs/smb/server/connection.c\n@@ -13,6 +13,7 @@\n #include \"mgmt/ksmbd_ida.h\"\n #include \"connection.h\"\n #include \"interface.h\"\n+#include \"transport.h\"\n #include \"transport_tcp.h\"\n #include \"transport_rdma.h\"\n #include \"misc.h\"\ndiff --git a/fs/smb/server/connection.h b/fs/smb/server/connection.h\nindex b060baf5f688..0e87283a9ddb 100644\n--- a/fs/smb/server/connection.h\n+++ b/fs/smb/server/connection.h\n@@ -145,11 +145,6 @@ struct ksmbd_transport_ops {\n \tvoid (*free_transport)(struct ksmbd_transport *kt);\n };\n \n-struct ksmbd_transport {\n-\tstruct ksmbd_conn\t\t\t*conn;\n-\tconst struct ksmbd_transport_ops\t*ops;\n-};\n-\n #define KSMBD_TCP_RECV_TIMEOUT\t(7 * HZ)\n #define KSMBD_TCP_SEND_TIMEOUT\t(5 * HZ)\n #define KSMBD_TCP_PEER_SOCKADDR(c)\t((struct sockaddr *)&((c)->peer_addr))\ndiff --git a/fs/smb/server/transport.c b/fs/smb/server/transport.c\nnew file mode 100644\nindex 000000000000..0a99fb821e02\n--- /dev/null\n+++ b/fs/smb/server/transport.c\n@@ -0,0 +1,344 @@\n+// SPDX-License-Identifier: GPL-2.0-or-later\n+\n+#include <linux/freezer.h>\n+\n+#include \"server.h\"\n+#include \"glob.h\"\n+#include \"connection.h\"\n+#include \"interface.h\"\n+#include \"transport.h\"\n+\n+/*\n+ * ksmbd_transport_iovec - get iovec for reading from socket\n+ * @t:\t\tksmbd transport struct\n+ * @nr_segs:\tnumber of iov segments needed for reading\n+ *\n+ * Return:\treturn existing or newly allocate iovec\n+ */\n+struct kvec *ksmbd_transport_iovec(struct ksmbd_transport *t,\n+\t\t\t\t   unsigned int nr_segs)\n+{\n+\tstruct kvec *new_iov;\n+\n+\tif (t->io.iov && nr_segs <= t->io.nr_iov)\n+\t\treturn t->io.iov;\n+\n+\t/* not big enough -- allocate a new one and release the old */\n+\tnew_iov = kmalloc_array(nr_segs, sizeof(*new_iov), KSMBD_DEFAULT_GFP);\n+\tif (new_iov) {\n+\t\tkfree(t->io.iov);\n+\t\tt->io.iov = new_iov;\n+\t\tt->io.nr_iov = nr_segs;\n+\t}\n+\treturn new_iov;\n+}\n+\n+int ksmbd_transport_alloc_conn(struct ksmbd_transport *t,\n+\t\t\t       struct socket *client_sk)\n+{\n+\tstruct task_struct *handler;\n+\tstruct ksmbd_conn *conn;\n+\n+\tconn = ksmbd_conn_alloc();\n+\tif (!conn)\n+\t\treturn -ENOMEM;\n+\n+\tconn->transport = t;\n+\tt->conn = conn;\n+\n+#if IS_ENABLED(CONFIG_IPV6)\n+\tif (client_sk->sk->sk_family == AF_INET6) {\n+\t\tmemcpy(&conn->inet6_addr, &client_sk->sk->sk_v6_daddr, 16);\n+\t\tconn->inet_hash = ipv6_addr_hash(&client_sk->sk->sk_v6_daddr);\n+\t} else {\n+\t\tconn->inet_addr = inet_sk(client_sk->sk)->inet_daddr;\n+\t\tconn->inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);\n+\t}\n+#else\n+\tconn->inet_addr = inet_sk(client_sk->sk)->inet_daddr;\n+\tconn->inet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);\n+#endif\n+\tdown_write(&conn_list_lock);\n+\thash_add(conn_list, &conn->hlist, conn->inet_hash);\n+\tup_write(&conn_list_lock);\n+\n+#if IS_ENABLED(CONFIG_IPV6)\n+\tif (client_sk->sk->sk_family == AF_INET6)\n+\t\thandler = kthread_run(ksmbd_conn_handler_loop,\n+\t\t\t\t      conn, \"ksmbd:%pI6c\",\n+\t\t\t\t      &conn->inet6_addr);\n+\telse\n+\t\thandler = kthread_run(ksmbd_conn_handler_loop,\n+\t\t\t\t      conn, \"ksmbd:%pI4\",\n+\t\t\t\t      &conn->inet_addr);\n+#else\n+\thandler = kthread_run(ksmbd_conn_handler_loop,\n+\t\t\t      conn, \"ksmbd:%pI4\",\n+\t\t\t      &conn->inet_addr);\n+#endif\n+\tif (IS_ERR(handler)) {\n+\t\tpr_err(\"cannot start conn thread\\n\");\n+\t\treturn PTR_ERR(handler);\n+\t}\n+\n+\treturn 0;\n+}\n+\n+/**\n+ * kvec_array_init() - initialize a IO vector segment\n+ * @new:\tIO vector to be initialized\n+ * @iov:\tbase IO vector\n+ * @nr_segs:\tnumber of segments in base iov\n+ * @bytes:\ttotal iovec length so far for read\n+ *\n+ * Return:\tNumber of IO segments\n+ */\n+static unsigned int kvec_array_init(struct kvec *new, struct kvec *iov,\n+\t\t\t\t    unsigned int nr_segs, size_t bytes)\n+{\n+\tsize_t base = 0;\n+\n+\twhile (bytes || !iov->iov_len) {\n+\t\tint copy = min(bytes, iov->iov_len);\n+\n+\t\tbytes -= copy;\n+\t\tbase += copy;\n+\t\tif (iov->iov_len == base) {\n+\t\t\tiov++;\n+\t\t\tnr_segs--;\n+\t\t\tbase = 0;\n+\t\t}\n+\t}\n+\n+\tmemcpy(new, iov, sizeof(*iov) * nr_segs);\n+\tnew->iov_base += base;\n+\tnew->iov_len -= base;\n+\treturn nr_segs;\n+}\n+\n+/**\n+ * ksmbd_readv() - read data from socket in given iovec\n+ * @t:\t\t\tksmbd transport instance\n+ * @sock:\t\tsocket to read from\n+ * @iov_orig:\t\tbase IO vector\n+ * @nr_segs:\t\tnumber of segments in base iov\n+ * @to_read:\t\tnumber of bytes to read from socket\n+ * @max_retries:\tmaximum retry count\n+ *\n+ * Return:\ton success return number of bytes read from socket,\n+ *\t\totherwise return error number\n+ */\n+int ksmbd_readv(struct ksmbd_transport *t, struct socket *sock,\n+\t\tstruct kvec *iov_orig, unsigned int nr_segs,\n+\t\tunsigned int to_read, int max_retries)\n+{\n+\tint length = 0;\n+\tint total_read;\n+\tunsigned int segs;\n+\tstruct msghdr ksmbd_msg;\n+\tstruct kvec *iov;\n+\tstruct ksmbd_conn *conn = t->conn;\n+\n+\tiov = ksmbd_transport_iovec(t, nr_segs);\n+\tif (!iov)\n+\t\treturn -ENOMEM;\n+\n+\tksmbd_msg.msg_control = NULL;\n+\tksmbd_msg.msg_controllen = 0;\n+\n+\tfor (total_read = 0; to_read; total_read += length, to_read -= length) {\n+\t\ttry_to_freeze();\n+\n+\t\tif (!ksmbd_conn_alive(conn)) {\n+\t\t\ttotal_read = -ESHUTDOWN;\n+\t\t\tbreak;\n+\t\t}\n+\t\tsegs = kvec_array_init(iov, iov_orig, nr_segs, total_read);\n+\n+\t\tlength = kernel_recvmsg(sock, &ksmbd_msg,\n+\t\t\t\t\tiov, segs, to_read, 0);\n+\n+\t\tif (length == -EINTR) {\n+\t\t\ttotal_read = -ESHUTDOWN;\n+\t\t\tbreak;\n+\t\t} else if (ksmbd_conn_need_reconnect(conn)) {\n+\t\t\ttotal_read = -EAGAIN;\n+\t\t\tbreak;\n+\t\t} else if (length == -ERESTARTSYS || length == -EAGAIN) {\n+\t\t\t/*\n+\t\t\t * If max_retries is negative, Allow unlimited\n+\t\t\t * retries to keep connection with inactive sessions.\n+\t\t\t */\n+\t\t\tif (max_retries == 0) {\n+\t\t\t\ttotal_read = length;\n+\t\t\t\tbreak;\n+\t\t\t} else if (max_retries > 0) {\n+\t\t\t\tmax_retries--;\n+\t\t\t}\n+\n+\t\t\tusleep_range(1000, 2000);\n+\t\t\tlength = 0;\n+\t\t\tcontinue;\n+\t\t} else if (length <= 0) {\n+\t\t\ttotal_read = length;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\treturn total_read;\n+}\n+\n+struct socket *ksmbd_create_socket(struct interface *iface, int sock_type,\n+\t\t\t\t   int ipproto, int port)\n+{\n+\tint ret;\n+\tstruct sockaddr_in6 sin6;\n+\tstruct sockaddr_in sin;\n+\tstruct socket *ksmbd_socket;\n+\tbool ipv4 = false;\n+\n+\tret = sock_create_kern(iface->net, PF_INET6, sock_type,\n+\t\t\t       ipproto, &ksmbd_socket);\n+\tif (ret) {\n+\t\tif (ret != -EAFNOSUPPORT)\n+\t\t\tpr_err(\"Can't create socket for ipv6, fallback to ipv4: %d\\n\", ret);\n+\t\tret = sock_create_kern(iface->net, PF_INET, sock_type,\n+\t\t\t\t       ipproto, &ksmbd_socket);\n+\t\tif (ret) {\n+\t\t\tpr_err(\"Can't create socket for ipv4: %d\\n\", ret);\n+\t\t\treturn ERR_PTR(ret);\n+\t\t}\n+\n+\t\tsin.sin_family = PF_INET;\n+\t\tsin.sin_addr.s_addr = htonl(INADDR_ANY);\n+\t\tsin.sin_port = htons(port);\n+\t\tipv4 = true;\n+\t} else {\n+\t\tsin6.sin6_family = PF_INET6;\n+\t\tsin6.sin6_addr = in6addr_any;\n+\t\tsin6.sin6_port = htons(port);\n+\n+\t\tlock_sock(ksmbd_socket->sk);\n+\t\tksmbd_socket->sk->sk_ipv6only = false;\n+\t\trelease_sock(ksmbd_socket->sk);\n+\t}\n+\n+\tret = sock_setsockopt(ksmbd_socket,\n+\t\t\t      SOL_SOCKET,\n+\t\t\t      SO_BINDTODEVICE,\n+\t\t\t      KERNEL_SOCKPTR(iface->name),\n+\t\t\t      strlen(iface->name));\n+\tif (ret != -ENODEV && ret < 0) {\n+\t\tpr_err(\"Failed to set SO_BINDTODEVICE: %d\\n\", ret);\n+\t\tgoto out_error;\n+\t}\n+\n+\tif (ipv4)\n+\t\tret = kernel_bind(ksmbd_socket, (struct sockaddr_unsized *)&sin,\n+\t\t\t\t  sizeof(sin));\n+\telse\n+\t\tret = kernel_bind(ksmbd_socket, (struct sockaddr_unsized *)&sin6,\n+\t\t\t\t  sizeof(sin6));\n+\tif (ret) {\n+\t\tpr_err(\"Failed to bind socket: %d\\n\", ret);\n+\t\tgoto out_error;\n+\t}\n+\n+\tret = kernel_listen(ksmbd_socket, KSMBD_SOCKET_BACKLOG);\n+\tif (ret) {\n+\t\tpr_err(\"Port listen() error: %d\\n\", ret);\n+\t\tgoto out_error;\n+\t}\n+\n+\treturn ksmbd_socket;\n+\n+out_error:\n+\tksmbd_destroy_socket(ksmbd_socket);\n+\treturn ERR_PTR(ret);\n+}\n+\n+void ksmbd_destroy_socket(struct socket *ksmbd_socket)\n+{\n+\tint ret;\n+\n+\tif (!ksmbd_socket)\n+\t\treturn;\n+\n+\tret = kernel_sock_shutdown(ksmbd_socket, SHUT_RDWR);\n+\tif (ret)\n+\t\tpr_err(\"Failed to shutdown socket: %d\\n\", ret);\n+\tsock_release(ksmbd_socket);\n+}\n+\n+/**\n+ * ksmbd_check_max_ip_conns() - reject when per-IP connection cap reached\n+ * @client_sk:\tfreshly accepted client socket\n+ *\n+ * Return:\t0 if a new connection from this peer is allowed, -EAGAIN\n+ *\t\twhen server_conf.max_ip_connections has been reached.\n+ */\n+int ksmbd_check_max_ip_conns(struct socket *client_sk)\n+{\n+\tstruct ksmbd_conn *conn;\n+\tunsigned int max_ip_conns = 0;\n+\tint inet_hash;\n+\tint ret = 0;\n+\n+\tif (!server_conf.max_ip_connections)\n+\t\treturn 0;\n+\n+#if IS_ENABLED(CONFIG_IPV6)\n+\tif (client_sk->sk->sk_family == AF_INET6)\n+\t\tinet_hash = ipv6_addr_hash(&client_sk->sk->sk_v6_daddr);\n+\telse\n+\t\tinet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);\n+#else\n+\tinet_hash = ipv4_addr_hash(inet_sk(client_sk->sk)->inet_daddr);\n+#endif\n+\n+\tdown_read(&conn_list_lock);\n+\thash_for_each_possible(conn_list, conn, hlist, inet_hash) {\n+#if IS_ENABLED(CONFIG_IPV6)\n+\t\tif (client_sk->sk->sk_family == AF_INET6) {\n+\t\t\tif (memcmp(&client_sk->sk->sk_v6_daddr,\n+\t\t\t\t   &conn->inet6_addr, 16) == 0)\n+\t\t\t\tmax_ip_conns++;\n+\t\t} else if (inet_sk(client_sk->sk)->inet_daddr ==\n+\t\t\t   conn->inet_addr)\n+\t\t\tmax_ip_conns++;\n+#else\n+\t\tif (inet_sk(client_sk->sk)->inet_daddr == conn->inet_addr)\n+\t\t\tmax_ip_conns++;\n+#endif\n+\t\tif (server_conf.max_ip_connections <= max_ip_conns) {\n+\t\t\tpr_info_ratelimited(\"Maximum IP connections exceeded (%u/%u)\\n\",\n+\t\t\t\t\t    max_ip_conns,\n+\t\t\t\t\t    server_conf.max_ip_connections);\n+\t\t\tret = -EAGAIN;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tup_read(&conn_list_lock);\n+\treturn ret;\n+}\n+\n+/**\n+ * ksmbd_check_max_conns() - reserve a slot under the global connection cap\n+ *\n+ * On success the global counter is incremented; the caller is responsible for\n+ * decrementing it on disconnect.\n+ *\n+ * Return:\t0 if allowed, -EAGAIN if server_conf.max_connections reached.\n+ */\n+int ksmbd_check_max_conns(void)\n+{\n+\tif (!server_conf.max_connections)\n+\t\treturn 0;\n+\n+\tif (atomic_inc_return(&active_num_conn) >= server_conf.max_connections) {\n+\t\tpr_info_ratelimited(\"Limit the maximum number of connections(%u)\\n\",\n+\t\t\t\t    atomic_read(&active_num_conn));\n+\t\tatomic_dec(&active_num_conn);\n+\t\treturn -EAGAIN;\n+\t}\n+\treturn 0;\n+}\ndiff --git a/fs/smb/server/transport.h b/fs/smb/server/transport.h\nnew file mode 100644\nindex 000000000000..6b2fb4f9005c\n--- /dev/null\n+++ b/fs/smb/server/transport.h\n@@ -0,0 +1,40 @@\n+/* SPDX-License-Identifier: GPL-2.0-or-later */\n+/*\n+ *   Copyright (C) 2026, SUSE LLC\n+ *\n+ *   Author: Henrique Carvalho <henrique.carvalho@suse.com>\n+ */\n+\n+#ifndef __KSMBD_TRANSPORT_H__\n+#define __KSMBD_TRANSPORT_H__\n+\n+#include <net/sock.h>\n+\n+#include \"connection.h\"\n+#include \"interface.h\"\n+\n+struct ksmbd_transport {\n+\tstruct ksmbd_conn\t\t\t*conn;\n+\tconst struct ksmbd_transport_ops\t*ops;\n+\tstruct {\n+\t\tstruct kvec\t\t\t*iov;\n+\t\tunsigned int\t\t\tnr_iov;\n+\t} io;\n+};\n+\n+#define KSMBD_TRANS(t)\t(&(t)->transport)\n+\n+struct kvec *ksmbd_transport_iovec(struct ksmbd_transport *t,\n+\t\t\t\t   unsigned int nr_segs);\n+int ksmbd_transport_alloc_conn(struct ksmbd_transport *t,\n+\t\t\t       struct socket *client_sk);\n+int ksmbd_readv(struct ksmbd_transport *t, struct socket *sock,\n+\t\tstruct kvec *iov_orig, unsigned int nr_segs,\n+\t\tunsigned int to_read, int max_retries);\n+struct socket *ksmbd_create_socket(struct interface *iface, int sock_type,\n+\t\t\t\t   int ipproto, int port);\n+void ksmbd_destroy_socket(struct socket *ksmbd_socket);\n+int ksmbd_check_max_ip_conns(struct socket *client_sk);\n+int ksmbd_check_max_conns(void);\n+\n+#endif /* __KSMBD_TRANSPORT_H__ */\ndiff --git a/fs/smb/server/transport_tcp.c b/fs/smb/server/transport_tcp.c\nindex 37f4238f72f5..07123ebcf8fd 100644\n--- a/fs/smb/server/transport_tcp.c\n+++ b/fs/smb/server/transport_tcp.c\n@@ -10,6 +10,7 @@\n #include \"server.h\"\n #include \"auth.h\"\n #include \"connection.h\"\n+#include \"transport.h\"\n #include \"transport_tcp.h\"\n #include \"interface.h\"\n \n",
    "prefixes": [
        "v2",
        "06/11"
    ]
}