summaryrefslogtreecommitdiff
path: root/drivers/nvme/target/tcp.c
diff options
context:
space:
mode:
authorJens Axboe <axboe@kernel.dk>2021-04-06 09:17:22 -0600
committerJens Axboe <axboe@kernel.dk>2021-04-06 09:17:22 -0600
commit762d6bd27d57491bedbbf0464a27a43f387de788 (patch)
treed911962d73d17a88110f4fbf7eb28b53563c2e35 /drivers/nvme/target/tcp.c
parent80755855f808c27c7154937667436f30e47bc820 (diff)
parent8609c63fce58e94d82f6b6bf29c7806062e2e867 (diff)
Merge tag 'nvme-5.13-2021-04-06' of git://git.infradead.org/nvme into for-5.13/drivers
Pull NVMe updates from Christoph: "nvme updates for Linux 5.13 - fix handling of very large MDTS values (Bart Van Assche) - retrigger ANA log update if group descriptor isn't found (Hannes Reinecke) - fix locking contexts in nvme-tcp and nvmet-tcp (Sagi Grimberg) - return proper error code from discovery ctrl (Hou Pu) - verify the SGLS field in nvmet-tcp and nvmet-fc (Max Gurtovoy) - disallow passthru cmd from targeting a nsid != nsid of the block dev (Niklas Cassel) - do not allow model_number exceed 40 bytes in nvmet (Noam Gottlieb) - enable optional queue idle period tracking in nvmet-tcp (Mark Wunderlich) - various cleanups and optimizations (Chaitanya Kulkarni, Kanchan Joshi) - expose fast_io_fail_tmo in sysfs (Daniel Wagner) - implement non-MDTS command limits (Keith Busch) - reduce warnings for unhandled command effects (Keith Busch) - allocate storage for the SQE as part of the nvme_request (Keith Busch)" * tag 'nvme-5.13-2021-04-06' of git://git.infradead.org/nvme: (33 commits) nvme: fix handling of large MDTS values nvme: implement non-mdts command limits nvme: disallow passthru cmd from targeting a nsid != nsid of the block dev nvme: retrigger ANA log update if group descriptor isn't found nvme: export fast_io_fail_tmo to sysfs nvme: remove superfluous else in nvme_ctrl_loss_tmo_store nvme: use sysfs_emit instead of sprintf nvme-fc: check sgl supported by target nvme-tcp: check sgl supported by target nvmet-tcp: enable optional queue idle period tracking nvmet-tcp: fix incorrect locking in state_change sk callback nvme-tcp: block BH in sk state_change sk callback nvmet: return proper error code from discovery ctrl nvme: warn of unhandled effects only once nvme: use driver pdu command for passthrough nvme-pci: allocate nvme_command within driver pdu nvmet: do not allow model_number exceed 40 bytes nvmet: remove unnecessary ctrl parameter nvmet-fc: update function documentation nvme-fc: fix the function documentation comment ...
Diffstat (limited to 'drivers/nvme/target/tcp.c')
-rw-r--r--drivers/nvme/target/tcp.c40
1 files changed, 36 insertions, 4 deletions
diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c
index 8b0485ada315..558a973277fd 100644
--- a/drivers/nvme/target/tcp.c
+++ b/drivers/nvme/target/tcp.c
@@ -29,6 +29,16 @@ static int so_priority;
module_param(so_priority, int, 0644);
MODULE_PARM_DESC(so_priority, "nvmet tcp socket optimize priority");
+/* Define a time period (in usecs) that io_work() shall sample an activated
+ * queue before determining it to be idle. This optional module behavior
+ * can enable NIC solutions that support socket optimized packet processing
+ * using advanced interrupt moderation techniques.
+ */
+static int idle_poll_period_usecs;
+module_param(idle_poll_period_usecs, int, 0644);
+MODULE_PARM_DESC(idle_poll_period_usecs,
+ "nvmet tcp io_work poll till idle time period in usecs");
+
#define NVMET_TCP_RECV_BUDGET 8
#define NVMET_TCP_SEND_BUDGET 8
#define NVMET_TCP_IO_WORK_BUDGET 64
@@ -119,6 +129,8 @@ struct nvmet_tcp_queue {
struct ahash_request *snd_hash;
struct ahash_request *rcv_hash;
+ unsigned long poll_end;
+
spinlock_t state_lock;
enum nvmet_tcp_queue_state state;
@@ -1216,6 +1228,23 @@ static void nvmet_tcp_schedule_release_queue(struct nvmet_tcp_queue *queue)
spin_unlock(&queue->state_lock);
}
+static inline void nvmet_tcp_arm_queue_deadline(struct nvmet_tcp_queue *queue)
+{
+ queue->poll_end = jiffies + usecs_to_jiffies(idle_poll_period_usecs);
+}
+
+static bool nvmet_tcp_check_queue_deadline(struct nvmet_tcp_queue *queue,
+ int ops)
+{
+ if (!idle_poll_period_usecs)
+ return false;
+
+ if (ops)
+ nvmet_tcp_arm_queue_deadline(queue);
+
+ return !time_after(jiffies, queue->poll_end);
+}
+
static void nvmet_tcp_io_work(struct work_struct *w)
{
struct nvmet_tcp_queue *queue =
@@ -1241,9 +1270,10 @@ static void nvmet_tcp_io_work(struct work_struct *w)
} while (pending && ops < NVMET_TCP_IO_WORK_BUDGET);
/*
- * We exahusted our budget, requeue our selves
+ * Requeue the worker if idle deadline period is in progress or any
+ * ops activity was recorded during the do-while loop above.
*/
- if (pending)
+ if (nvmet_tcp_check_queue_deadline(queue, ops) || pending)
queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work);
}
@@ -1434,7 +1464,7 @@ static void nvmet_tcp_state_change(struct sock *sk)
{
struct nvmet_tcp_queue *queue;
- write_lock_bh(&sk->sk_callback_lock);
+ read_lock_bh(&sk->sk_callback_lock);
queue = sk->sk_user_data;
if (!queue)
goto done;
@@ -1452,7 +1482,7 @@ static void nvmet_tcp_state_change(struct sock *sk)
queue->idx, sk->sk_state);
}
done:
- write_unlock_bh(&sk->sk_callback_lock);
+ read_unlock_bh(&sk->sk_callback_lock);
}
static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
@@ -1501,6 +1531,8 @@ static int nvmet_tcp_set_queue_sock(struct nvmet_tcp_queue *queue)
sock->sk->sk_state_change = nvmet_tcp_state_change;
queue->write_space = sock->sk->sk_write_space;
sock->sk->sk_write_space = nvmet_tcp_write_space;
+ if (idle_poll_period_usecs)
+ nvmet_tcp_arm_queue_deadline(queue);
queue_work_on(queue_cpu(queue), nvmet_tcp_wq, &queue->io_work);
}
write_unlock_bh(&sock->sk->sk_callback_lock);