@@ -11,6 +11,7 @@
#include <linux/ctype.h>
#include <linux/pci.h>
#include <linux/pci-p2pdma.h>
+#include <net/tcp.h>
#include "nvmet.h"
@@ -222,6 +223,45 @@ static ssize_t nvmet_addr_trsvcid_store(struct config_item *item,
CONFIGFS_ATTR(nvmet_, addr_trsvcid);
+static ssize_t nvmet_tcp_congestion_show(struct config_item *item,
+ char *page)
+{
+ struct nvmet_port *port = to_nvmet_port(item);
+
+ return snprintf(page, PAGE_SIZE, "%s\n",
+ port->tcp_congestion ? port->tcp_congestion : "");
+}
+
+static ssize_t nvmet_tcp_congestion_store(struct config_item *item,
+ const char *page, size_t count)
+{
+ struct nvmet_port *port = to_nvmet_port(item);
+ int len;
+ char *buf;
+
+ len = strcspn(page, "\n");
+ if (!len)
+ return -EINVAL;
+
+ if (nvmet_is_port_enabled(port, __func__))
+ return -EACCES;
+
+ buf = kmemdup_nul(page, len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ if (strlen(buf) >= TCP_CA_NAME_MAX) {
+ kfree(buf);
+ return -EINVAL;
+ }
+
+ kfree(port->tcp_congestion);
+ port->tcp_congestion = buf;
+
+ return count;
+}
+
+CONFIGFS_ATTR(nvmet_, tcp_congestion);
+
static ssize_t nvmet_param_inline_data_size_show(struct config_item *item,
char *page)
{
@@ -1597,6 +1637,7 @@ static void nvmet_port_release(struct config_item *item)
list_del(&port->global_entry);
kfree(port->ana_state);
+ kfree(port->tcp_congestion);
kfree(port);
}
@@ -1605,6 +1646,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = {
&nvmet_attr_addr_treq,
&nvmet_attr_addr_traddr,
&nvmet_attr_addr_trsvcid,
+ &nvmet_attr_tcp_congestion,
&nvmet_attr_addr_trtype,
&nvmet_attr_param_inline_data_size,
#ifdef CONFIG_BLK_DEV_INTEGRITY
@@ -145,6 +145,7 @@ struct nvmet_port {
struct config_group ana_groups_group;
struct nvmet_ana_group ana_default_group;
enum nvme_ana_state *ana_state;
+ const char *tcp_congestion;
void *priv;
bool enabled;
int inline_data_size;
@@ -1741,6 +1741,19 @@ static int nvmet_tcp_add_port(struct nvmet_port *nport)
if (so_priority > 0)
sock_set_priority(port->sock->sk, so_priority);
+ if (nport->tcp_congestion) {
+ lock_sock(port->sock->sk);
+ ret = tcp_set_congestion_control(port->sock->sk,
+ nport->tcp_congestion,
+ true, true);
+ release_sock(port->sock->sk);
+ if (ret) {
+ pr_err("failed to set port socket's congestion to %s: %d\n",
+ nport->tcp_congestion, ret);
+ goto err_sock;
+ }
+ }
+
ret = kernel_bind(port->sock, (struct sockaddr *)&port->addr,
sizeof(port->addr));
if (ret) {