Skip to content
68 changes: 42 additions & 26 deletions block/blk-mq-debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -608,9 +608,23 @@ static const struct blk_mq_debugfs_attr blk_mq_debugfs_ctx_attrs[] = {
{},
};

static void debugfs_create_files(struct dentry *parent, void *data,
static void debugfs_create_files(struct request_queue *q, struct dentry *parent,
void *data,
const struct blk_mq_debugfs_attr *attr)
{
lockdep_assert_held(&q->debugfs_mutex);
/*
* Creating new debugfs entries with queue freezed has the risk of
* deadlock.
*/
WARN_ON_ONCE(q->mq_freeze_depth != 0);
/*
* debugfs_mutex should not be nested under other locks that can be
* grabbed while queue is frozen.
*/
lockdep_assert_not_held(&q->elevator_lock);
lockdep_assert_not_held(&q->rq_qos_mutex);

if (IS_ERR_OR_NULL(parent))
return;

Expand All @@ -624,21 +638,14 @@ void blk_mq_debugfs_register(struct request_queue *q)
struct blk_mq_hw_ctx *hctx;
unsigned long i;

debugfs_create_files(q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);
debugfs_create_files(q, q->debugfs_dir, q, blk_mq_debugfs_queue_attrs);

queue_for_each_hw_ctx(q, hctx, i) {
if (!hctx->debugfs_dir)
blk_mq_debugfs_register_hctx(q, hctx);
}

if (q->rq_qos) {
struct rq_qos *rqos = q->rq_qos;

while (rqos) {
blk_mq_debugfs_register_rqos(rqos);
rqos = rqos->next;
}
}
blk_mq_debugfs_register_rq_qos(q);
}

static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
Expand All @@ -650,7 +657,8 @@ static void blk_mq_debugfs_register_ctx(struct blk_mq_hw_ctx *hctx,
snprintf(name, sizeof(name), "cpu%u", ctx->cpu);
ctx_dir = debugfs_create_dir(name, hctx->debugfs_dir);

debugfs_create_files(ctx_dir, ctx, blk_mq_debugfs_ctx_attrs);
debugfs_create_files(hctx->queue, ctx_dir, ctx,
blk_mq_debugfs_ctx_attrs);
}

void blk_mq_debugfs_register_hctx(struct request_queue *q,
Expand All @@ -666,7 +674,8 @@ void blk_mq_debugfs_register_hctx(struct request_queue *q,
snprintf(name, sizeof(name), "hctx%u", hctx->queue_num);
hctx->debugfs_dir = debugfs_create_dir(name, q->debugfs_dir);

debugfs_create_files(hctx->debugfs_dir, hctx, blk_mq_debugfs_hctx_attrs);
debugfs_create_files(q, hctx->debugfs_dir, hctx,
blk_mq_debugfs_hctx_attrs);

hctx_for_each_ctx(hctx, ctx, i)
blk_mq_debugfs_register_ctx(hctx, ctx);
Expand All @@ -686,8 +695,10 @@ void blk_mq_debugfs_register_hctxs(struct request_queue *q)
struct blk_mq_hw_ctx *hctx;
unsigned long i;

mutex_lock(&q->debugfs_mutex);
queue_for_each_hw_ctx(q, hctx, i)
blk_mq_debugfs_register_hctx(q, hctx);
mutex_unlock(&q->debugfs_mutex);
}

void blk_mq_debugfs_unregister_hctxs(struct request_queue *q)
Expand Down Expand Up @@ -717,7 +728,7 @@ void blk_mq_debugfs_register_sched(struct request_queue *q)

q->sched_debugfs_dir = debugfs_create_dir("sched", q->debugfs_dir);

debugfs_create_files(q->sched_debugfs_dir, q, e->queue_debugfs_attrs);
debugfs_create_files(q, q->sched_debugfs_dir, q, e->queue_debugfs_attrs);
}

void blk_mq_debugfs_unregister_sched(struct request_queue *q)
Expand All @@ -741,17 +752,7 @@ static const char *rq_qos_id_to_name(enum rq_qos_id id)
return "unknown";
}

void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
{
lockdep_assert_held(&rqos->disk->queue->debugfs_mutex);

if (!rqos->disk->queue->debugfs_dir)
return;
debugfs_remove_recursive(rqos->debugfs_dir);
rqos->debugfs_dir = NULL;
}

void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
static void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
{
struct request_queue *q = rqos->disk->queue;
const char *dir_name = rq_qos_id_to_name(rqos->id);
Expand All @@ -766,7 +767,22 @@ void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
q->debugfs_dir);

rqos->debugfs_dir = debugfs_create_dir(dir_name, q->rqos_debugfs_dir);
debugfs_create_files(rqos->debugfs_dir, rqos, rqos->ops->debugfs_attrs);
debugfs_create_files(q, rqos->debugfs_dir, rqos,
rqos->ops->debugfs_attrs);
}

void blk_mq_debugfs_register_rq_qos(struct request_queue *q)
{
lockdep_assert_held(&q->debugfs_mutex);

if (q->rq_qos) {
struct rq_qos *rqos = q->rq_qos;

while (rqos) {
blk_mq_debugfs_register_rqos(rqos);
rqos = rqos->next;
}
}
}

void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
Expand All @@ -789,7 +805,7 @@ void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,

hctx->sched_debugfs_dir = debugfs_create_dir("sched",
hctx->debugfs_dir);
debugfs_create_files(hctx->sched_debugfs_dir, hctx,
debugfs_create_files(q, hctx->sched_debugfs_dir, hctx,
e->hctx_debugfs_attrs);
}

Expand Down
8 changes: 2 additions & 6 deletions block/blk-mq-debugfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ void blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
struct blk_mq_hw_ctx *hctx);
void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx);

void blk_mq_debugfs_register_rqos(struct rq_qos *rqos);
void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos);
void blk_mq_debugfs_register_rq_qos(struct request_queue *q);
#else
static inline void blk_mq_debugfs_register(struct request_queue *q)
{
Expand Down Expand Up @@ -74,13 +73,10 @@ static inline void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hc
{
}

static inline void blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
static inline void blk_mq_debugfs_register_rq_qos(struct request_queue *q)
{
}

static inline void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
{
}
#endif

#if defined(CONFIG_BLK_DEV_ZONED) && defined(CONFIG_BLK_DEBUG_FS)
Expand Down
11 changes: 0 additions & 11 deletions block/blk-rq-qos.c
Original file line number Diff line number Diff line change
Expand Up @@ -347,13 +347,6 @@ int rq_qos_add(struct rq_qos *rqos, struct gendisk *disk, enum rq_qos_id id,
blk_queue_flag_set(QUEUE_FLAG_QOS_ENABLED, q);

blk_mq_unfreeze_queue(q, memflags);

if (rqos->ops->debugfs_attrs) {
mutex_lock(&q->debugfs_mutex);
blk_mq_debugfs_register_rqos(rqos);
mutex_unlock(&q->debugfs_mutex);
}

return 0;
ebusy:
blk_mq_unfreeze_queue(q, memflags);
Expand All @@ -378,8 +371,4 @@ void rq_qos_del(struct rq_qos *rqos)
if (!q->rq_qos)
blk_queue_flag_clear(QUEUE_FLAG_QOS_ENABLED, q);
blk_mq_unfreeze_queue(q, memflags);

mutex_lock(&q->debugfs_mutex);
blk_mq_debugfs_unregister_rqos(rqos);
mutex_unlock(&q->debugfs_mutex);
}
39 changes: 2 additions & 37 deletions block/blk-sysfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -636,52 +636,17 @@ static ssize_t queue_wb_lat_show(struct gendisk *disk, char *page)
static ssize_t queue_wb_lat_store(struct gendisk *disk, const char *page,
size_t count)
{
struct request_queue *q = disk->queue;
struct rq_qos *rqos;
ssize_t ret;
s64 val;
unsigned int memflags;

ret = queue_var_store64(&val, page);
if (ret < 0)
return ret;
if (val < -1)
return -EINVAL;

/*
* Ensure that the queue is idled, in case the latency update
* ends up either enabling or disabling wbt completely. We can't
* have IO inflight if that happens.
*/
memflags = blk_mq_freeze_queue(q);

rqos = wbt_rq_qos(q);
if (!rqos) {
ret = wbt_init(disk);
if (ret)
goto out;
}

ret = count;
if (val == -1)
val = wbt_default_latency_nsec(q);
else if (val >= 0)
val *= 1000ULL;

if (wbt_get_min_lat(q) == val)
goto out;

blk_mq_quiesce_queue(q);

mutex_lock(&disk->rqos_state_mutex);
wbt_set_min_lat(q, val);
mutex_unlock(&disk->rqos_state_mutex);

blk_mq_unquiesce_queue(q);
out:
blk_mq_unfreeze_queue(q, memflags);

return ret;
ret = wbt_set_lat(disk, val);
return ret ? ret : count;
}

QUEUE_RW_ENTRY(queue_wb_lat, "wbt_lat_usec");
Expand Down
Loading