Commit cc56694f authored by Ming Lei's avatar Ming Lei Committed by Jens Axboe
Browse files

blk-mq-debugfs: support rq_qos



blk-mq-debugfs has been proved as very helpful for debug some
tough issues, such as IO hang.

We have seen blk-wbt related IO hang several times, even inside
Red Hat BZ, there is such report not sovled yet, so this patch
adds support debugfs on rq_qos.

Cc: Bart Van Assche <bart.vanassche@wdc.com>
Cc: Omar Sandoval <osandov@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarMing Lei <ming.lei@redhat.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent f9824952
Loading
Loading
Loading
Loading
+54 −0
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@
#include "blk-mq.h"
#include "blk-mq.h"
#include "blk-mq-debugfs.h"
#include "blk-mq-debugfs.h"
#include "blk-mq-tag.h"
#include "blk-mq-tag.h"
#include "blk-rq-qos.h"


static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
static void print_stat(struct seq_file *m, struct blk_rq_stat *stat)
{
{
@@ -856,6 +857,15 @@ int blk_mq_debugfs_register(struct request_queue *q)
			goto err;
			goto err;
	}
	}


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

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

	return 0;
	return 0;


err:
err:
@@ -978,6 +988,50 @@ void blk_mq_debugfs_unregister_sched(struct request_queue *q)
	q->sched_debugfs_dir = NULL;
	q->sched_debugfs_dir = NULL;
}
}


void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos)
{
	debugfs_remove_recursive(rqos->debugfs_dir);
	rqos->debugfs_dir = NULL;
}

int blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
{
	struct request_queue *q = rqos->q;
	const char *dir_name = rq_qos_id_to_name(rqos->id);

	if (!q->debugfs_dir)
		return -ENOENT;

	if (rqos->debugfs_dir || !rqos->ops->debugfs_attrs)
		return 0;

	if (!q->rqos_debugfs_dir) {
		q->rqos_debugfs_dir = debugfs_create_dir("rqos",
							 q->debugfs_dir);
		if (!q->rqos_debugfs_dir)
			return -ENOMEM;
	}

	rqos->debugfs_dir = debugfs_create_dir(dir_name,
					       rqos->q->rqos_debugfs_dir);
	if (!rqos->debugfs_dir)
		return -ENOMEM;

	if (!debugfs_create_files(rqos->debugfs_dir, rqos,
				  rqos->ops->debugfs_attrs))
		goto err;
	return 0;
 err:
	blk_mq_debugfs_unregister_rqos(rqos);
	return -ENOMEM;
}

void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q)
{
	debugfs_remove_recursive(q->rqos_debugfs_dir);
	q->rqos_debugfs_dir = NULL;
}

int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
				       struct blk_mq_hw_ctx *hctx)
				       struct blk_mq_hw_ctx *hctx)
{
{
+17 −0
Original line number Original line Diff line number Diff line
@@ -31,6 +31,10 @@ void blk_mq_debugfs_unregister_sched(struct request_queue *q);
int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
				       struct blk_mq_hw_ctx *hctx);
				       struct blk_mq_hw_ctx *hctx);
void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx);
void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx);

int blk_mq_debugfs_register_rqos(struct rq_qos *rqos);
void blk_mq_debugfs_unregister_rqos(struct rq_qos *rqos);
void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q);
#else
#else
static inline int blk_mq_debugfs_register(struct request_queue *q)
static inline int blk_mq_debugfs_register(struct request_queue *q)
{
{
@@ -78,6 +82,19 @@ static inline int blk_mq_debugfs_register_sched_hctx(struct request_queue *q,
static inline void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
static inline void blk_mq_debugfs_unregister_sched_hctx(struct blk_mq_hw_ctx *hctx)
{
{
}
}

static inline int blk_mq_debugfs_register_rqos(struct rq_qos *rqos)
{
	return 0;
}

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

static inline void blk_mq_debugfs_unregister_queue_rqos(struct request_queue *q)
{
}
#endif
#endif


#ifdef CONFIG_BLK_DEBUG_FS_ZONED
#ifdef CONFIG_BLK_DEBUG_FS_ZONED
+2 −0
Original line number Original line Diff line number Diff line
@@ -264,6 +264,8 @@ void rq_qos_wait(struct rq_wait *rqw, void *private_data,


void rq_qos_exit(struct request_queue *q)
void rq_qos_exit(struct request_queue *q)
{
{
	blk_mq_debugfs_unregister_queue_rqos(q);

	while (q->rq_qos) {
	while (q->rq_qos) {
		struct rq_qos *rqos = q->rq_qos;
		struct rq_qos *rqos = q->rq_qos;
		q->rq_qos = rqos->next;
		q->rq_qos = rqos->next;
+24 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,10 @@
#include <linux/atomic.h>
#include <linux/atomic.h>
#include <linux/wait.h>
#include <linux/wait.h>


#include "blk-mq-debugfs.h"

struct blk_mq_debugfs_attr;

enum rq_qos_id {
enum rq_qos_id {
	RQ_QOS_WBT,
	RQ_QOS_WBT,
	RQ_QOS_CGROUP,
	RQ_QOS_CGROUP,
@@ -22,6 +26,9 @@ struct rq_qos {
	struct request_queue *q;
	struct request_queue *q;
	enum rq_qos_id id;
	enum rq_qos_id id;
	struct rq_qos *next;
	struct rq_qos *next;
#ifdef CONFIG_BLK_DEBUG_FS
	struct dentry *debugfs_dir;
#endif
};
};


struct rq_qos_ops {
struct rq_qos_ops {
@@ -33,6 +40,7 @@ struct rq_qos_ops {
	void (*done_bio)(struct rq_qos *, struct bio *);
	void (*done_bio)(struct rq_qos *, struct bio *);
	void (*cleanup)(struct rq_qos *, struct bio *);
	void (*cleanup)(struct rq_qos *, struct bio *);
	void (*exit)(struct rq_qos *);
	void (*exit)(struct rq_qos *);
	const struct blk_mq_debugfs_attr *debugfs_attrs;
};
};


struct rq_depth {
struct rq_depth {
@@ -66,6 +74,17 @@ static inline struct rq_qos *blkcg_rq_qos(struct request_queue *q)
	return rq_qos_id(q, RQ_QOS_CGROUP);
	return rq_qos_id(q, RQ_QOS_CGROUP);
}
}


static inline const char *rq_qos_id_to_name(enum rq_qos_id id)
{
	switch (id) {
	case RQ_QOS_WBT:
		return "wbt";
	case RQ_QOS_CGROUP:
		return "cgroup";
	}
	return "unknown";
}

static inline void rq_wait_init(struct rq_wait *rq_wait)
static inline void rq_wait_init(struct rq_wait *rq_wait)
{
{
	atomic_set(&rq_wait->inflight, 0);
	atomic_set(&rq_wait->inflight, 0);
@@ -76,6 +95,9 @@ static inline void rq_qos_add(struct request_queue *q, struct rq_qos *rqos)
{
{
	rqos->next = q->rq_qos;
	rqos->next = q->rq_qos;
	q->rq_qos = rqos;
	q->rq_qos = rqos;

	if (rqos->ops->debugfs_attrs)
		blk_mq_debugfs_register_rqos(rqos);
}
}


static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
@@ -91,6 +113,8 @@ static inline void rq_qos_del(struct request_queue *q, struct rq_qos *rqos)
		}
		}
		prev = cur;
		prev = cur;
	}
	}

	blk_mq_debugfs_unregister_rqos(rqos);
}
}


typedef bool (acquire_inflight_cb_t)(struct rq_wait *rqw, void *private_data);
typedef bool (acquire_inflight_cb_t)(struct rq_wait *rqw, void *private_data);
+1 −0
Original line number Original line Diff line number Diff line
@@ -560,6 +560,7 @@ struct request_queue {
#ifdef CONFIG_BLK_DEBUG_FS
#ifdef CONFIG_BLK_DEBUG_FS
	struct dentry		*debugfs_dir;
	struct dentry		*debugfs_dir;
	struct dentry		*sched_debugfs_dir;
	struct dentry		*sched_debugfs_dir;
	struct dentry		*rqos_debugfs_dir;
#endif
#endif


	bool			mq_sysfs_init_done;
	bool			mq_sysfs_init_done;