]> www.infradead.org Git - users/hch/block.git/commitdiff
block: untangle request_queue refcounting from sysfs block-sysfs-cleanups
authorChristoph Hellwig <hch@lst.de>
Sat, 18 Jun 2022 14:30:13 +0000 (16:30 +0200)
committerChristoph Hellwig <hch@lst.de>
Sat, 18 Jun 2022 14:30:13 +0000 (16:30 +0200)
The kobject embedded into the request_queue is used for the queue
directory in sysfs, but that is a child of the gendisks directory and is
intimately tied to it.  Move this kobject to the gendisk and use a
refcount_t in the request_queue for the actual request_queue refcounting
that is completely unrelated to the device model.

Signed-off-by: Christoph Hellwig <hch@lst.de>
block/blk-core.c
block/blk-crypto-sysfs.c
block/blk-ia-ranges.c
block/blk-sysfs.c
block/blk.h
block/bsg.c
block/elevator.c
include/linux/blkdev.h

index 9f069c5a4688d9d5fe9b68ed26382e9789ff7def..e3a5a7e9669d1431d66ad922f126ff3505538aad 100644 (file)
@@ -46,6 +46,7 @@
 #include <trace/events/block.h>
 
 #include "blk.h"
+#include "blk-mq-debugfs.h"
 #include "blk-mq-sched.h"
 #include "blk-pm.h"
 #include "blk-cgroup.h"
@@ -60,13 +61,20 @@ EXPORT_TRACEPOINT_SYMBOL_GPL(block_split);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_unplug);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_insert);
 
-DEFINE_IDA(blk_queue_ida);
+static DEFINE_IDA(blk_queue_ida);
 
 /*
  * For queue allocation
  */
-struct kmem_cache *blk_requestq_cachep;
-struct kmem_cache *blk_requestq_srcu_cachep;
+static struct kmem_cache *blk_requestq_cachep;
+static struct kmem_cache *blk_requestq_srcu_cachep;
+
+static inline struct kmem_cache *blk_get_queue_kmem_cache(bool srcu)
+{
+       if (srcu)
+               return blk_requestq_srcu_cachep;
+       return blk_requestq_cachep;
+}
 
 /*
  * Controlling structure to kblockd
@@ -254,6 +262,41 @@ void blk_clear_pm_only(struct request_queue *q)
 }
 EXPORT_SYMBOL_GPL(blk_clear_pm_only);
 
+static void blk_free_queue_rcu(struct rcu_head *rcu_head)
+{
+       struct request_queue *q =
+               container_of(rcu_head, struct request_queue, rcu_head);
+
+       kmem_cache_free(blk_get_queue_kmem_cache(blk_queue_has_srcu(q)), q);
+}
+
+static void blk_queue_free(struct request_queue *q)
+{
+       might_sleep();
+
+       percpu_ref_exit(&q->q_usage_counter);
+
+       if (q->poll_stat)
+               blk_stat_remove_callback(q, q->poll_cb);
+       blk_stat_free_callback(q->poll_cb);
+
+       blk_free_queue_stats(q->stats);
+       kfree(q->poll_stat);
+
+       blk_queue_free_zone_bitmaps(q);
+
+       if (queue_is_mq(q))
+               blk_mq_release(q);
+
+       bioset_exit(&q->bio_split);
+
+       if (blk_queue_has_srcu(q))
+               cleanup_srcu_struct(q->srcu);
+
+       ida_simple_remove(&blk_queue_ida, q->id);
+       call_rcu(&q->rcu_head, blk_free_queue_rcu);
+}
+
 /**
  * blk_put_queue - decrement the request_queue refcount
  * @q: the request_queue structure to decrement the refcount for
@@ -266,7 +309,8 @@ EXPORT_SYMBOL_GPL(blk_clear_pm_only);
  */
 void blk_put_queue(struct request_queue *q)
 {
-       kobject_put(&q->kobj);
+       if (refcount_dec_and_test(&q->refs))
+               blk_queue_free(q);
 }
 EXPORT_SYMBOL(blk_put_queue);
 
@@ -412,8 +456,7 @@ struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu)
        INIT_WORK(&q->timeout_work, blk_timeout_work);
        INIT_LIST_HEAD(&q->icq_list);
 
-       kobject_init(&q->kobj, &blk_queue_ktype);
-
+       refcount_set(&q->refs, 1);
        mutex_init(&q->debugfs_mutex);
        mutex_init(&q->sysfs_lock);
        mutex_init(&q->sysfs_dir_lock);
@@ -463,7 +506,7 @@ bool blk_get_queue(struct request_queue *q)
 {
        if (unlikely(blk_queue_dying(q)))
                return false;
-       kobject_get(&q->kobj);
+       refcount_inc(&q->refs);
        return true;
 }
 EXPORT_SYMBOL(blk_get_queue);
index a638a2eecfc89d7bb0469f367f6f174644eb571e..e74a918ef9f18bb10d67b4569193e56dd62f35c9 100644 (file)
@@ -140,8 +140,8 @@ int blk_crypto_sysfs_register(struct gendisk *disk)
                return -ENOMEM;
        obj->profile = q->crypto_profile;
 
-       err = kobject_init_and_add(&obj->kobj, &blk_crypto_ktype, &q->kobj,
-                                  "crypto");
+       err = kobject_init_and_add(&obj->kobj, &blk_crypto_ktype,
+                                  &disk->queue_kobj, "crypto");
        if (err) {
                kobject_put(&obj->kobj);
                return err;
index 56ed48d2954e66ce6d51a032cb3993eef3c28d63..6bd0bafe68cc90fe97badee016a1cb6f9a7e0d69 100644 (file)
@@ -136,7 +136,8 @@ int disk_register_independent_access_ranges(struct gendisk *disk,
         */
        WARN_ON(iars->sysfs_registered);
        ret = kobject_init_and_add(&iars->kobj, &blk_ia_ranges_ktype,
-                                  &q->kobj, "%s", "independent_access_ranges");
+                                  &disk->queue_kobj, "%s",
+                                  "independent_access_ranges");
        if (ret) {
                q->ia_ranges = NULL;
                kobject_put(&iars->kobj);
index b7fe2007026140eeee7e1733b212c9f49d41f3b3..c63a6d7085fade6ab695120bdc843042c9bec023 100644 (file)
@@ -673,8 +673,8 @@ static struct attribute *queue_attrs[] = {
 static umode_t queue_attr_visible(struct kobject *kobj, struct attribute *attr,
                                int n)
 {
-       struct request_queue *q =
-               container_of(kobj, struct request_queue, kobj);
+       struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+       struct request_queue *q = disk->queue;
 
        if (attr == &queue_io_timeout_entry.attr &&
                (!q->mq_ops || !q->mq_ops->timeout))
@@ -700,8 +700,8 @@ static ssize_t
 queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
 {
        struct queue_sysfs_entry *entry = to_queue(attr);
-       struct request_queue *q =
-               container_of(kobj, struct request_queue, kobj);
+       struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+       struct request_queue *q = disk->queue;
        ssize_t res;
 
        if (!entry->show)
@@ -717,72 +717,19 @@ queue_attr_store(struct kobject *kobj, struct attribute *attr,
                    const char *page, size_t length)
 {
        struct queue_sysfs_entry *entry = to_queue(attr);
-       struct request_queue *q;
+       struct gendisk *disk = container_of(kobj, struct gendisk, queue_kobj);
+       struct request_queue *q = disk->queue;
        ssize_t res;
 
        if (!entry->store)
                return -EIO;
 
-       q = container_of(kobj, struct request_queue, kobj);
        mutex_lock(&q->sysfs_lock);
        res = entry->store(q, page, length);
        mutex_unlock(&q->sysfs_lock);
        return res;
 }
 
-static void blk_free_queue_rcu(struct rcu_head *rcu_head)
-{
-       struct request_queue *q = container_of(rcu_head, struct request_queue,
-                                              rcu_head);
-
-       kmem_cache_free(blk_get_queue_kmem_cache(blk_queue_has_srcu(q)), q);
-}
-
-/**
- * blk_release_queue - releases all allocated resources of the request_queue
- * @kobj: pointer to a kobject, whose container is a request_queue
- *
- * This function releases all allocated resources of the request queue.
- *
- * The struct request_queue refcount is incremented with blk_get_queue() and
- * decremented with blk_put_queue(). Once the refcount reaches 0 this function
- * is called.
- *
- * Drivers exist which depend on the release of the request_queue to be
- * synchronous, it should not be deferred.
- *
- * Context: can sleep
- */
-static void blk_release_queue(struct kobject *kobj)
-{
-       struct request_queue *q =
-               container_of(kobj, struct request_queue, kobj);
-
-       might_sleep();
-
-       percpu_ref_exit(&q->q_usage_counter);
-
-       if (q->poll_stat)
-               blk_stat_remove_callback(q, q->poll_cb);
-       blk_stat_free_callback(q->poll_cb);
-
-       blk_free_queue_stats(q->stats);
-       kfree(q->poll_stat);
-
-       blk_queue_free_zone_bitmaps(q);
-
-       if (queue_is_mq(q))
-               blk_mq_release(q);
-
-       bioset_exit(&q->bio_split);
-
-       if (blk_queue_has_srcu(q))
-               cleanup_srcu_struct(q->srcu);
-
-       ida_simple_remove(&blk_queue_ida, q->id);
-       call_rcu(&q->rcu_head, blk_free_queue_rcu);
-}
-
 static const struct sysfs_ops queue_sysfs_ops = {
        .show   = queue_attr_show,
        .store  = queue_attr_store,
@@ -793,10 +740,15 @@ static const struct attribute_group *blk_queue_attr_groups[] = {
        NULL
 };
 
-struct kobj_type blk_queue_ktype = {
+static void blk_queue_release(struct kobject *kobj)
+{
+       /* nothing to do here, all data is associated with the parent gendisk */
+}
+
+static struct kobj_type blk_queue_ktype = {
        .default_groups = blk_queue_attr_groups,
        .sysfs_ops      = &queue_sysfs_ops,
-       .release        = blk_release_queue,
+       .release        = blk_queue_release,
 };
 
 /**
@@ -810,7 +762,8 @@ int blk_register_queue(struct gendisk *disk)
 
        mutex_lock(&q->sysfs_dir_lock);
 
-       ret = kobject_add(&q->kobj, &disk_to_dev(disk)->kobj, "queue");
+       kobject_init(&disk->queue_kobj, &blk_queue_ktype);
+       ret = kobject_add(&disk->queue_kobj, &disk_to_dev(disk)->kobj, "queue");
        if (ret < 0)
                goto unlock;
 
@@ -819,8 +772,7 @@ int blk_register_queue(struct gendisk *disk)
        mutex_lock(&q->sysfs_lock);
 
        mutex_lock(&q->debugfs_mutex);
-       q->debugfs_dir = debugfs_create_dir(kobject_name(q->kobj.parent),
-                                           blk_debugfs_root);
+       q->debugfs_dir = debugfs_create_dir(disk->disk_name, blk_debugfs_root);
        if (queue_is_mq(q))
                blk_mq_debugfs_register(q);
        mutex_unlock(&q->debugfs_mutex);
@@ -844,7 +796,7 @@ int blk_register_queue(struct gendisk *disk)
        blk_throtl_register_queue(q);
 
        /* Now everything is ready and send out KOBJ_ADD uevent */
-       kobject_uevent(&q->kobj, KOBJ_ADD);
+       kobject_uevent(&disk->queue_kobj, KOBJ_ADD);
        if (q->elevator)
                kobject_uevent(&q->elevator->kobj, KOBJ_ADD);
        mutex_unlock(&q->sysfs_lock);
@@ -873,7 +825,7 @@ put_dev:
        disk_unregister_independent_access_ranges(disk);
        mutex_unlock(&q->sysfs_lock);
        mutex_unlock(&q->sysfs_dir_lock);
-       kobject_del(&q->kobj);
+       kobject_del(&disk->queue_kobj);
 
        return ret;
 }
@@ -920,8 +872,8 @@ void blk_unregister_queue(struct gendisk *disk)
        mutex_unlock(&q->sysfs_lock);
 
        /* Now that we've deleted all child objects, we can delete the queue. */
-       kobject_uevent(&q->kobj, KOBJ_REMOVE);
-       kobject_del(&q->kobj);
+       kobject_uevent(&disk->queue_kobj, KOBJ_REMOVE);
+       kobject_del(&disk->queue_kobj);
        mutex_unlock(&q->sysfs_dir_lock);
 
        mutex_lock(&q->debugfs_mutex);
index 8c0842a38dd3552189faab820b46ebe92efd99a9..f2fdc68238b64389b0111103f1f1d753d7bf5dad 100644 (file)
@@ -26,11 +26,6 @@ struct blk_flush_queue {
        spinlock_t              mq_flush_lock;
 };
 
-extern struct kmem_cache *blk_requestq_cachep;
-extern struct kmem_cache *blk_requestq_srcu_cachep;
-extern struct kobj_type blk_queue_ktype;
-extern struct ida blk_queue_ida;
-
 bool is_flush_rq(struct request *req);
 
 struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
@@ -413,12 +408,6 @@ int bio_add_hw_page(struct request_queue *q, struct bio *bio,
                struct page *page, unsigned int len, unsigned int offset,
                unsigned int max_sectors, bool *same_page);
 
-static inline struct kmem_cache *blk_get_queue_kmem_cache(bool srcu)
-{
-       if (srcu)
-               return blk_requestq_srcu_cachep;
-       return blk_requestq_cachep;
-}
 struct request_queue *blk_alloc_queue(int node_id, bool alloc_srcu);
 
 int disk_scan_partitions(struct gendisk *disk, fmode_t mode);
index 882f56bff14f830234ee38d1ddfbe6aebf81ce91..ad0fbd7992aca70162d0c01833645b3d641a1763 100644 (file)
@@ -175,8 +175,8 @@ static void bsg_device_release(struct device *dev)
 
 void bsg_unregister_queue(struct bsg_device *bd)
 {
-       if (bd->queue->kobj.sd)
-               sysfs_remove_link(&bd->queue->kobj, "bsg");
+       if (bd->queue->disk)
+               sysfs_remove_link(&bd->queue->disk->queue_kobj, "bsg");
        cdev_device_del(&bd->cdev, &bd->device);
        put_device(&bd->device);
 }
@@ -216,8 +216,9 @@ struct bsg_device *bsg_register_queue(struct request_queue *q,
        if (ret)
                goto out_put_device;
 
-       if (q->kobj.sd) {
-               ret = sysfs_create_link(&q->kobj, &bd->device.kobj, "bsg");
+       if (q->disk) {
+               ret = sysfs_create_link(&q->disk->queue_kobj, &bd->device.kobj,
+                                       "bsg");
                if (ret)
                        goto out_device_del;
        }
index c319765892bb90f00162cb6cac03f8d5434e64b2..d3ca2ec57faf87109b8221dd0dc8161130e89e92 100644 (file)
@@ -499,7 +499,7 @@ int elv_register_queue(struct request_queue *q, bool uevent)
 
        lockdep_assert_held(&q->sysfs_lock);
 
-       error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched");
+       error = kobject_add(&e->kobj, &q->disk->queue_kobj, "iosched");
        if (!error) {
                struct elv_fs_entry *attr = e->type->elevator_attrs;
                if (attr) {
index cfe36c87ac4ca0261ef9b5f81cb651ff04d4e8fa..d299a740d2d6bb7b62dba0326390bd331fa8b0d1 100644 (file)
@@ -154,6 +154,7 @@ struct gendisk {
        unsigned open_partitions;       /* number of open partitions */
 
        struct backing_dev_info *bdi;
+       struct kobject queue_kobj;      /* the queue/ directory */
        struct kobject *slave_dir;
 #ifdef CONFIG_BLOCK_HOLDER_DEPRECATED
        struct list_head slave_bdevs;
@@ -401,10 +402,7 @@ struct request_queue {
 
        struct gendisk          *disk;
 
-       /*
-        * queue kobject
-        */
-       struct kobject kobj;
+       refcount_t              refs;
 
        /*
         * mq queue kobject