linux/block/blk-mq-sysfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/module.h>
   4#include <linux/backing-dev.h>
   5#include <linux/bio.h>
   6#include <linux/blkdev.h>
   7#include <linux/mm.h>
   8#include <linux/init.h>
   9#include <linux/slab.h>
  10#include <linux/workqueue.h>
  11#include <linux/smp.h>
  12
  13#include <linux/blk-mq.h>
  14#include "blk.h"
  15#include "blk-mq.h"
  16#include "blk-mq-tag.h"
  17
  18static void blk_mq_sysfs_release(struct kobject *kobj)
  19{
  20        struct blk_mq_ctxs *ctxs = container_of(kobj, struct blk_mq_ctxs, kobj);
  21
  22        free_percpu(ctxs->queue_ctx);
  23        kfree(ctxs);
  24}
  25
  26static void blk_mq_ctx_sysfs_release(struct kobject *kobj)
  27{
  28        struct blk_mq_ctx *ctx = container_of(kobj, struct blk_mq_ctx, kobj);
  29
  30        /* ctx->ctxs won't be released until all ctx are freed */
  31        kobject_put(&ctx->ctxs->kobj);
  32}
  33
  34static void blk_mq_hw_sysfs_release(struct kobject *kobj)
  35{
  36        struct blk_mq_hw_ctx *hctx = container_of(kobj, struct blk_mq_hw_ctx,
  37                                                  kobj);
  38
  39        if (hctx->flags & BLK_MQ_F_BLOCKING)
  40                cleanup_srcu_struct(hctx->srcu);
  41        blk_free_flush_queue(hctx->fq);
  42        sbitmap_free(&hctx->ctx_map);
  43        free_cpumask_var(hctx->cpumask);
  44        kfree(hctx->ctxs);
  45        kfree(hctx);
  46}
  47
  48struct blk_mq_ctx_sysfs_entry {
  49        struct attribute attr;
  50        ssize_t (*show)(struct blk_mq_ctx *, char *);
  51        ssize_t (*store)(struct blk_mq_ctx *, const char *, size_t);
  52};
  53
  54struct blk_mq_hw_ctx_sysfs_entry {
  55        struct attribute attr;
  56        ssize_t (*show)(struct blk_mq_hw_ctx *, char *);
  57        ssize_t (*store)(struct blk_mq_hw_ctx *, const char *, size_t);
  58};
  59
  60static ssize_t blk_mq_sysfs_show(struct kobject *kobj, struct attribute *attr,
  61                                 char *page)
  62{
  63        struct blk_mq_ctx_sysfs_entry *entry;
  64        struct blk_mq_ctx *ctx;
  65        struct request_queue *q;
  66        ssize_t res;
  67
  68        entry = container_of(attr, struct blk_mq_ctx_sysfs_entry, attr);
  69        ctx = container_of(kobj, struct blk_mq_ctx, kobj);
  70        q = ctx->queue;
  71
  72        if (!entry->show)
  73                return -EIO;
  74
  75        mutex_lock(&q->sysfs_lock);
  76        res = entry->show(ctx, page);
  77        mutex_unlock(&q->sysfs_lock);
  78        return res;
  79}
  80
  81static ssize_t blk_mq_sysfs_store(struct kobject *kobj, struct attribute *attr,
  82                                  const char *page, size_t length)
  83{
  84        struct blk_mq_ctx_sysfs_entry *entry;
  85        struct blk_mq_ctx *ctx;
  86        struct request_queue *q;
  87        ssize_t res;
  88
  89        entry = container_of(attr, struct blk_mq_ctx_sysfs_entry, attr);
  90        ctx = container_of(kobj, struct blk_mq_ctx, kobj);
  91        q = ctx->queue;
  92
  93        if (!entry->store)
  94                return -EIO;
  95
  96        mutex_lock(&q->sysfs_lock);
  97        res = entry->store(ctx, page, length);
  98        mutex_unlock(&q->sysfs_lock);
  99        return res;
 100}
 101
 102static ssize_t blk_mq_hw_sysfs_show(struct kobject *kobj,
 103                                    struct attribute *attr, char *page)
 104{
 105        struct blk_mq_hw_ctx_sysfs_entry *entry;
 106        struct blk_mq_hw_ctx *hctx;
 107        struct request_queue *q;
 108        ssize_t res;
 109
 110        entry = container_of(attr, struct blk_mq_hw_ctx_sysfs_entry, attr);
 111        hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj);
 112        q = hctx->queue;
 113
 114        if (!entry->show)
 115                return -EIO;
 116
 117        mutex_lock(&q->sysfs_lock);
 118        res = entry->show(hctx, page);
 119        mutex_unlock(&q->sysfs_lock);
 120        return res;
 121}
 122
 123static ssize_t blk_mq_hw_sysfs_store(struct kobject *kobj,
 124                                     struct attribute *attr, const char *page,
 125                                     size_t length)
 126{
 127        struct blk_mq_hw_ctx_sysfs_entry *entry;
 128        struct blk_mq_hw_ctx *hctx;
 129        struct request_queue *q;
 130        ssize_t res;
 131
 132        entry = container_of(attr, struct blk_mq_hw_ctx_sysfs_entry, attr);
 133        hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj);
 134        q = hctx->queue;
 135
 136        if (!entry->store)
 137                return -EIO;
 138
 139        mutex_lock(&q->sysfs_lock);
 140        res = entry->store(hctx, page, length);
 141        mutex_unlock(&q->sysfs_lock);
 142        return res;
 143}
 144
 145static ssize_t blk_mq_hw_sysfs_nr_tags_show(struct blk_mq_hw_ctx *hctx,
 146                                            char *page)
 147{
 148        return sprintf(page, "%u\n", hctx->tags->nr_tags);
 149}
 150
 151static ssize_t blk_mq_hw_sysfs_nr_reserved_tags_show(struct blk_mq_hw_ctx *hctx,
 152                                                     char *page)
 153{
 154        return sprintf(page, "%u\n", hctx->tags->nr_reserved_tags);
 155}
 156
 157static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
 158{
 159        const size_t size = PAGE_SIZE - 1;
 160        unsigned int i, first = 1;
 161        int ret = 0, pos = 0;
 162
 163        for_each_cpu(i, hctx->cpumask) {
 164                if (first)
 165                        ret = snprintf(pos + page, size - pos, "%u", i);
 166                else
 167                        ret = snprintf(pos + page, size - pos, ", %u", i);
 168
 169                if (ret >= size - pos)
 170                        break;
 171
 172                first = 0;
 173                pos += ret;
 174        }
 175
 176        ret = snprintf(pos + page, size + 1 - pos, "\n");
 177        return pos + ret;
 178}
 179
 180static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_tags = {
 181        .attr = {.name = "nr_tags", .mode = 0444 },
 182        .show = blk_mq_hw_sysfs_nr_tags_show,
 183};
 184static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_reserved_tags = {
 185        .attr = {.name = "nr_reserved_tags", .mode = 0444 },
 186        .show = blk_mq_hw_sysfs_nr_reserved_tags_show,
 187};
 188static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
 189        .attr = {.name = "cpu_list", .mode = 0444 },
 190        .show = blk_mq_hw_sysfs_cpus_show,
 191};
 192
 193static struct attribute *default_hw_ctx_attrs[] = {
 194        &blk_mq_hw_sysfs_nr_tags.attr,
 195        &blk_mq_hw_sysfs_nr_reserved_tags.attr,
 196        &blk_mq_hw_sysfs_cpus.attr,
 197        NULL,
 198};
 199ATTRIBUTE_GROUPS(default_hw_ctx);
 200
 201static const struct sysfs_ops blk_mq_sysfs_ops = {
 202        .show   = blk_mq_sysfs_show,
 203        .store  = blk_mq_sysfs_store,
 204};
 205
 206static const struct sysfs_ops blk_mq_hw_sysfs_ops = {
 207        .show   = blk_mq_hw_sysfs_show,
 208        .store  = blk_mq_hw_sysfs_store,
 209};
 210
 211static struct kobj_type blk_mq_ktype = {
 212        .sysfs_ops      = &blk_mq_sysfs_ops,
 213        .release        = blk_mq_sysfs_release,
 214};
 215
 216static struct kobj_type blk_mq_ctx_ktype = {
 217        .sysfs_ops      = &blk_mq_sysfs_ops,
 218        .release        = blk_mq_ctx_sysfs_release,
 219};
 220
 221static struct kobj_type blk_mq_hw_ktype = {
 222        .sysfs_ops      = &blk_mq_hw_sysfs_ops,
 223        .default_groups = default_hw_ctx_groups,
 224        .release        = blk_mq_hw_sysfs_release,
 225};
 226
 227static void blk_mq_unregister_hctx(struct blk_mq_hw_ctx *hctx)
 228{
 229        struct blk_mq_ctx *ctx;
 230        int i;
 231
 232        if (!hctx->nr_ctx)
 233                return;
 234
 235        hctx_for_each_ctx(hctx, ctx, i)
 236                kobject_del(&ctx->kobj);
 237
 238        kobject_del(&hctx->kobj);
 239}
 240
 241static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
 242{
 243        struct request_queue *q = hctx->queue;
 244        struct blk_mq_ctx *ctx;
 245        int i, ret;
 246
 247        if (!hctx->nr_ctx)
 248                return 0;
 249
 250        ret = kobject_add(&hctx->kobj, q->mq_kobj, "%u", hctx->queue_num);
 251        if (ret)
 252                return ret;
 253
 254        hctx_for_each_ctx(hctx, ctx, i) {
 255                ret = kobject_add(&ctx->kobj, &hctx->kobj, "cpu%u", ctx->cpu);
 256                if (ret)
 257                        break;
 258        }
 259
 260        return ret;
 261}
 262
 263void blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
 264{
 265        struct blk_mq_hw_ctx *hctx;
 266        int i;
 267
 268        lockdep_assert_held(&q->sysfs_dir_lock);
 269
 270        queue_for_each_hw_ctx(q, hctx, i)
 271                blk_mq_unregister_hctx(hctx);
 272
 273        kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
 274        kobject_del(q->mq_kobj);
 275        kobject_put(&dev->kobj);
 276
 277        q->mq_sysfs_init_done = false;
 278}
 279
 280void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx)
 281{
 282        kobject_init(&hctx->kobj, &blk_mq_hw_ktype);
 283}
 284
 285void blk_mq_sysfs_deinit(struct request_queue *q)
 286{
 287        struct blk_mq_ctx *ctx;
 288        int cpu;
 289
 290        for_each_possible_cpu(cpu) {
 291                ctx = per_cpu_ptr(q->queue_ctx, cpu);
 292                kobject_put(&ctx->kobj);
 293        }
 294        kobject_put(q->mq_kobj);
 295}
 296
 297void blk_mq_sysfs_init(struct request_queue *q)
 298{
 299        struct blk_mq_ctx *ctx;
 300        int cpu;
 301
 302        kobject_init(q->mq_kobj, &blk_mq_ktype);
 303
 304        for_each_possible_cpu(cpu) {
 305                ctx = per_cpu_ptr(q->queue_ctx, cpu);
 306
 307                kobject_get(q->mq_kobj);
 308                kobject_init(&ctx->kobj, &blk_mq_ctx_ktype);
 309        }
 310}
 311
 312int __blk_mq_register_dev(struct device *dev, struct request_queue *q)
 313{
 314        struct blk_mq_hw_ctx *hctx;
 315        int ret, i;
 316
 317        WARN_ON_ONCE(!q->kobj.parent);
 318        lockdep_assert_held(&q->sysfs_dir_lock);
 319
 320        ret = kobject_add(q->mq_kobj, kobject_get(&dev->kobj), "%s", "mq");
 321        if (ret < 0)
 322                goto out;
 323
 324        kobject_uevent(q->mq_kobj, KOBJ_ADD);
 325
 326        queue_for_each_hw_ctx(q, hctx, i) {
 327                ret = blk_mq_register_hctx(hctx);
 328                if (ret)
 329                        goto unreg;
 330        }
 331
 332        q->mq_sysfs_init_done = true;
 333
 334out:
 335        return ret;
 336
 337unreg:
 338        while (--i >= 0)
 339                blk_mq_unregister_hctx(q->queue_hw_ctx[i]);
 340
 341        kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
 342        kobject_del(q->mq_kobj);
 343        kobject_put(&dev->kobj);
 344        return ret;
 345}
 346
 347void blk_mq_sysfs_unregister(struct request_queue *q)
 348{
 349        struct blk_mq_hw_ctx *hctx;
 350        int i;
 351
 352        mutex_lock(&q->sysfs_dir_lock);
 353        if (!q->mq_sysfs_init_done)
 354                goto unlock;
 355
 356        queue_for_each_hw_ctx(q, hctx, i)
 357                blk_mq_unregister_hctx(hctx);
 358
 359unlock:
 360        mutex_unlock(&q->sysfs_dir_lock);
 361}
 362
 363int blk_mq_sysfs_register(struct request_queue *q)
 364{
 365        struct blk_mq_hw_ctx *hctx;
 366        int i, ret = 0;
 367
 368        mutex_lock(&q->sysfs_dir_lock);
 369        if (!q->mq_sysfs_init_done)
 370                goto unlock;
 371
 372        queue_for_each_hw_ctx(q, hctx, i) {
 373                ret = blk_mq_register_hctx(hctx);
 374                if (ret)
 375                        break;
 376        }
 377
 378unlock:
 379        mutex_unlock(&q->sysfs_dir_lock);
 380
 381        return ret;
 382}
 383