|
@@ -78,6 +78,8 @@ struct throtl_grp {
|
|
|
|
|
|
/* Some throttle limits got updated for the group */
|
|
|
int limits_changed;
|
|
|
+
|
|
|
+ struct rcu_head rcu_head;
|
|
|
};
|
|
|
|
|
|
struct throtl_data
|
|
@@ -151,12 +153,30 @@ static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg)
|
|
|
return tg;
|
|
|
}
|
|
|
|
|
|
+static void throtl_free_tg(struct rcu_head *head)
|
|
|
+{
|
|
|
+ struct throtl_grp *tg;
|
|
|
+
|
|
|
+ tg = container_of(head, struct throtl_grp, rcu_head);
|
|
|
+ kfree(tg);
|
|
|
+}
|
|
|
+
|
|
|
static void throtl_put_tg(struct throtl_grp *tg)
|
|
|
{
|
|
|
BUG_ON(atomic_read(&tg->ref) <= 0);
|
|
|
if (!atomic_dec_and_test(&tg->ref))
|
|
|
return;
|
|
|
- kfree(tg);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * A group is freed in rcu manner. But having an rcu lock does not
|
|
|
+ * mean that one can access all the fields of blkg and assume these
|
|
|
+ * are valid. For example, don't try to follow throtl_data and
|
|
|
+ * request queue links.
|
|
|
+ *
|
|
|
+ * Having a reference to blkg under an rcu allows acess to only
|
|
|
+ * values local to groups like group stats and group rate limits
|
|
|
+ */
|
|
|
+ call_rcu(&tg->rcu_head, throtl_free_tg);
|
|
|
}
|
|
|
|
|
|
static void throtl_init_group(struct throtl_grp *tg)
|