diff options
author | Tejun Heo <tj@kernel.org> | 2013-04-14 14:36:56 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2013-05-14 14:42:05 -0400 |
commit | fa3ca07e96185aa1496b405472399a2a2a336a17 (patch) | |
tree | 5cd4a902d628f5ce9ee2b0b91d0f435948da4a57 /kernel/cgroup.c | |
parent | f722406faae2d073cc1d01063d1123c35425939e (diff) |
cgroup: refactor hierarchy_id handling
We're planning to converting hierarchy_ida to an idr and use it to
look up hierarchy from its id. As we want the mapping to happen
atomically with cgroupfs_root registration, this patch refactors
hierarchy_id init / exit so that ida operations happen inside
cgroup_[root_]mutex.
* s/init_root_id()/cgroup_init_root_id()/ and make it return 0 or
-errno like a normal function.
* Move hierarchy_id initialization from cgroup_root_from_opts() into
cgroup_mount() block where the root is confirmed to be used and
being registered while holding both mutexes.
* Split cgroup_drop_id() into cgroup_exit_root_id() and
cgroup_free_root(), so that ID release can happen before dropping
the mutexes in cgroup_kill_sb(). The latter expects hierarchy_id to
be exited before being invoked.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 2a9926275f80..dbc84f7d23b8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -1426,13 +1426,13 @@ static void init_cgroup_root(struct cgroupfs_root *root) | |||
1426 | list_add_tail(&cgrp->allcg_node, &root->allcg_list); | 1426 | list_add_tail(&cgrp->allcg_node, &root->allcg_list); |
1427 | } | 1427 | } |
1428 | 1428 | ||
1429 | static bool init_root_id(struct cgroupfs_root *root) | 1429 | static int cgroup_init_root_id(struct cgroupfs_root *root) |
1430 | { | 1430 | { |
1431 | int ret = 0; | 1431 | int ret; |
1432 | 1432 | ||
1433 | do { | 1433 | do { |
1434 | if (!ida_pre_get(&hierarchy_ida, GFP_KERNEL)) | 1434 | if (!ida_pre_get(&hierarchy_ida, GFP_KERNEL)) |
1435 | return false; | 1435 | return -ENOMEM; |
1436 | spin_lock(&hierarchy_id_lock); | 1436 | spin_lock(&hierarchy_id_lock); |
1437 | /* Try to allocate the next unused ID */ | 1437 | /* Try to allocate the next unused ID */ |
1438 | ret = ida_get_new_above(&hierarchy_ida, next_hierarchy_id, | 1438 | ret = ida_get_new_above(&hierarchy_ida, next_hierarchy_id, |
@@ -1448,7 +1448,18 @@ static bool init_root_id(struct cgroupfs_root *root) | |||
1448 | } | 1448 | } |
1449 | spin_unlock(&hierarchy_id_lock); | 1449 | spin_unlock(&hierarchy_id_lock); |
1450 | } while (ret); | 1450 | } while (ret); |
1451 | return true; | 1451 | return 0; |
1452 | } | ||
1453 | |||
1454 | static void cgroup_exit_root_id(struct cgroupfs_root *root) | ||
1455 | { | ||
1456 | if (root->hierarchy_id) { | ||
1457 | spin_lock(&hierarchy_id_lock); | ||
1458 | ida_remove(&hierarchy_ida, root->hierarchy_id); | ||
1459 | spin_unlock(&hierarchy_id_lock); | ||
1460 | |||
1461 | root->hierarchy_id = 0; | ||
1462 | } | ||
1452 | } | 1463 | } |
1453 | 1464 | ||
1454 | static int cgroup_test_super(struct super_block *sb, void *data) | 1465 | static int cgroup_test_super(struct super_block *sb, void *data) |
@@ -1482,10 +1493,6 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts) | |||
1482 | if (!root) | 1493 | if (!root) |
1483 | return ERR_PTR(-ENOMEM); | 1494 | return ERR_PTR(-ENOMEM); |
1484 | 1495 | ||
1485 | if (!init_root_id(root)) { | ||
1486 | kfree(root); | ||
1487 | return ERR_PTR(-ENOMEM); | ||
1488 | } | ||
1489 | init_cgroup_root(root); | 1496 | init_cgroup_root(root); |
1490 | 1497 | ||
1491 | root->subsys_mask = opts->subsys_mask; | 1498 | root->subsys_mask = opts->subsys_mask; |
@@ -1500,17 +1507,15 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts) | |||
1500 | return root; | 1507 | return root; |
1501 | } | 1508 | } |
1502 | 1509 | ||
1503 | static void cgroup_drop_root(struct cgroupfs_root *root) | 1510 | static void cgroup_free_root(struct cgroupfs_root *root) |
1504 | { | 1511 | { |
1505 | if (!root) | 1512 | if (root) { |
1506 | return; | 1513 | /* hierarhcy ID shoulid already have been released */ |
1514 | WARN_ON_ONCE(root->hierarchy_id); | ||
1507 | 1515 | ||
1508 | BUG_ON(!root->hierarchy_id); | 1516 | ida_destroy(&root->cgroup_ida); |
1509 | spin_lock(&hierarchy_id_lock); | 1517 | kfree(root); |
1510 | ida_remove(&hierarchy_ida, root->hierarchy_id); | 1518 | } |
1511 | spin_unlock(&hierarchy_id_lock); | ||
1512 | ida_destroy(&root->cgroup_ida); | ||
1513 | kfree(root); | ||
1514 | } | 1519 | } |
1515 | 1520 | ||
1516 | static int cgroup_set_super(struct super_block *sb, void *data) | 1521 | static int cgroup_set_super(struct super_block *sb, void *data) |
@@ -1597,7 +1602,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1597 | sb = sget(fs_type, cgroup_test_super, cgroup_set_super, 0, &opts); | 1602 | sb = sget(fs_type, cgroup_test_super, cgroup_set_super, 0, &opts); |
1598 | if (IS_ERR(sb)) { | 1603 | if (IS_ERR(sb)) { |
1599 | ret = PTR_ERR(sb); | 1604 | ret = PTR_ERR(sb); |
1600 | cgroup_drop_root(opts.new_root); | 1605 | cgroup_free_root(opts.new_root); |
1601 | goto drop_modules; | 1606 | goto drop_modules; |
1602 | } | 1607 | } |
1603 | 1608 | ||
@@ -1641,6 +1646,10 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1641 | if (ret) | 1646 | if (ret) |
1642 | goto unlock_drop; | 1647 | goto unlock_drop; |
1643 | 1648 | ||
1649 | ret = cgroup_init_root_id(root); | ||
1650 | if (ret) | ||
1651 | goto unlock_drop; | ||
1652 | |||
1644 | ret = rebind_subsystems(root, root->subsys_mask); | 1653 | ret = rebind_subsystems(root, root->subsys_mask); |
1645 | if (ret == -EBUSY) { | 1654 | if (ret == -EBUSY) { |
1646 | free_cg_links(&tmp_cg_links); | 1655 | free_cg_links(&tmp_cg_links); |
@@ -1684,7 +1693,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1684 | * We re-used an existing hierarchy - the new root (if | 1693 | * We re-used an existing hierarchy - the new root (if |
1685 | * any) is not needed | 1694 | * any) is not needed |
1686 | */ | 1695 | */ |
1687 | cgroup_drop_root(opts.new_root); | 1696 | cgroup_free_root(opts.new_root); |
1688 | 1697 | ||
1689 | if (((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) && | 1698 | if (((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) && |
1690 | root->flags != opts.flags) { | 1699 | root->flags != opts.flags) { |
@@ -1702,6 +1711,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type, | |||
1702 | return dget(sb->s_root); | 1711 | return dget(sb->s_root); |
1703 | 1712 | ||
1704 | unlock_drop: | 1713 | unlock_drop: |
1714 | cgroup_exit_root_id(root); | ||
1705 | mutex_unlock(&cgroup_root_mutex); | 1715 | mutex_unlock(&cgroup_root_mutex); |
1706 | mutex_unlock(&cgroup_mutex); | 1716 | mutex_unlock(&cgroup_mutex); |
1707 | mutex_unlock(&inode->i_mutex); | 1717 | mutex_unlock(&inode->i_mutex); |
@@ -1754,13 +1764,15 @@ static void cgroup_kill_sb(struct super_block *sb) { | |||
1754 | root_count--; | 1764 | root_count--; |
1755 | } | 1765 | } |
1756 | 1766 | ||
1767 | cgroup_exit_root_id(root); | ||
1768 | |||
1757 | mutex_unlock(&cgroup_root_mutex); | 1769 | mutex_unlock(&cgroup_root_mutex); |
1758 | mutex_unlock(&cgroup_mutex); | 1770 | mutex_unlock(&cgroup_mutex); |
1759 | 1771 | ||
1760 | simple_xattrs_free(&cgrp->xattrs); | 1772 | simple_xattrs_free(&cgrp->xattrs); |
1761 | 1773 | ||
1762 | kill_litter_super(sb); | 1774 | kill_litter_super(sb); |
1763 | cgroup_drop_root(root); | 1775 | cgroup_free_root(root); |
1764 | } | 1776 | } |
1765 | 1777 | ||
1766 | static struct file_system_type cgroup_fs_type = { | 1778 | static struct file_system_type cgroup_fs_type = { |
@@ -4642,7 +4654,9 @@ int __init cgroup_init(void) | |||
4642 | /* Add init_css_set to the hash table */ | 4654 | /* Add init_css_set to the hash table */ |
4643 | key = css_set_hash(init_css_set.subsys); | 4655 | key = css_set_hash(init_css_set.subsys); |
4644 | hash_add(css_set_table, &init_css_set.hlist, key); | 4656 | hash_add(css_set_table, &init_css_set.hlist, key); |
4645 | BUG_ON(!init_root_id(&rootnode)); | 4657 | |
4658 | /* allocate id for the dummy hierarchy */ | ||
4659 | BUG_ON(cgroup_init_root_id(&rootnode)); | ||
4646 | 4660 | ||
4647 | cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); | 4661 | cgroup_kobj = kobject_create_and_add("cgroup", fs_kobj); |
4648 | if (!cgroup_kobj) { | 4662 | if (!cgroup_kobj) { |