LCOV - code coverage report
Current view: top level - block - blk-mq-sysfs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 121 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 17 0.0 %

          Line data    Source code
       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             : 
      18           0 : static void blk_mq_sysfs_release(struct kobject *kobj)
      19             : {
      20           0 :         struct blk_mq_ctxs *ctxs = container_of(kobj, struct blk_mq_ctxs, kobj);
      21             : 
      22           0 :         free_percpu(ctxs->queue_ctx);
      23           0 :         kfree(ctxs);
      24           0 : }
      25             : 
      26           0 : static void blk_mq_ctx_sysfs_release(struct kobject *kobj)
      27             : {
      28           0 :         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           0 :         kobject_put(&ctx->ctxs->kobj);
      32           0 : }
      33             : 
      34           0 : static void blk_mq_hw_sysfs_release(struct kobject *kobj)
      35             : {
      36           0 :         struct blk_mq_hw_ctx *hctx = container_of(kobj, struct blk_mq_hw_ctx,
      37             :                                                   kobj);
      38             : 
      39           0 :         blk_free_flush_queue(hctx->fq);
      40           0 :         sbitmap_free(&hctx->ctx_map);
      41           0 :         free_cpumask_var(hctx->cpumask);
      42           0 :         kfree(hctx->ctxs);
      43           0 :         kfree(hctx);
      44           0 : }
      45             : 
      46             : struct blk_mq_hw_ctx_sysfs_entry {
      47             :         struct attribute attr;
      48             :         ssize_t (*show)(struct blk_mq_hw_ctx *, char *);
      49             :         ssize_t (*store)(struct blk_mq_hw_ctx *, const char *, size_t);
      50             : };
      51             : 
      52           0 : static ssize_t blk_mq_hw_sysfs_show(struct kobject *kobj,
      53             :                                     struct attribute *attr, char *page)
      54             : {
      55             :         struct blk_mq_hw_ctx_sysfs_entry *entry;
      56             :         struct blk_mq_hw_ctx *hctx;
      57             :         struct request_queue *q;
      58             :         ssize_t res;
      59             : 
      60           0 :         entry = container_of(attr, struct blk_mq_hw_ctx_sysfs_entry, attr);
      61           0 :         hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj);
      62           0 :         q = hctx->queue;
      63             : 
      64           0 :         if (!entry->show)
      65             :                 return -EIO;
      66             : 
      67           0 :         mutex_lock(&q->sysfs_lock);
      68           0 :         res = entry->show(hctx, page);
      69           0 :         mutex_unlock(&q->sysfs_lock);
      70           0 :         return res;
      71             : }
      72             : 
      73           0 : static ssize_t blk_mq_hw_sysfs_store(struct kobject *kobj,
      74             :                                      struct attribute *attr, const char *page,
      75             :                                      size_t length)
      76             : {
      77             :         struct blk_mq_hw_ctx_sysfs_entry *entry;
      78             :         struct blk_mq_hw_ctx *hctx;
      79             :         struct request_queue *q;
      80             :         ssize_t res;
      81             : 
      82           0 :         entry = container_of(attr, struct blk_mq_hw_ctx_sysfs_entry, attr);
      83           0 :         hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj);
      84           0 :         q = hctx->queue;
      85             : 
      86           0 :         if (!entry->store)
      87             :                 return -EIO;
      88             : 
      89           0 :         mutex_lock(&q->sysfs_lock);
      90           0 :         res = entry->store(hctx, page, length);
      91           0 :         mutex_unlock(&q->sysfs_lock);
      92           0 :         return res;
      93             : }
      94             : 
      95           0 : static ssize_t blk_mq_hw_sysfs_nr_tags_show(struct blk_mq_hw_ctx *hctx,
      96             :                                             char *page)
      97             : {
      98           0 :         return sprintf(page, "%u\n", hctx->tags->nr_tags);
      99             : }
     100             : 
     101           0 : static ssize_t blk_mq_hw_sysfs_nr_reserved_tags_show(struct blk_mq_hw_ctx *hctx,
     102             :                                                      char *page)
     103             : {
     104           0 :         return sprintf(page, "%u\n", hctx->tags->nr_reserved_tags);
     105             : }
     106             : 
     107           0 : static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page)
     108             : {
     109           0 :         const size_t size = PAGE_SIZE - 1;
     110           0 :         unsigned int i, first = 1;
     111           0 :         int ret = 0, pos = 0;
     112             : 
     113           0 :         for_each_cpu(i, hctx->cpumask) {
     114           0 :                 if (first)
     115           0 :                         ret = snprintf(pos + page, size - pos, "%u", i);
     116             :                 else
     117           0 :                         ret = snprintf(pos + page, size - pos, ", %u", i);
     118             : 
     119           0 :                 if (ret >= size - pos)
     120             :                         break;
     121             : 
     122           0 :                 first = 0;
     123           0 :                 pos += ret;
     124             :         }
     125             : 
     126           0 :         ret = snprintf(pos + page, size + 1 - pos, "\n");
     127           0 :         return pos + ret;
     128             : }
     129             : 
     130             : static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_tags = {
     131             :         .attr = {.name = "nr_tags", .mode = 0444 },
     132             :         .show = blk_mq_hw_sysfs_nr_tags_show,
     133             : };
     134             : static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_nr_reserved_tags = {
     135             :         .attr = {.name = "nr_reserved_tags", .mode = 0444 },
     136             :         .show = blk_mq_hw_sysfs_nr_reserved_tags_show,
     137             : };
     138             : static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = {
     139             :         .attr = {.name = "cpu_list", .mode = 0444 },
     140             :         .show = blk_mq_hw_sysfs_cpus_show,
     141             : };
     142             : 
     143             : static struct attribute *default_hw_ctx_attrs[] = {
     144             :         &blk_mq_hw_sysfs_nr_tags.attr,
     145             :         &blk_mq_hw_sysfs_nr_reserved_tags.attr,
     146             :         &blk_mq_hw_sysfs_cpus.attr,
     147             :         NULL,
     148             : };
     149             : ATTRIBUTE_GROUPS(default_hw_ctx);
     150             : 
     151             : static const struct sysfs_ops blk_mq_hw_sysfs_ops = {
     152             :         .show   = blk_mq_hw_sysfs_show,
     153             :         .store  = blk_mq_hw_sysfs_store,
     154             : };
     155             : 
     156             : static struct kobj_type blk_mq_ktype = {
     157             :         .release        = blk_mq_sysfs_release,
     158             : };
     159             : 
     160             : static struct kobj_type blk_mq_ctx_ktype = {
     161             :         .release        = blk_mq_ctx_sysfs_release,
     162             : };
     163             : 
     164             : static struct kobj_type blk_mq_hw_ktype = {
     165             :         .sysfs_ops      = &blk_mq_hw_sysfs_ops,
     166             :         .default_groups = default_hw_ctx_groups,
     167             :         .release        = blk_mq_hw_sysfs_release,
     168             : };
     169             : 
     170           0 : static void blk_mq_unregister_hctx(struct blk_mq_hw_ctx *hctx)
     171             : {
     172             :         struct blk_mq_ctx *ctx;
     173             :         int i;
     174             : 
     175           0 :         if (!hctx->nr_ctx)
     176             :                 return;
     177             : 
     178           0 :         hctx_for_each_ctx(hctx, ctx, i)
     179           0 :                 kobject_del(&ctx->kobj);
     180             : 
     181           0 :         kobject_del(&hctx->kobj);
     182             : }
     183             : 
     184           0 : static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx)
     185             : {
     186           0 :         struct request_queue *q = hctx->queue;
     187             :         struct blk_mq_ctx *ctx;
     188             :         int i, ret;
     189             : 
     190           0 :         if (!hctx->nr_ctx)
     191             :                 return 0;
     192             : 
     193           0 :         ret = kobject_add(&hctx->kobj, q->mq_kobj, "%u", hctx->queue_num);
     194           0 :         if (ret)
     195             :                 return ret;
     196             : 
     197           0 :         hctx_for_each_ctx(hctx, ctx, i) {
     198           0 :                 ret = kobject_add(&ctx->kobj, &hctx->kobj, "cpu%u", ctx->cpu);
     199           0 :                 if (ret)
     200             :                         break;
     201             :         }
     202             : 
     203             :         return ret;
     204             : }
     205             : 
     206           0 : void blk_mq_unregister_dev(struct device *dev, struct request_queue *q)
     207             : {
     208             :         struct blk_mq_hw_ctx *hctx;
     209             :         unsigned long i;
     210             : 
     211             :         lockdep_assert_held(&q->sysfs_dir_lock);
     212             : 
     213           0 :         queue_for_each_hw_ctx(q, hctx, i)
     214           0 :                 blk_mq_unregister_hctx(hctx);
     215             : 
     216           0 :         kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
     217           0 :         kobject_del(q->mq_kobj);
     218           0 :         kobject_put(&dev->kobj);
     219             : 
     220           0 :         q->mq_sysfs_init_done = false;
     221           0 : }
     222             : 
     223           0 : void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx)
     224             : {
     225           0 :         kobject_init(&hctx->kobj, &blk_mq_hw_ktype);
     226           0 : }
     227             : 
     228           0 : void blk_mq_sysfs_deinit(struct request_queue *q)
     229             : {
     230             :         struct blk_mq_ctx *ctx;
     231             :         int cpu;
     232             : 
     233           0 :         for_each_possible_cpu(cpu) {
     234           0 :                 ctx = per_cpu_ptr(q->queue_ctx, cpu);
     235           0 :                 kobject_put(&ctx->kobj);
     236             :         }
     237           0 :         kobject_put(q->mq_kobj);
     238           0 : }
     239             : 
     240           0 : void blk_mq_sysfs_init(struct request_queue *q)
     241             : {
     242             :         struct blk_mq_ctx *ctx;
     243             :         int cpu;
     244             : 
     245           0 :         kobject_init(q->mq_kobj, &blk_mq_ktype);
     246             : 
     247           0 :         for_each_possible_cpu(cpu) {
     248           0 :                 ctx = per_cpu_ptr(q->queue_ctx, cpu);
     249             : 
     250           0 :                 kobject_get(q->mq_kobj);
     251           0 :                 kobject_init(&ctx->kobj, &blk_mq_ctx_ktype);
     252             :         }
     253           0 : }
     254             : 
     255           0 : int __blk_mq_register_dev(struct device *dev, struct request_queue *q)
     256             : {
     257             :         struct blk_mq_hw_ctx *hctx;
     258             :         unsigned long i, j;
     259             :         int ret;
     260             : 
     261           0 :         WARN_ON_ONCE(!q->kobj.parent);
     262             :         lockdep_assert_held(&q->sysfs_dir_lock);
     263             : 
     264           0 :         ret = kobject_add(q->mq_kobj, kobject_get(&dev->kobj), "%s", "mq");
     265           0 :         if (ret < 0)
     266             :                 goto out;
     267             : 
     268           0 :         kobject_uevent(q->mq_kobj, KOBJ_ADD);
     269             : 
     270           0 :         queue_for_each_hw_ctx(q, hctx, i) {
     271           0 :                 ret = blk_mq_register_hctx(hctx);
     272           0 :                 if (ret)
     273             :                         goto unreg;
     274             :         }
     275             : 
     276           0 :         q->mq_sysfs_init_done = true;
     277             : 
     278             : out:
     279             :         return ret;
     280             : 
     281             : unreg:
     282           0 :         queue_for_each_hw_ctx(q, hctx, j) {
     283           0 :                 if (j < i)
     284           0 :                         blk_mq_unregister_hctx(hctx);
     285             :         }
     286             : 
     287           0 :         kobject_uevent(q->mq_kobj, KOBJ_REMOVE);
     288           0 :         kobject_del(q->mq_kobj);
     289           0 :         kobject_put(&dev->kobj);
     290           0 :         return ret;
     291             : }
     292             : 
     293           0 : void blk_mq_sysfs_unregister(struct request_queue *q)
     294             : {
     295             :         struct blk_mq_hw_ctx *hctx;
     296             :         unsigned long i;
     297             : 
     298           0 :         mutex_lock(&q->sysfs_dir_lock);
     299           0 :         if (!q->mq_sysfs_init_done)
     300             :                 goto unlock;
     301             : 
     302           0 :         queue_for_each_hw_ctx(q, hctx, i)
     303           0 :                 blk_mq_unregister_hctx(hctx);
     304             : 
     305             : unlock:
     306           0 :         mutex_unlock(&q->sysfs_dir_lock);
     307           0 : }
     308             : 
     309           0 : int blk_mq_sysfs_register(struct request_queue *q)
     310             : {
     311             :         struct blk_mq_hw_ctx *hctx;
     312             :         unsigned long i;
     313           0 :         int ret = 0;
     314             : 
     315           0 :         mutex_lock(&q->sysfs_dir_lock);
     316           0 :         if (!q->mq_sysfs_init_done)
     317             :                 goto unlock;
     318             : 
     319           0 :         queue_for_each_hw_ctx(q, hctx, i) {
     320           0 :                 ret = blk_mq_register_hctx(hctx);
     321           0 :                 if (ret)
     322             :                         break;
     323             :         }
     324             : 
     325             : unlock:
     326           0 :         mutex_unlock(&q->sysfs_dir_lock);
     327             : 
     328           0 :         return ret;
     329             : }

Generated by: LCOV version 1.14