diff options
-rw-r--r-- | block/blk-throttle.c | 22 |
1 files changed, 21 insertions, 1 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c index b9412d1cea9e..90ad40735f73 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c | |||
@@ -78,6 +78,8 @@ struct throtl_grp { | |||
78 | 78 | ||
79 | /* Some throttle limits got updated for the group */ | 79 | /* Some throttle limits got updated for the group */ |
80 | int limits_changed; | 80 | int limits_changed; |
81 | |||
82 | struct rcu_head rcu_head; | ||
81 | }; | 83 | }; |
82 | 84 | ||
83 | struct throtl_data | 85 | struct throtl_data |
@@ -151,12 +153,30 @@ static inline struct throtl_grp *throtl_ref_get_tg(struct throtl_grp *tg) | |||
151 | return tg; | 153 | return tg; |
152 | } | 154 | } |
153 | 155 | ||
156 | static void throtl_free_tg(struct rcu_head *head) | ||
157 | { | ||
158 | struct throtl_grp *tg; | ||
159 | |||
160 | tg = container_of(head, struct throtl_grp, rcu_head); | ||
161 | kfree(tg); | ||
162 | } | ||
163 | |||
154 | static void throtl_put_tg(struct throtl_grp *tg) | 164 | static void throtl_put_tg(struct throtl_grp *tg) |
155 | { | 165 | { |
156 | BUG_ON(atomic_read(&tg->ref) <= 0); | 166 | BUG_ON(atomic_read(&tg->ref) <= 0); |
157 | if (!atomic_dec_and_test(&tg->ref)) | 167 | if (!atomic_dec_and_test(&tg->ref)) |
158 | return; | 168 | return; |
159 | kfree(tg); | 169 | |
170 | /* | ||
171 | * A group is freed in rcu manner. But having an rcu lock does not | ||
172 | * mean that one can access all the fields of blkg and assume these | ||
173 | * are valid. For example, don't try to follow throtl_data and | ||
174 | * request queue links. | ||
175 | * | ||
176 | * Having a reference to blkg under an rcu allows acess to only | ||
177 | * values local to groups like group stats and group rate limits | ||
178 | */ | ||
179 | call_rcu(&tg->rcu_head, throtl_free_tg); | ||
160 | } | 180 | } |
161 | 181 | ||
162 | static void throtl_init_group(struct throtl_grp *tg) | 182 | static void throtl_init_group(struct throtl_grp *tg) |