blk-mq: User defined HCTX CPU mapping
Subsystems (2)
RFC PATCH 1/1 blk-mq: User defined HCTX CPU mapping
The default mapping of a cpu to a hardware context is often generally applicable, however a user may know of a more appropriate mapping for their specific access usage.
This patch allows a user to define their own policy by making the mq hctx cpu_list writable. The usage allows a user to append a comma separated and/or range list of CPUs to a given hctx's tag set mapping to reassign what hctx a cpu may map.
While the writable attribute exists under a specific request_queue, the settings will affect all request queues sharing the same tagset.
The user defined setting is lost if the block device is removed and re-added, or if the driver re-runs the queue mapping.
--- block/blk-mq-debugfs.c | 16 ++++++---- block/blk-mq-debugfs.h | 11 +++++++ block/blk-mq-sysfs.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++- block/blk-mq.c | 9 ------ block/blk-mq.h | 12 ++++++++ 5 files changed, 112 insertions(+), 16 deletions(-)
block/blk-mq-debugfs.c +10 -6
@@ -870,18 +870,22 @@ void blk_mq_debugfs_unregister(struct request_queue *q) q->debugfs_dir =NULL ; } -static int blk_mq_debugfs_register_ctx (struct blk_mq_hw_ctx *hctx, -struct blk_mq_ctx *ctx) +void blk_mq_debugfs_unregister_ctx (struct blk_mq_ctx *ctx) +{ +debugfs_remove_recursive (ctx->debugfs_dir); +} + +int blk_mq_debugfs_register_ctx (struct blk_mq_hw_ctx *hctx, +struct blk_mq_ctx *ctx) { -struct dentry *ctx_dir;char name[20 ];snprintf (name,sizeof (name),"cpu%u" , ctx->cpu); - ctx_dir =debugfs_create_dir (name, hctx->debugfs_dir); -if (!ctx_dir) + ctx->debugfs_dir =debugfs_create_dir (name, hctx->debugfs_dir); +if (!ctx->debugfs_dir)return -ENOMEM ; -if (!debugfs_create_files (ctx_dir, ctx, blk_mq_debugfs_ctx_attrs)) +if (!debugfs_create_files (ctx->debugfs_dir, ctx, blk_mq_debugfs_ctx_attrs))return -ENOMEM ;return 0 ;
block/blk-mq-debugfs.h +11 -0
@@ -18,6 +18,9 @@ struct blk_mq_debugfs_attr {int __blk_mq_debugfs_rq_show (struct seq_file *m,struct request *rq);int blk_mq_debugfs_rq_show (struct seq_file *m,void *v); +void blk_mq_debugfs_unregister_ctx (struct blk_mq_ctx *ctx); +int blk_mq_debugfs_register_ctx (struct blk_mq_hw_ctx *hctx, +struct blk_mq_ctx *ctx);int blk_mq_debugfs_register (struct request_queue *q);void blk_mq_debugfs_unregister (struct request_queue *q); int blk_mq_debugfs_register_hctx(struct request_queue *q,
@@ -41,6 +44,14 @@ static inline void blk_mq_debugfs_unregister(struct request_queue *q) { } +void blk_mq_debugfs_unregister_ctx (struct blk_mq_ctx *ctx) {} + +int blk_mq_debugfs_register_ctx (struct blk_mq_hw_ctx *hctx, +struct blk_mq_ctx *ctx) +{ +return 0 ; +} +static inline int blk_mq_debugfs_register_hctx (struct request_queue *q,struct blk_mq_hw_ctx *hctx) {
block/blk-mq-sysfs.c +79 -1
99 lines not on this page · raw message
block/blk-mq.c +0 -9
@@ -1248,15 +1248,6 @@ static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx)hctx_unlock (hctx, srcu_idx); } -static inline int blk_mq_first_mapped_cpu (struct blk_mq_hw_ctx *hctx) -{ -int cpu =cpumask_first_and (hctx->cpumask, cpu_online_mask); - -if (cpu >= nr_cpu_ids) - cpu =cpumask_first (hctx->cpumask); -return cpu; -} -/* * It'd be great if the workqueue API had a way to pass * in a mask and had some smarts for more clever placement.
block/blk-mq.h +12 -0
@@ -28,6 +28,9 @@ struct blk_mq_ctx {struct request_queue *queue;struct kobject kobj; +#ifdef CONFIG_BLK_DEBUG_FS +struct dentry *debugfs_dir; +#endif }____cacheline_aligned_in_smp ;void blk_mq_freeze_queue (struct request_queue *q);
@@ -203,4 +206,13 @@ static inline void blk_mq_put_driver_tag(struct request *rq) __blk_mq_put_driver_tag(hctx, rq); } +static inline int blk_mq_first_mapped_cpu (struct blk_mq_hw_ctx *hctx) +{ +int cpu =cpumask_first_and (hctx->cpumask, cpu_online_mask); + +if (cpu >= nr_cpu_ids) + cpu =cpumask_first (hctx->cpumask); +return cpu; +} +#endif
Signature · 1 line
2.14.3
Christoph Hellwig
maintainerQuoted 9 lines · Keith Busch
The default mapping of a cpu to a hardware context is often generally applicable, however a user may know of a more appropriate mapping for their specific access usage.
This patch allows a user to define their own policy by making the mq hctx
cpu_listwritable. The usage allows a user to append a comma separated and/or range list of CPUs to a given hctx's tag set mapping to reassign what hctx a cpu may map.
Quoted 5 lines
While the writable attribute exists under a specific
request_queue, the settings will affect all request queues sharing the same tagset.The user defined setting is lost if the block device is removed and re-added, or if the driver re-runs the queue mapping.
We can't do this without driver opt-in. Managed interrupt rely on the fact that we can't generate more interrupts once all cpus mapped to the interrupt line have been offlined.
So what exactly is the use case? What drivers do you care about?
Quoted 13 lines · Christoph Hellwig
Quoted 12 lines · Keith Busch
The default mapping of a cpu to a hardware context is often generally applicable, however a user may know of a more appropriate mapping for their specific access usage.
This patch allows a user to define their own policy by making the mq hctx
cpu_listwritable. The usage allows a user to append a comma separated and/or range list of CPUs to a given hctx's tag set mapping to reassign what hctx a cpu may map.While the writable attribute exists under a specific
request_queue, the settings will affect all request queues sharing the same tagset.
Quoted 8 lines
Quoted 2 lines
The user defined setting is lost if the block device is removed and re-added, or if the driver re-runs the queue mapping.
We can't do this without driver opt-in. Managed interrupt rely on the fact that we can't generate more interrupts once all cpus mapped to the interrupt line have been offlined.
So what exactly is the use case? What drivers do you care about?
This patch came at a customer request for NVMe. The controllers have 1:1 queues to CPUs, so currently a submission on CPU A will interrupt CPU A.
The user really wants their application to run in CPU A and have the interrupt run in CPU B. We can't change the IRQ affinity, so I thought changing the submission affinity would be less intrusive.
I think you're saying this will break if CPU B is offlined. I hadn't considered that, so it doesn't sound like this will work.