Skip to content

Commit 7774e77

Browse files
ChaitanayaKulkarniChristoph Hellwig
authored andcommitted
nvmet: use xarray for ctrl ns storing
This patch replaces the ctrl->namespaces tracking from linked list to xarray and improves the performance when accessing one namespce :- XArray vs Default:- IOPS and BW (more the better) increase BW (~1.8%):- --------------------------------------------------- XArray :- read: IOPS=160k, BW=626MiB/s (656MB/s)(18.3GiB/30001msec) read: IOPS=160k, BW=626MiB/s (656MB/s)(18.3GiB/30001msec) read: IOPS=162k, BW=631MiB/s (662MB/s)(18.5GiB/30001msec) Default:- read: IOPS=156k, BW=609MiB/s (639MB/s)(17.8GiB/30001msec) read: IOPS=157k, BW=613MiB/s (643MB/s)(17.0GiB/30001msec) read: IOPS=160k, BW=626MiB/s (656MB/s)(18.3GiB/30001msec) Submission latency (less the better) decrease (~8.3%):- ------------------------------------------------------- XArray:- slat (usec): min=7, max=8386, avg=11.19, stdev=5.96 slat (usec): min=7, max=441, avg=11.09, stdev=4.48 slat (usec): min=7, max=1088, avg=11.21, stdev=4.54 Default :- slat (usec): min=8, max=2826.5k, avg=23.96, stdev=3911.50 slat (usec): min=8, max=503, avg=12.52, stdev=5.07 slat (usec): min=8, max=2384, avg=12.50, stdev=5.28 CPU Usage (less the better) decrease (~5.2%):- ---------------------------------------------- XArray:- cpu : usr=1.84%, sys=18.61%, ctx=949471, majf=0, minf=250 cpu : usr=1.83%, sys=18.41%, ctx=950262, majf=0, minf=237 cpu : usr=1.82%, sys=18.82%, ctx=957224, majf=0, minf=234 Default:- cpu : usr=1.70%, sys=19.21%, ctx=858196, majf=0, minf=251 cpu : usr=1.82%, sys=19.98%, ctx=929720, majf=0, minf=227 cpu : usr=1.83%, sys=20.33%, ctx=947208, majf=0, minf=235. Signed-off-by: Chaitanya Kulkarni <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent ca0f1a8 commit 7774e77

File tree

3 files changed

+27
-57
lines changed

3 files changed

+27
-57
lines changed

drivers/nvme/target/admin-cmd.c

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,10 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req,
113113
u64 data_units_read = 0, data_units_written = 0;
114114
struct nvmet_ns *ns;
115115
struct nvmet_ctrl *ctrl;
116+
unsigned long idx;
116117

117118
ctrl = req->sq->ctrl;
118-
119-
rcu_read_lock();
120-
list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) {
119+
xa_for_each(&ctrl->subsys->namespaces, idx, ns) {
121120
/* we don't have the right data for file backed ns */
122121
if (!ns->bdev)
123122
continue;
@@ -127,9 +126,7 @@ static u16 nvmet_get_smart_log_all(struct nvmet_req *req,
127126
host_writes += part_stat_read(ns->bdev->bd_part, ios[WRITE]);
128127
data_units_written += DIV_ROUND_UP(
129128
part_stat_read(ns->bdev->bd_part, sectors[WRITE]), 1000);
130-
131129
}
132-
rcu_read_unlock();
133130

134131
put_unaligned_le64(host_reads, &slog->host_reads[0]);
135132
put_unaligned_le64(data_units_read, &slog->data_units_read[0]);
@@ -230,14 +227,13 @@ static u32 nvmet_format_ana_group(struct nvmet_req *req, u32 grpid,
230227
{
231228
struct nvmet_ctrl *ctrl = req->sq->ctrl;
232229
struct nvmet_ns *ns;
230+
unsigned long idx;
233231
u32 count = 0;
234232

235233
if (!(req->cmd->get_log_page.lsp & NVME_ANA_LOG_RGO)) {
236-
rcu_read_lock();
237-
list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link)
234+
xa_for_each(&ctrl->subsys->namespaces, idx, ns)
238235
if (ns->anagrpid == grpid)
239236
desc->nsids[count++] = cpu_to_le32(ns->nsid);
240-
rcu_read_unlock();
241237
}
242238

243239
desc->grpid = cpu_to_le32(grpid);
@@ -556,6 +552,7 @@ static void nvmet_execute_identify_nslist(struct nvmet_req *req)
556552
static const int buf_size = NVME_IDENTIFY_DATA_SIZE;
557553
struct nvmet_ctrl *ctrl = req->sq->ctrl;
558554
struct nvmet_ns *ns;
555+
unsigned long idx;
559556
u32 min_nsid = le32_to_cpu(req->cmd->identify.nsid);
560557
__le32 *list;
561558
u16 status = 0;
@@ -567,15 +564,13 @@ static void nvmet_execute_identify_nslist(struct nvmet_req *req)
567564
goto out;
568565
}
569566

570-
rcu_read_lock();
571-
list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) {
567+
xa_for_each(&ctrl->subsys->namespaces, idx, ns) {
572568
if (ns->nsid <= min_nsid)
573569
continue;
574570
list[i++] = cpu_to_le32(ns->nsid);
575571
if (i == buf_size / sizeof(__le32))
576572
break;
577573
}
578-
rcu_read_unlock();
579574

580575
status = nvmet_copy_to_sgl(req, 0, list, buf_size);
581576

drivers/nvme/target/core.c

Lines changed: 20 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,14 @@ u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len)
115115

116116
static unsigned int nvmet_max_nsid(struct nvmet_subsys *subsys)
117117
{
118-
struct nvmet_ns *ns;
118+
unsigned long nsid = 0;
119+
struct nvmet_ns *cur;
120+
unsigned long idx;
119121

120-
if (list_empty(&subsys->namespaces))
121-
return 0;
122+
xa_for_each(&subsys->namespaces, idx, cur)
123+
nsid = cur->nsid;
122124

123-
ns = list_last_entry(&subsys->namespaces, struct nvmet_ns, dev_link);
124-
return ns->nsid;
125+
return nsid;
125126
}
126127

127128
static u32 nvmet_async_event_result(struct nvmet_async_event *aen)
@@ -410,28 +411,13 @@ static void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl)
410411
cancel_delayed_work_sync(&ctrl->ka_work);
411412
}
412413

413-
static struct nvmet_ns *__nvmet_find_namespace(struct nvmet_ctrl *ctrl,
414-
__le32 nsid)
415-
{
416-
struct nvmet_ns *ns;
417-
418-
list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link) {
419-
if (ns->nsid == le32_to_cpu(nsid))
420-
return ns;
421-
}
422-
423-
return NULL;
424-
}
425-
426414
struct nvmet_ns *nvmet_find_namespace(struct nvmet_ctrl *ctrl, __le32 nsid)
427415
{
428416
struct nvmet_ns *ns;
429417

430-
rcu_read_lock();
431-
ns = __nvmet_find_namespace(ctrl, nsid);
418+
ns = xa_load(&ctrl->subsys->namespaces, le32_to_cpu(nsid));
432419
if (ns)
433420
percpu_ref_get(&ns->ref);
434-
rcu_read_unlock();
435421

436422
return ns;
437423
}
@@ -586,24 +572,10 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
586572
if (ns->nsid > subsys->max_nsid)
587573
subsys->max_nsid = ns->nsid;
588574

589-
/*
590-
* The namespaces list needs to be sorted to simplify the implementation
591-
* of the Identify Namepace List subcommand.
592-
*/
593-
if (list_empty(&subsys->namespaces)) {
594-
list_add_tail_rcu(&ns->dev_link, &subsys->namespaces);
595-
} else {
596-
struct nvmet_ns *old;
597-
598-
list_for_each_entry_rcu(old, &subsys->namespaces, dev_link,
599-
lockdep_is_held(&subsys->lock)) {
600-
BUG_ON(ns->nsid == old->nsid);
601-
if (ns->nsid < old->nsid)
602-
break;
603-
}
575+
ret = xa_insert(&subsys->namespaces, ns->nsid, ns, GFP_KERNEL);
576+
if (ret)
577+
goto out_restore_subsys_maxnsid;
604578

605-
list_add_tail_rcu(&ns->dev_link, &old->dev_link);
606-
}
607579
subsys->nr_namespaces++;
608580

609581
nvmet_ns_changed(subsys, ns->nsid);
@@ -612,6 +584,10 @@ int nvmet_ns_enable(struct nvmet_ns *ns)
612584
out_unlock:
613585
mutex_unlock(&subsys->lock);
614586
return ret;
587+
588+
out_restore_subsys_maxnsid:
589+
subsys->max_nsid = nvmet_max_nsid(subsys);
590+
percpu_ref_exit(&ns->ref);
615591
out_dev_put:
616592
list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry)
617593
pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid));
@@ -630,7 +606,7 @@ void nvmet_ns_disable(struct nvmet_ns *ns)
630606
goto out_unlock;
631607

632608
ns->enabled = false;
633-
list_del_rcu(&ns->dev_link);
609+
xa_erase(&ns->subsys->namespaces, ns->nsid);
634610
if (ns->nsid == subsys->max_nsid)
635611
subsys->max_nsid = nvmet_max_nsid(subsys);
636612

@@ -681,7 +657,6 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
681657
if (!ns)
682658
return NULL;
683659

684-
INIT_LIST_HEAD(&ns->dev_link);
685660
init_completion(&ns->disable_done);
686661

687662
ns->nsid = nsid;
@@ -1263,14 +1238,14 @@ static void nvmet_setup_p2p_ns_map(struct nvmet_ctrl *ctrl,
12631238
struct nvmet_req *req)
12641239
{
12651240
struct nvmet_ns *ns;
1241+
unsigned long idx;
12661242

12671243
if (!req->p2p_client)
12681244
return;
12691245

12701246
ctrl->p2p_client = get_device(req->p2p_client);
12711247

1272-
list_for_each_entry_rcu(ns, &ctrl->subsys->namespaces, dev_link,
1273-
lockdep_is_held(&ctrl->subsys->lock))
1248+
xa_for_each(&ctrl->subsys->namespaces, idx, ns)
12741249
nvmet_p2pmem_ns_add_p2p(ctrl, ns);
12751250
}
12761251

@@ -1523,7 +1498,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
15231498
kref_init(&subsys->ref);
15241499

15251500
mutex_init(&subsys->lock);
1526-
INIT_LIST_HEAD(&subsys->namespaces);
1501+
xa_init(&subsys->namespaces);
15271502
INIT_LIST_HEAD(&subsys->ctrls);
15281503
INIT_LIST_HEAD(&subsys->hosts);
15291504

@@ -1535,8 +1510,9 @@ static void nvmet_subsys_free(struct kref *ref)
15351510
struct nvmet_subsys *subsys =
15361511
container_of(ref, struct nvmet_subsys, ref);
15371512

1538-
WARN_ON_ONCE(!list_empty(&subsys->namespaces));
1513+
WARN_ON_ONCE(!xa_empty(&subsys->namespaces));
15391514

1515+
xa_destroy(&subsys->namespaces);
15401516
kfree(subsys->subsysnqn);
15411517
kfree_rcu(subsys->model, rcuhead);
15421518
kfree(subsys);

drivers/nvme/target/nvmet.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
(cpu_to_le32(offsetof(struct nvmf_connect_command, x)))
5353

5454
struct nvmet_ns {
55-
struct list_head dev_link;
5655
struct percpu_ref ref;
5756
struct block_device *bdev;
5857
struct file *file;
@@ -219,7 +218,7 @@ struct nvmet_subsys {
219218
struct mutex lock;
220219
struct kref ref;
221220

222-
struct list_head namespaces;
221+
struct xarray namespaces;
223222
unsigned int nr_namespaces;
224223
unsigned int max_nsid;
225224
u16 cntlid_min;

0 commit comments

Comments
 (0)