|
@@ -29,6 +29,14 @@
|
|
|
|
|
|
#define MAX_KEY_LEN 100
|
|
#define MAX_KEY_LEN 100
|
|
|
|
|
|
|
|
+/*
|
|
|
|
+ * blkcg_pol_mutex protects blkcg_policy[] and policy [de]activation.
|
|
|
|
+ * blkcg_pol_register_mutex nests outside of it and synchronizes entire
|
|
|
|
+ * policy [un]register operations including cgroup file additions /
|
|
|
|
+ * removals. Putting cgroup file registration outside blkcg_pol_mutex
|
|
|
|
+ * allows grabbing it from cgroup callbacks.
|
|
|
|
+ */
|
|
|
|
+static DEFINE_MUTEX(blkcg_pol_register_mutex);
|
|
static DEFINE_MUTEX(blkcg_pol_mutex);
|
|
static DEFINE_MUTEX(blkcg_pol_mutex);
|
|
|
|
|
|
struct blkcg blkcg_root;
|
|
struct blkcg blkcg_root;
|
|
@@ -453,20 +461,7 @@ static int blkcg_reset_stats(struct cgroup_subsys_state *css,
|
|
struct blkcg_gq *blkg;
|
|
struct blkcg_gq *blkg;
|
|
int i;
|
|
int i;
|
|
|
|
|
|
- /*
|
|
|
|
- * XXX: We invoke cgroup_add/rm_cftypes() under blkcg_pol_mutex
|
|
|
|
- * which ends up putting cgroup's internal cgroup_tree_mutex under
|
|
|
|
- * it; however, cgroup_tree_mutex is nested above cgroup file
|
|
|
|
- * active protection and grabbing blkcg_pol_mutex from a cgroup
|
|
|
|
- * file operation creates a possible circular dependency. cgroup
|
|
|
|
- * internal locking is planned to go through further simplification
|
|
|
|
- * and this issue should go away soon. For now, let's trylock
|
|
|
|
- * blkcg_pol_mutex and restart the write on failure.
|
|
|
|
- *
|
|
|
|
- * http://lkml.kernel.org/g/5363C04B.4010400@oracle.com
|
|
|
|
- */
|
|
|
|
- if (!mutex_trylock(&blkcg_pol_mutex))
|
|
|
|
- return restart_syscall();
|
|
|
|
|
|
+ mutex_lock(&blkcg_pol_mutex);
|
|
spin_lock_irq(&blkcg->lock);
|
|
spin_lock_irq(&blkcg->lock);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1190,6 +1185,7 @@ int blkcg_policy_register(struct blkcg_policy *pol)
|
|
if (WARN_ON(pol->pd_size < sizeof(struct blkg_policy_data)))
|
|
if (WARN_ON(pol->pd_size < sizeof(struct blkg_policy_data)))
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
+ mutex_lock(&blkcg_pol_register_mutex);
|
|
mutex_lock(&blkcg_pol_mutex);
|
|
mutex_lock(&blkcg_pol_mutex);
|
|
|
|
|
|
/* find an empty slot */
|
|
/* find an empty slot */
|
|
@@ -1198,19 +1194,23 @@ int blkcg_policy_register(struct blkcg_policy *pol)
|
|
if (!blkcg_policy[i])
|
|
if (!blkcg_policy[i])
|
|
break;
|
|
break;
|
|
if (i >= BLKCG_MAX_POLS)
|
|
if (i >= BLKCG_MAX_POLS)
|
|
- goto out_unlock;
|
|
|
|
|
|
+ goto err_unlock;
|
|
|
|
|
|
/* register and update blkgs */
|
|
/* register and update blkgs */
|
|
pol->plid = i;
|
|
pol->plid = i;
|
|
blkcg_policy[i] = pol;
|
|
blkcg_policy[i] = pol;
|
|
|
|
+ mutex_unlock(&blkcg_pol_mutex);
|
|
|
|
|
|
/* everything is in place, add intf files for the new policy */
|
|
/* everything is in place, add intf files for the new policy */
|
|
if (pol->cftypes)
|
|
if (pol->cftypes)
|
|
WARN_ON(cgroup_add_legacy_cftypes(&blkio_cgrp_subsys,
|
|
WARN_ON(cgroup_add_legacy_cftypes(&blkio_cgrp_subsys,
|
|
pol->cftypes));
|
|
pol->cftypes));
|
|
- ret = 0;
|
|
|
|
-out_unlock:
|
|
|
|
|
|
+ mutex_unlock(&blkcg_pol_register_mutex);
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+err_unlock:
|
|
mutex_unlock(&blkcg_pol_mutex);
|
|
mutex_unlock(&blkcg_pol_mutex);
|
|
|
|
+ mutex_unlock(&blkcg_pol_register_mutex);
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(blkcg_policy_register);
|
|
EXPORT_SYMBOL_GPL(blkcg_policy_register);
|
|
@@ -1223,7 +1223,7 @@ EXPORT_SYMBOL_GPL(blkcg_policy_register);
|
|
*/
|
|
*/
|
|
void blkcg_policy_unregister(struct blkcg_policy *pol)
|
|
void blkcg_policy_unregister(struct blkcg_policy *pol)
|
|
{
|
|
{
|
|
- mutex_lock(&blkcg_pol_mutex);
|
|
|
|
|
|
+ mutex_lock(&blkcg_pol_register_mutex);
|
|
|
|
|
|
if (WARN_ON(blkcg_policy[pol->plid] != pol))
|
|
if (WARN_ON(blkcg_policy[pol->plid] != pol))
|
|
goto out_unlock;
|
|
goto out_unlock;
|
|
@@ -1233,8 +1233,10 @@ void blkcg_policy_unregister(struct blkcg_policy *pol)
|
|
cgroup_rm_cftypes(pol->cftypes);
|
|
cgroup_rm_cftypes(pol->cftypes);
|
|
|
|
|
|
/* unregister and update blkgs */
|
|
/* unregister and update blkgs */
|
|
|
|
+ mutex_lock(&blkcg_pol_mutex);
|
|
blkcg_policy[pol->plid] = NULL;
|
|
blkcg_policy[pol->plid] = NULL;
|
|
-out_unlock:
|
|
|
|
mutex_unlock(&blkcg_pol_mutex);
|
|
mutex_unlock(&blkcg_pol_mutex);
|
|
|
|
+out_unlock:
|
|
|
|
+ mutex_unlock(&blkcg_pol_register_mutex);
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(blkcg_policy_unregister);
|
|
EXPORT_SYMBOL_GPL(blkcg_policy_unregister);
|