diff options
Diffstat (limited to 'block/blk-cgroup.c')
-rw-r--r-- | block/blk-cgroup.c | 40 |
1 files changed, 21 insertions, 19 deletions
diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 5e2723f2c6a3..2ff74ffcbb27 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c | |||
@@ -29,6 +29,14 @@ | |||
29 | 29 | ||
30 | #define MAX_KEY_LEN 100 | 30 | #define MAX_KEY_LEN 100 |
31 | 31 | ||
32 | /* | ||
33 | * blkcg_pol_mutex protects blkcg_policy[] and policy [de]activation. | ||
34 | * blkcg_pol_register_mutex nests outside of it and synchronizes entire | ||
35 | * policy [un]register operations including cgroup file additions / | ||
36 | * removals. Putting cgroup file registration outside blkcg_pol_mutex | ||
37 | * allows grabbing it from cgroup callbacks. | ||
38 | */ | ||
39 | static DEFINE_MUTEX(blkcg_pol_register_mutex); | ||
32 | static DEFINE_MUTEX(blkcg_pol_mutex); | 40 | static DEFINE_MUTEX(blkcg_pol_mutex); |
33 | 41 | ||
34 | struct blkcg blkcg_root; | 42 | struct blkcg blkcg_root; |
@@ -453,20 +461,7 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css, | |||
453 | struct blkcg_gq *blkg; | 461 | struct blkcg_gq *blkg; |
454 | int i; | 462 | int i; |
455 | 463 | ||
456 | /* | 464 | mutex_lock(&blkcg_pol_mutex); |
457 | * XXX: We invoke cgroup_add/rm_cftypes() under blkcg_pol_mutex | ||
458 | * which ends up putting cgroup's internal cgroup_tree_mutex under | ||
459 | * it; however, cgroup_tree_mutex is nested above cgroup file | ||
460 | * active protection and grabbing blkcg_pol_mutex from a cgroup | ||
461 | * file operation creates a possible circular dependency. cgroup | ||
462 | * internal locking is planned to go through further simplification | ||
463 | * and this issue should go away soon. For now, let's trylock | ||
464 | * blkcg_pol_mutex and restart the write on failure. | ||
465 | * | ||
466 | * http://lkml.kernel.org/g/5363C04B.4010400@oracle.com | ||
467 | */ | ||
468 | if (!mutex_trylock(&blkcg_pol_mutex)) | ||
469 | return restart_syscall(); | ||
470 | spin_lock_irq(&blkcg->lock); | 465 | spin_lock_irq(&blkcg->lock); |
471 | 466 | ||
472 | /* | 467 | /* |
@@ -1190,6 +1185,7 @@ int blkcg_policy_register(struct blkcg_policy *pol) | |||
1190 | if (WARN_ON(pol->pd_size < sizeof(struct blkg_policy_data))) | 1185 | if (WARN_ON(pol->pd_size < sizeof(struct blkg_policy_data))) |
1191 | return -EINVAL; | 1186 | return -EINVAL; |
1192 | 1187 | ||
1188 | mutex_lock(&blkcg_pol_register_mutex); | ||
1193 | mutex_lock(&blkcg_pol_mutex); | 1189 | mutex_lock(&blkcg_pol_mutex); |
1194 | 1190 | ||
1195 | /* find an empty slot */ | 1191 | /* find an empty slot */ |
@@ -1198,19 +1194,23 @@ int blkcg_policy_register(struct blkcg_policy *pol) | |||
1198 | if (!blkcg_policy[i]) | 1194 | if (!blkcg_policy[i]) |
1199 | break; | 1195 | break; |
1200 | if (i >= BLKCG_MAX_POLS) | 1196 | if (i >= BLKCG_MAX_POLS) |
1201 | goto out_unlock; | 1197 | goto err_unlock; |
1202 | 1198 | ||
1203 | /* register and update blkgs */ | 1199 | /* register and update blkgs */ |
1204 | pol->plid = i; | 1200 | pol->plid = i; |
1205 | blkcg_policy[i] = pol; | 1201 | blkcg_policy[i] = pol; |
1202 | mutex_unlock(&blkcg_pol_mutex); | ||
1206 | 1203 | ||
1207 | /* everything is in place, add intf files for the new policy */ | 1204 | /* everything is in place, add intf files for the new policy */ |
1208 | if (pol->cftypes) | 1205 | if (pol->cftypes) |
1209 | WARN_ON(cgroup_add_legacy_cftypes(&blkio_cgrp_subsys, | 1206 | WARN_ON(cgroup_add_legacy_cftypes(&blkio_cgrp_subsys, |
1210 | pol->cftypes)); | 1207 | pol->cftypes)); |
1211 | ret = 0; | 1208 | mutex_unlock(&blkcg_pol_register_mutex); |
1212 | out_unlock: | 1209 | return 0; |
1210 | |||
1211 | err_unlock: | ||
1213 | mutex_unlock(&blkcg_pol_mutex); | 1212 | mutex_unlock(&blkcg_pol_mutex); |
1213 | mutex_unlock(&blkcg_pol_register_mutex); | ||
1214 | return ret; | 1214 | return ret; |
1215 | } | 1215 | } |
1216 | EXPORT_SYMBOL_GPL(blkcg_policy_register); | 1216 | EXPORT_SYMBOL_GPL(blkcg_policy_register); |
@@ -1223,7 +1223,7 @@ EXPORT_SYMBOL_GPL(blkcg_policy_register); | |||
1223 | */ | 1223 | */ |
1224 | void blkcg_policy_unregister(struct blkcg_policy *pol) | 1224 | void blkcg_policy_unregister(struct blkcg_policy *pol) |
1225 | { | 1225 | { |
1226 | mutex_lock(&blkcg_pol_mutex); | 1226 | mutex_lock(&blkcg_pol_register_mutex); |
1227 | 1227 | ||
1228 | if (WARN_ON(blkcg_policy[pol->plid] != pol)) | 1228 | if (WARN_ON(blkcg_policy[pol->plid] != pol)) |
1229 | goto out_unlock; | 1229 | goto out_unlock; |
@@ -1233,8 +1233,10 @@ void blkcg_policy_unregister(struct blkcg_policy *pol) | |||
1233 | cgroup_rm_cftypes(pol->cftypes); | 1233 | cgroup_rm_cftypes(pol->cftypes); |
1234 | 1234 | ||
1235 | /* unregister and update blkgs */ | 1235 | /* unregister and update blkgs */ |
1236 | mutex_lock(&blkcg_pol_mutex); | ||
1236 | blkcg_policy[pol->plid] = NULL; | 1237 | blkcg_policy[pol->plid] = NULL; |
1237 | out_unlock: | ||
1238 | mutex_unlock(&blkcg_pol_mutex); | 1238 | mutex_unlock(&blkcg_pol_mutex); |
1239 | out_unlock: | ||
1240 | mutex_unlock(&blkcg_pol_register_mutex); | ||
1239 | } | 1241 | } |
1240 | EXPORT_SYMBOL_GPL(blkcg_policy_unregister); | 1242 | EXPORT_SYMBOL_GPL(blkcg_policy_unregister); |