summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--block/blk-cgroup.c78
-rw-r--r--include/linux/blk-cgroup.h1
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
313static 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
331static void blkg_destroy(struct blkcg_gq *blkg) 313static 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 */
1068static void blkcg_css_offline(struct cgroup_subsys_state *css) 1056static 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 */
1102static 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
1123static void blkcg_css_free(struct cgroup_subsys_state *css) 1082static 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/*