[PATCH 3/5] nvmet_tcp: assign queue to group
Wunderlich, Mark
mark.wunderlich at intel.com
Thu Aug 27 21:00:58 EDT 2020
nvmet_tcp: assign queue to group
Each newly created nvmf target queue connection is
assigned to a specific poll group.
The queue group assignment is based on the queue's socket
so_incoming_cpu value. Since there is a pre-allocated
poll group for every available active CPU, this policy
will provide fast direct queue to poll group assignment.
The unique napi_id of the new queue socket is added to a
group list. Multiple napi_ids are maintained per group
to support multi-port configurations where the number of
socket connections could exceed the number of active CPUs.
The group napi_ids are maintained for future patch for
polling when the group is found to be idle.
Signed-off-by: Mark Wunderlich <mark.wunderlich at intel.com>
---
drivers/nvme/target/tcp.c | 78 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 77 insertions(+), 1 deletion(-)
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 3e3c217c77d4..84dd5b300a1d 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -128,6 +128,7 @@ struct nvmet_tcp_queue {
int idx;
struct list_head queue_list;
+ struct nvmet_tcp_queue_group *group;
struct nvmet_tcp_cmd connect;
@@ -169,6 +170,7 @@ static struct workqueue_struct *nvmet_tcp_wq;
static const struct nvmet_fabrics_ops nvmet_tcp_ops;
static void nvmet_tcp_free_cmd(struct nvmet_tcp_cmd *c);
static void nvmet_tcp_finish_cmd(struct nvmet_tcp_cmd *cmd);
+static void nvmet_tcp_remove_from_group(struct nvmet_tcp_queue *queue);
static inline u16 nvmet_tcp_cmd_tag(struct nvmet_tcp_queue *queue,
struct nvmet_tcp_cmd *cmd)
@@ -1367,6 +1369,8 @@ static void nvmet_tcp_release_queue_work(struct work_struct *w)
struct nvmet_tcp_queue *queue =
container_of(w, struct nvmet_tcp_queue, release_work);
+ nvmet_tcp_remove_from_group(queue);
+
mutex_lock(&nvmet_tcp_queue_mutex);
list_del_init(&queue->queue_list);
mutex_unlock(&nvmet_tcp_queue_mutex);
@@ -1487,6 +1491,73 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
return 0;
}
+static inline bool nvmet_tcp_add_group_napi_id(struct nvmet_tcp_queue_group *group,
+ unsigned int napi_id)
+{
+ int i, free_index = NVMET_TCP_GROUP_NAPI_LIMIT;
+
+ for (i = 0; i < NVMET_TCP_GROUP_NAPI_LIMIT; i++) {
+ if (group->napi[i].napi_id == napi_id) {
+ group->napi[i].napi_cnt++;
+ return true;
+ } else if (!group->napi[i].napi_id && free_index == NVMET_TCP_GROUP_NAPI_LIMIT) {
+ free_index = i;
+ }
+ }
+
+ if (free_index < NVMET_TCP_GROUP_NAPI_LIMIT) {
+ group->napi[free_index].napi_id = napi_id;
+ group->napi[free_index].napi_cnt++;
+ return true;
+ }
+ return false;
+}
+
+static bool nvmet_tcp_add_to_group(struct nvmet_tcp_queue *queue)
+{
+ struct nvmet_tcp_queue_group *group;
+ bool assigned = true;
+ int i, nr_grps = num_possible_cpus();
+
+ group = nvmet_tcp_queue_groups + queue->sock->sk->sk_incoming_cpu;
+ if (!nvmet_tcp_add_group_napi_id(group, queue->sock->sk->sk_napi_id)) {
+ /*
+ * attempt assignment to another group with free napi id slot
+ */
+ assigned = false;
+ for (i = 0; i < nr_grps; i++) {
+ group = nvmet_tcp_queue_groups + i;
+ if (nvmet_tcp_add_group_napi_id(group, queue->sock->sk->sk_napi_id)) {
+ assigned = true;
+ break;
+ }
+ }
+ }
+ if (!assigned)
+ return false;
+
+ queue->group = group;
+ return true;
+}
+
+static void nvmet_tcp_remove_from_group(struct nvmet_tcp_queue *queue)
+{
+ struct nvmet_tcp_queue_group *group = queue->group;
+ int i;
+
+ if (unlikely(!group))
+ return;
+
+ queue->group = NULL;
+
+ for (i = 0; i < NVMET_TCP_GROUP_NAPI_LIMIT; i++) {
+ if (group->napi[i].napi_id == queue->sock->sk->sk_napi_id) {
+ if (--group->napi[i].napi_cnt == 0)
+ group->napi[i].napi_id = 0;
+ }
+ }
+}
+
static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
struct socket *newsock)
{
@@ -1528,13 +1599,18 @@ static int nvmet_tcp_alloc_queue(struct nvmet_tcp_port *port,
list_add_tail(&queue->queue_list, &nvmet_tcp_queue_list);
mutex_unlock(&nvmet_tcp_queue_mutex);
+ if (!nvmet_tcp_add_to_group(queue))
+ goto out_destroy_sq;
+
ret = nvmet_tcp_set_queue_sock(queue);
if (ret)
- goto out_destroy_sq;
+ goto out_remove_from_group;
queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work);
return 0;
+out_remove_from_group:
+ nvmet_tcp_remove_from_group(queue);
out_destroy_sq:
mutex_lock(&nvmet_tcp_queue_mutex);
list_del_init(&queue->queue_list);
More information about the Linux-nvme
mailing list