[PATCH -next 2/4] block/rq_qos: factor out a helper to add rq_qos and activate policy

From: Yu Kuai
Date: Wed Jan 04 2023 - 03:29:39 EST


From: Yu Kuai <yukuai3@xxxxxxxxxx>

For the policy that use both rq_qos and blkcg_policy, rq_qos_add() and
blkcg_activate_policy() should be atomic, otherwise null-ptr-deference
can be triggered. This patch prepare to use a global mutex to protect
them, there are no functional changes.

Signed-off-by: Yu Kuai <yukuai3@xxxxxxxxxx>
---
block/blk-iocost.c | 14 +-------------
block/blk-iolatency.c | 7 +------
block/blk-rq-qos.c | 23 +++++++++++++++++++++++
block/blk-rq-qos.h | 6 ++++++
4 files changed, 31 insertions(+), 19 deletions(-)

diff --git a/block/blk-iocost.c b/block/blk-iocost.c
index 6955605629e4..9199124f0cc2 100644
--- a/block/blk-iocost.c
+++ b/block/blk-iocost.c
@@ -2883,23 +2883,11 @@ static int blk_iocost_init(struct gendisk *disk)
ioc_refresh_params(ioc, true);
spin_unlock_irq(&ioc->lock);

- /*
- * rqos must be added before activation to allow ioc_pd_init() to
- * lookup the ioc from q. This means that the rqos methods may get
- * called before policy activation completion, can't assume that the
- * target bio has an iocg associated and need to test for NULL iocg.
- */
- ret = rq_qos_add(q, rqos);
+ ret = rq_qos_add_and_activate_policy(q, rqos, &blkcg_policy_iocost);
if (ret)
goto err_free_ioc;
-
- ret = blkcg_activate_policy(q, &blkcg_policy_iocost);
- if (ret)
- goto err_del_qos;
return 0;

-err_del_qos:
- rq_qos_del(q, rqos);
err_free_ioc:
free_percpu(ioc->pcpu_stat);
kfree(ioc);
diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c
index ecdc10741836..a29b923e2a6a 100644
--- a/block/blk-iolatency.c
+++ b/block/blk-iolatency.c
@@ -771,20 +771,15 @@ int blk_iolatency_init(struct gendisk *disk)
rqos->ops = &blkcg_iolatency_ops;
rqos->q = q;

- ret = rq_qos_add(q, rqos);
+ ret = rq_qos_add_and_activate_policy(q, rqos, &blkcg_policy_iolatency);
if (ret)
goto err_free;
- ret = blkcg_activate_policy(q, &blkcg_policy_iolatency);
- if (ret)
- goto err_qos_del;

timer_setup(&blkiolat->timer, blkiolatency_timer_fn, 0);
INIT_WORK(&blkiolat->enable_work, blkiolatency_enable_work_fn);

return 0;

-err_qos_del:
- rq_qos_del(q, rqos);
err_free:
kfree(blkiolat);
return ret;
diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c
index b6ea40775b2a..50544bfb12f1 100644
--- a/block/blk-rq-qos.c
+++ b/block/blk-rq-qos.c
@@ -353,3 +353,26 @@ void rq_qos_exit(struct request_queue *q)
rqos->ops->exit(rqos);
}
}
+
+#ifdef CONFIG_BLK_CGROUP
+int rq_qos_add_and_activate_policy(struct request_queue *q, struct rq_qos *rqos,
+ const struct blkcg_policy *pol)
+{
+ /*
+ * rqos must be added before activation to allow pd_init_fn() to
+ * lookup the global structure from q. This means that the rqos methods
+ * may get called before policy activation completion, can't assume that
+ * the target bio has an pd associated and need to test for NULL.
+ */
+ int ret = rq_qos_add(q, rqos);
+
+ if (ret)
+ return ret;
+
+ ret = blkcg_activate_policy(q, pol);
+ if (ret)
+ rq_qos_del(q, rqos);
+
+ return ret;
+}
+#endif
diff --git a/block/blk-rq-qos.h b/block/blk-rq-qos.h
index f2d95e19d7a8..0778cff3777c 100644
--- a/block/blk-rq-qos.h
+++ b/block/blk-rq-qos.h
@@ -173,4 +173,10 @@ static inline void rq_qos_queue_depth_changed(struct request_queue *q)
__rq_qos_queue_depth_changed(q->rq_qos);
}

+#ifdef CONFIG_BLK_CGROUP
+#include "blk-cgroup.h"
+int rq_qos_add_and_activate_policy(struct request_queue *q, struct rq_qos *rqos,
+ const struct blkcg_policy *pol);
+#endif
+
#endif
--
2.31.1