08a9ad8bf6
Maintain statistics per cgroup and export these to user space. These statistics are essential for verifying whether the proper I/O priorities have been assigned to requests. An example of the statistics data with this patch applied: $ cat /sys/fs/cgroup/io.stat 11:2 rbytes=0 wbytes=0 rios=3 wios=0 dbytes=0 dios=0 [NONE] dispatched=0 inserted=0 merged=171 [RT] dispatched=0 inserted=0 merged=0 [BE] dispatched=0 inserted=0 merged=0 [IDLE] dispatched=0 inserted=0 merged=0 8:32 rbytes=2142720 wbytes=0 rios=105 wios=0 dbytes=0 dios=0 [NONE] dispatched=0 inserted=0 merged=171 [RT] dispatched=0 inserted=0 merged=0 [BE] dispatched=0 inserted=0 merged=0 [IDLE] dispatched=0 inserted=0 merged=0 Cc: Damien Le Moal <damien.lemoal@wdc.com> Cc: Hannes Reinecke <hare@suse.de> Cc: Christoph Hellwig <hch@lst.de> Cc: Ming Lei <ming.lei@redhat.com> Cc: Johannes Thumshirn <johannes.thumshirn@wdc.com> Cc: Himanshu Madhani <himanshu.madhani@oracle.com> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Link: https://lore.kernel.org/r/20210618004456.7280-16-bvanassche@acm.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
127 lines
2.8 KiB
C
127 lines
2.8 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/blk-cgroup.h>
|
|
#include <linux/ioprio.h>
|
|
|
|
#include "mq-deadline-cgroup.h"
|
|
|
|
static struct blkcg_policy dd_blkcg_policy;
|
|
|
|
static struct blkcg_policy_data *dd_cpd_alloc(gfp_t gfp)
|
|
{
|
|
struct dd_blkcg *pd;
|
|
|
|
pd = kzalloc(sizeof(*pd), gfp);
|
|
if (!pd)
|
|
return NULL;
|
|
pd->stats = alloc_percpu_gfp(typeof(*pd->stats),
|
|
GFP_KERNEL | __GFP_ZERO);
|
|
if (!pd->stats) {
|
|
kfree(pd);
|
|
return NULL;
|
|
}
|
|
return &pd->cpd;
|
|
}
|
|
|
|
static void dd_cpd_free(struct blkcg_policy_data *cpd)
|
|
{
|
|
struct dd_blkcg *dd_blkcg = container_of(cpd, typeof(*dd_blkcg), cpd);
|
|
|
|
free_percpu(dd_blkcg->stats);
|
|
kfree(dd_blkcg);
|
|
}
|
|
|
|
static struct dd_blkcg *dd_blkcg_from_pd(struct blkg_policy_data *pd)
|
|
{
|
|
return container_of(blkcg_to_cpd(pd->blkg->blkcg, &dd_blkcg_policy),
|
|
struct dd_blkcg, cpd);
|
|
}
|
|
|
|
/*
|
|
* Convert an association between a block cgroup and a request queue into a
|
|
* pointer to the mq-deadline information associated with a (blkcg, queue) pair.
|
|
*/
|
|
struct dd_blkcg *dd_blkcg_from_bio(struct bio *bio)
|
|
{
|
|
struct blkg_policy_data *pd;
|
|
|
|
pd = blkg_to_pd(bio->bi_blkg, &dd_blkcg_policy);
|
|
if (!pd)
|
|
return NULL;
|
|
|
|
return dd_blkcg_from_pd(pd);
|
|
}
|
|
|
|
static size_t dd_pd_stat(struct blkg_policy_data *pd, char *buf, size_t size)
|
|
{
|
|
static const char *const prio_class_name[] = {
|
|
[IOPRIO_CLASS_NONE] = "NONE",
|
|
[IOPRIO_CLASS_RT] = "RT",
|
|
[IOPRIO_CLASS_BE] = "BE",
|
|
[IOPRIO_CLASS_IDLE] = "IDLE",
|
|
};
|
|
struct dd_blkcg *blkcg = dd_blkcg_from_pd(pd);
|
|
int res = 0;
|
|
u8 prio;
|
|
|
|
for (prio = 0; prio < ARRAY_SIZE(blkcg->stats->stats); prio++)
|
|
res += scnprintf(buf + res, size - res,
|
|
" [%s] dispatched=%u inserted=%u merged=%u",
|
|
prio_class_name[prio],
|
|
ddcg_sum(blkcg, dispatched, prio) +
|
|
ddcg_sum(blkcg, merged, prio) -
|
|
ddcg_sum(blkcg, completed, prio),
|
|
ddcg_sum(blkcg, inserted, prio) -
|
|
ddcg_sum(blkcg, completed, prio),
|
|
ddcg_sum(blkcg, merged, prio));
|
|
|
|
return res;
|
|
}
|
|
|
|
static struct blkg_policy_data *dd_pd_alloc(gfp_t gfp, struct request_queue *q,
|
|
struct blkcg *blkcg)
|
|
{
|
|
struct dd_blkg *pd;
|
|
|
|
pd = kzalloc(sizeof(*pd), gfp);
|
|
if (!pd)
|
|
return NULL;
|
|
return &pd->pd;
|
|
}
|
|
|
|
static void dd_pd_free(struct blkg_policy_data *pd)
|
|
{
|
|
struct dd_blkg *dd_blkg = container_of(pd, typeof(*dd_blkg), pd);
|
|
|
|
kfree(dd_blkg);
|
|
}
|
|
|
|
static struct blkcg_policy dd_blkcg_policy = {
|
|
.cpd_alloc_fn = dd_cpd_alloc,
|
|
.cpd_free_fn = dd_cpd_free,
|
|
|
|
.pd_alloc_fn = dd_pd_alloc,
|
|
.pd_free_fn = dd_pd_free,
|
|
.pd_stat_fn = dd_pd_stat,
|
|
};
|
|
|
|
int dd_activate_policy(struct request_queue *q)
|
|
{
|
|
return blkcg_activate_policy(q, &dd_blkcg_policy);
|
|
}
|
|
|
|
void dd_deactivate_policy(struct request_queue *q)
|
|
{
|
|
blkcg_deactivate_policy(q, &dd_blkcg_policy);
|
|
}
|
|
|
|
int __init dd_blkcg_init(void)
|
|
{
|
|
return blkcg_policy_register(&dd_blkcg_policy);
|
|
}
|
|
|
|
void __exit dd_blkcg_exit(void)
|
|
{
|
|
blkcg_policy_unregister(&dd_blkcg_policy);
|
|
}
|