diff options
-rw-r--r-- | block/blk-cgroup.c | 78 | ||||
-rw-r--r-- | include/linux/blk-cgroup.h | 1 |
2 files changed, 16 insertions, 63 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 694595b29b8f..2998e4f095d1 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -310,28 +310,11 @@ struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg, | |||
310 | } | 310 | } |
311 | } | 311 | } |
312 | 312 | ||
313 | static void blkg_pd_offline(struct blkcg_gq *blkg) | ||
314 | { | ||
315 | int i; | ||
316 | |||
317 | lockdep_assert_held(blkg->q->queue_lock); | ||
318 | lockdep_assert_held(&blkg->blkcg->lock); | ||
319 | |||
320 | for (i = 0; i < BLKCG_MAX_POLS; i++) { | ||
321 | struct blkcg_policy *pol = blkcg_policy[i]; | ||
322 | |||
323 | if (blkg->pd[i] && !blkg->pd[i]->offline && | ||
324 | pol->pd_offline_fn) { | ||
325 | pol->pd_offline_fn(blkg->pd[i]); | ||
326 | blkg->pd[i]->offline = true; | ||
327 | } | ||
328 | } | ||
329 | } | ||
330 | |||
331 | static void blkg_destroy(struct blkcg_gq *blkg) | 313 | static void blkg_destroy(struct blkcg_gq *blkg) |
332 | { | 314 | { |
333 | struct blkcg *blkcg = blkg->blkcg; | 315 | struct blkcg *blkcg = blkg->blkcg; |
334 | struct blkcg_gq *parent = blkg->parent; | 316 | struct blkcg_gq *parent = blkg->parent; |
317 | int i; | ||
335 | 318 | ||
336 | lockdep_assert_held(blkg->q->queue_lock); | 319 | lockdep_assert_held(blkg->q->queue_lock); |
337 | lockdep_assert_held(&blkcg->lock); | 320 | lockdep_assert_held(&blkcg->lock); |
@@ -340,6 +323,13 @@ static void blkg_destroy(struct blkcg_gq *blkg) | |||
340 | WARN_ON_ONCE(list_empty(&blkg->q_node)); | 323 | WARN_ON_ONCE(list_empty(&blkg->q_node)); |
341 | WARN_ON_ONCE(hlist_unhashed(&blkg->blkcg_node)); | 324 | WARN_ON_ONCE(hlist_unhashed(&blkg->blkcg_node)); |
342 | 325 | ||
326 | for (i = 0; i < BLKCG_MAX_POLS; i++) { | ||
327 | struct blkcg_policy *pol = blkcg_policy[i]; | ||
328 | |||
329 | if (blkg->pd[i] && pol->pd_offline_fn) | ||
330 | pol->pd_offline_fn(blkg->pd[i]); | ||
331 | } | ||
332 | |||
343 | if (parent) { | 333 | if (parent) { |
344 | blkg_rwstat_add_aux(&parent->stat_bytes, &blkg->stat_bytes); | 334 | blkg_rwstat_add_aux(&parent->stat_bytes, &blkg->stat_bytes); |
345 | blkg_rwstat_add_aux(&parent->stat_ios, &blkg->stat_ios); | 335 | blkg_rwstat_add_aux(&parent->stat_ios, &blkg->stat_ios); |
@@ -382,7 +372,6 @@ static void blkg_destroy_all(struct request_queue *q) | |||
382 | struct blkcg *blkcg = blkg->blkcg; | 372 | struct blkcg *blkcg = blkg->blkcg; |
383 | 373 | ||
384 | spin_lock(&blkcg->lock); | 374 | spin_lock(&blkcg->lock); |
385 | blkg_pd_offline(blkg); | ||
386 | blkg_destroy(blkg); | 375 | blkg_destroy(blkg); |
387 | spin_unlock(&blkcg->lock); | 376 | spin_unlock(&blkcg->lock); |
388 | } | 377 | } |
@@ -1058,54 +1047,21 @@ static struct cftype blkcg_legacy_files[] = { | |||
1058 | * @css: css of interest | 1047 | * @css: css of interest |
1059 | * | 1048 | * |
1060 | * This function is called when @css is about to go away and responsible | 1049 | * This function is called when @css is about to go away and responsible |
1061 | * for offlining all blkgs pd and killing all wbs associated with @css. | 1050 | * for shooting down all blkgs associated with @css. blkgs should be |
1062 | * blkgs pd offline should be done while holding both q and blkcg locks. | 1051 | * removed while holding both q and blkcg locks. As blkcg lock is nested |
1063 | * As blkcg lock is nested inside q lock, this function performs reverse | 1052 | * inside q lock, this function performs reverse double lock dancing. |
1064 | * double lock dancing. | ||
1065 | * | 1053 | * |
1066 | * This is the blkcg counterpart of ioc_release_fn(). | 1054 | * This is the blkcg counterpart of ioc_release_fn(). |
1067 | */ | 1055 | */ |
1068 | static void blkcg_css_offline(struct cgroup_subsys_state *css) | 1056 | static void blkcg_css_offline(struct cgroup_subsys_state *css) |
1069 | { | 1057 | { |
1070 | struct blkcg *blkcg = css_to_blkcg(css); | 1058 | struct blkcg *blkcg = css_to_blkcg(css); |
1071 | struct blkcg_gq *blkg; | ||
1072 | 1059 | ||
1073 | spin_lock_irq(&blkcg->lock); | 1060 | spin_lock_irq(&blkcg->lock); |
1074 | 1061 | ||
1075 | hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) { | ||
1076 | struct request_queue *q = blkg->q; | ||
1077 | |||
1078 | if (spin_trylock(q->queue_lock)) { | ||
1079 | blkg_pd_offline(blkg); | ||
1080 | spin_unlock(q->queue_lock); | ||
1081 | } else { | ||
1082 | spin_unlock_irq(&blkcg->lock); | ||
1083 | cpu_relax(); | ||
1084 | spin_lock_irq(&blkcg->lock); | ||
1085 | } | ||
1086 | } | ||
1087 | |||
1088 | spin_unlock_irq(&blkcg->lock); | ||
1089 | |||
1090 | wb_blkcg_offline(blkcg); | ||
1091 | } | ||
1092 | |||
1093 | /** | ||
1094 | * blkcg_destroy_all_blkgs - destroy all blkgs associated with a blkcg | ||
1095 | * @blkcg: blkcg of interest | ||
1096 | * | ||
1097 | * This function is called when blkcg css is about to free and responsible for | ||
1098 | * destroying all blkgs associated with @blkcg. | ||
1099 | * blkgs should be removed while holding both q and blkcg locks. As blkcg lock | ||
1100 | * is nested inside q lock, this function performs reverse double lock dancing. | ||
1101 | */ | ||
1102 | static void blkcg_destroy_all_blkgs(struct blkcg *blkcg) | ||
1103 | { | ||
1104 | spin_lock_irq(&blkcg->lock); | ||
1105 | while (!hlist_empty(&blkcg->blkg_list)) { | 1062 | while (!hlist_empty(&blkcg->blkg_list)) { |
1106 | struct blkcg_gq *blkg = hlist_entry(blkcg->blkg_list.first, | 1063 | struct blkcg_gq *blkg = hlist_entry(blkcg->blkg_list.first, |
1107 | struct blkcg_gq, | 1064 | struct blkcg_gq, blkcg_node); |
1108 | blkcg_node); | ||
1109 | struct request_queue *q = blkg->q; | 1065 | struct request_queue *q = blkg->q; |
1110 | 1066 | ||
1111 | if (spin_trylock(q->queue_lock)) { | 1067 | if (spin_trylock(q->queue_lock)) { |
@@ -1117,7 +1073,10 @@ static void blkcg_destroy_all_blkgs(struct blkcg *blkcg) | |||
1117 | spin_lock_irq(&blkcg->lock); | 1073 | spin_lock_irq(&blkcg->lock); |
1118 | } | 1074 | } |
1119 | } | 1075 | } |
1076 | |||
1120 | spin_unlock_irq(&blkcg->lock); | 1077 | spin_unlock_irq(&blkcg->lock); |
1078 | |||
1079 | wb_blkcg_offline(blkcg); | ||
1121 | } | 1080 | } |
1122 | 1081 | ||
1123 | static void blkcg_css_free(struct cgroup_subsys_state *css) | 1082 | static void blkcg_css_free(struct cgroup_subsys_state *css) |
@@ -1125,8 +1084,6 @@ static void blkcg_css_free(struct cgroup_subsys_state *css) | |||
1125 | struct blkcg *blkcg = css_to_blkcg(css); | 1084 | struct blkcg *blkcg = css_to_blkcg(css); |
1126 | int i; | 1085 | int i; |
1127 | 1086 | ||
1128 | blkcg_destroy_all_blkgs(blkcg); | ||
1129 | |||
1130 | mutex_lock(&blkcg_pol_mutex); | 1087 | mutex_lock(&blkcg_pol_mutex); |
1131 | 1088 | ||
1132 | list_del(&blkcg->all_blkcgs_node); | 1089 | list_del(&blkcg->all_blkcgs_node); |
@@ -1480,11 +1437,8 @@ void blkcg_deactivate_policy(struct request_queue *q, | |||
1480 | 1437 | ||
1481 | list_for_each_entry(blkg, &q->blkg_list, q_node) { | 1438 | list_for_each_entry(blkg, &q->blkg_list, q_node) { |
1482 | if (blkg->pd[pol->plid]) { | 1439 | if (blkg->pd[pol->plid]) { |
1483 | if (!blkg->pd[pol->plid]->offline && | 1440 | if (pol->pd_offline_fn) |
1484 | pol->pd_offline_fn) { | ||
1485 | pol->pd_offline_fn(blkg->pd[pol->plid]); | 1441 | pol->pd_offline_fn(blkg->pd[pol->plid]); |
1486 | blkg->pd[pol->plid]->offline = true; | ||
1487 | } | ||
1488 | pol->pd_free_fn(blkg->pd[pol->plid]); | 1442 | pol->pd_free_fn(blkg->pd[pol->plid]); |
1489 | blkg->pd[pol->plid] = NULL; | 1443 | blkg->pd[pol->plid] = NULL; |
1490 | } | 1444 | } |
diff --git a/include/linux/blk-cgroup.h b/include/linux/blk-cgroup.h index 34aec30e06c7..1615cdd4c797 100644 --- a/include/linux/blk-cgroup.h +++ b/include/linux/blk-cgroup.h | |||
@@ -89,7 +89,6 @@ struct blkg_policy_data { | |||
89 | /* the blkg and policy id this per-policy data belongs to */ | 89 | /* the blkg and policy id this per-policy data belongs to */ |
90 | struct blkcg_gq *blkg; | 90 | struct blkcg_gq *blkg; |
91 | int plid; | 91 | int plid; |
92 | bool offline; | ||
93 | }; | 92 | }; |
94 | 93 | ||
95 | /* | 94 | /* |