diff options
-rw-r--r-- | include/linux/cgroup.h | 1 | ||||
-rw-r--r-- | kernel/cgroup.c | 240 |
2 files changed, 182 insertions, 59 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index 3a1cb265afd6..4829a577c1b9 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h | |||
@@ -350,6 +350,7 @@ struct css_set { | |||
350 | * List of csets participating in the on-going migration either as | 350 | * List of csets participating in the on-going migration either as |
351 | * source or destination. Protected by cgroup_mutex. | 351 | * source or destination. Protected by cgroup_mutex. |
352 | */ | 352 | */ |
353 | struct list_head mg_preload_node; | ||
353 | struct list_head mg_node; | 354 | struct list_head mg_node; |
354 | 355 | ||
355 | /* | 356 | /* |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 23e3a8c74bd4..a93f6f1ebc69 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -644,6 +644,7 @@ static struct css_set *find_css_set(struct css_set *old_cset, | |||
644 | INIT_LIST_HEAD(&cset->cgrp_links); | 644 | INIT_LIST_HEAD(&cset->cgrp_links); |
645 | INIT_LIST_HEAD(&cset->tasks); | 645 | INIT_LIST_HEAD(&cset->tasks); |
646 | INIT_LIST_HEAD(&cset->mg_tasks); | 646 | INIT_LIST_HEAD(&cset->mg_tasks); |
647 | INIT_LIST_HEAD(&cset->mg_preload_node); | ||
647 | INIT_LIST_HEAD(&cset->mg_node); | 648 | INIT_LIST_HEAD(&cset->mg_node); |
648 | INIT_HLIST_NODE(&cset->hlist); | 649 | INIT_HLIST_NODE(&cset->hlist); |
649 | 650 | ||
@@ -1755,16 +1756,137 @@ static void cgroup_task_migrate(struct cgroup *old_cgrp, | |||
1755 | } | 1756 | } |
1756 | 1757 | ||
1757 | /** | 1758 | /** |
1758 | * cgroup_attach_task - attach a task or a whole threadgroup to a cgroup | 1759 | * cgroup_migrate_finish - cleanup after attach |
1759 | * @cgrp: the cgroup to attach to | 1760 | * @preloaded_csets: list of preloaded css_sets |
1760 | * @leader: the task or the leader of the threadgroup to be attached | ||
1761 | * @threadgroup: attach the whole threadgroup? | ||
1762 | * | 1761 | * |
1763 | * Call holding cgroup_mutex and the group_rwsem of the leader. Will take | 1762 | * Undo cgroup_migrate_add_src() and cgroup_migrate_prepare_dst(). See |
1764 | * task_lock of @tsk or each thread in the threadgroup individually in turn. | 1763 | * those functions for details. |
1765 | */ | 1764 | */ |
1766 | static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *leader, | 1765 | static void cgroup_migrate_finish(struct list_head *preloaded_csets) |
1767 | bool threadgroup) | 1766 | { |
1767 | struct css_set *cset, *tmp_cset; | ||
1768 | |||
1769 | lockdep_assert_held(&cgroup_mutex); | ||
1770 | |||
1771 | down_write(&css_set_rwsem); | ||
1772 | list_for_each_entry_safe(cset, tmp_cset, preloaded_csets, mg_preload_node) { | ||
1773 | cset->mg_src_cgrp = NULL; | ||
1774 | cset->mg_dst_cset = NULL; | ||
1775 | list_del_init(&cset->mg_preload_node); | ||
1776 | put_css_set_locked(cset, false); | ||
1777 | } | ||
1778 | up_write(&css_set_rwsem); | ||
1779 | } | ||
1780 | |||
1781 | /** | ||
1782 | * cgroup_migrate_add_src - add a migration source css_set | ||
1783 | * @src_cset: the source css_set to add | ||
1784 | * @dst_cgrp: the destination cgroup | ||
1785 | * @preloaded_csets: list of preloaded css_sets | ||
1786 | * | ||
1787 | * Tasks belonging to @src_cset are about to be migrated to @dst_cgrp. Pin | ||
1788 | * @src_cset and add it to @preloaded_csets, which should later be cleaned | ||
1789 | * up by cgroup_migrate_finish(). | ||
1790 | * | ||
1791 | * This function may be called without holding threadgroup_lock even if the | ||
1792 | * target is a process. Threads may be created and destroyed but as long | ||
1793 | * as cgroup_mutex is not dropped, no new css_set can be put into play and | ||
1794 | * the preloaded css_sets are guaranteed to cover all migrations. | ||
1795 | */ | ||
1796 | static void cgroup_migrate_add_src(struct css_set *src_cset, | ||
1797 | struct cgroup *dst_cgrp, | ||
1798 | struct list_head *preloaded_csets) | ||
1799 | { | ||
1800 | struct cgroup *src_cgrp; | ||
1801 | |||
1802 | lockdep_assert_held(&cgroup_mutex); | ||
1803 | lockdep_assert_held(&css_set_rwsem); | ||
1804 | |||
1805 | src_cgrp = cset_cgroup_from_root(src_cset, dst_cgrp->root); | ||
1806 | |||
1807 | /* nothing to do if this cset already belongs to the cgroup */ | ||
1808 | if (src_cgrp == dst_cgrp) | ||
1809 | return; | ||
1810 | |||
1811 | if (!list_empty(&src_cset->mg_preload_node)) | ||
1812 | return; | ||
1813 | |||
1814 | WARN_ON(src_cset->mg_src_cgrp); | ||
1815 | WARN_ON(!list_empty(&src_cset->mg_tasks)); | ||
1816 | WARN_ON(!list_empty(&src_cset->mg_node)); | ||
1817 | |||
1818 | src_cset->mg_src_cgrp = src_cgrp; | ||
1819 | get_css_set(src_cset); | ||
1820 | list_add(&src_cset->mg_preload_node, preloaded_csets); | ||
1821 | } | ||
1822 | |||
1823 | /** | ||
1824 | * cgroup_migrate_prepare_dst - prepare destination css_sets for migration | ||
1825 | * @dst_cgrp: the destination cgroup | ||
1826 | * @preloaded_csets: list of preloaded source css_sets | ||
1827 | * | ||
1828 | * Tasks are about to be moved to @dst_cgrp and all the source css_sets | ||
1829 | * have been preloaded to @preloaded_csets. This function looks up and | ||
1830 | * pins all destination css_sets, links each to its source, and put them on | ||
1831 | * @preloaded_csets. | ||
1832 | * | ||
1833 | * This function must be called after cgroup_migrate_add_src() has been | ||
1834 | * called on each migration source css_set. After migration is performed | ||
1835 | * using cgroup_migrate(), cgroup_migrate_finish() must be called on | ||
1836 | * @preloaded_csets. | ||
1837 | */ | ||
1838 | static int cgroup_migrate_prepare_dst(struct cgroup *dst_cgrp, | ||
1839 | struct list_head *preloaded_csets) | ||
1840 | { | ||
1841 | LIST_HEAD(csets); | ||
1842 | struct css_set *src_cset; | ||
1843 | |||
1844 | lockdep_assert_held(&cgroup_mutex); | ||
1845 | |||
1846 | /* look up the dst cset for each src cset and link it to src */ | ||
1847 | list_for_each_entry(src_cset, preloaded_csets, mg_preload_node) { | ||
1848 | struct css_set *dst_cset; | ||
1849 | |||
1850 | dst_cset = find_css_set(src_cset, dst_cgrp); | ||
1851 | if (!dst_cset) | ||
1852 | goto err; | ||
1853 | |||
1854 | WARN_ON_ONCE(src_cset->mg_dst_cset || dst_cset->mg_dst_cset); | ||
1855 | src_cset->mg_dst_cset = dst_cset; | ||
1856 | |||
1857 | if (list_empty(&dst_cset->mg_preload_node)) | ||
1858 | list_add(&dst_cset->mg_preload_node, &csets); | ||
1859 | else | ||
1860 | put_css_set(dst_cset, false); | ||
1861 | } | ||
1862 | |||
1863 | list_splice(&csets, preloaded_csets); | ||
1864 | return 0; | ||
1865 | err: | ||
1866 | cgroup_migrate_finish(&csets); | ||
1867 | return -ENOMEM; | ||
1868 | } | ||
1869 | |||
1870 | /** | ||
1871 | * cgroup_migrate - migrate a process or task to a cgroup | ||
1872 | * @cgrp: the destination cgroup | ||
1873 | * @leader: the leader of the process or the task to migrate | ||
1874 | * @threadgroup: whether @leader points to the whole process or a single task | ||
1875 | * | ||
1876 | * Migrate a process or task denoted by @leader to @cgrp. If migrating a | ||
1877 | * process, the caller must be holding threadgroup_lock of @leader. The | ||
1878 | * caller is also responsible for invoking cgroup_migrate_add_src() and | ||
1879 | * cgroup_migrate_prepare_dst() on the targets before invoking this | ||
1880 | * function and following up with cgroup_migrate_finish(). | ||
1881 | * | ||
1882 | * As long as a controller's ->can_attach() doesn't fail, this function is | ||
1883 | * guaranteed to succeed. This means that, excluding ->can_attach() | ||
1884 | * failure, when migrating multiple targets, the success or failure can be | ||
1885 | * decided for all targets by invoking group_migrate_prepare_dst() before | ||
1886 | * actually starting migrating. | ||
1887 | */ | ||
1888 | static int cgroup_migrate(struct cgroup *cgrp, struct task_struct *leader, | ||
1889 | bool threadgroup) | ||
1768 | { | 1890 | { |
1769 | struct cgroup_taskset tset = { | 1891 | struct cgroup_taskset tset = { |
1770 | .src_csets = LIST_HEAD_INIT(tset.src_csets), | 1892 | .src_csets = LIST_HEAD_INIT(tset.src_csets), |
@@ -1785,29 +1907,17 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *leader, | |||
1785 | rcu_read_lock(); | 1907 | rcu_read_lock(); |
1786 | task = leader; | 1908 | task = leader; |
1787 | do { | 1909 | do { |
1788 | struct cgroup *src_cgrp; | ||
1789 | |||
1790 | /* @task either already exited or can't exit until the end */ | 1910 | /* @task either already exited or can't exit until the end */ |
1791 | if (task->flags & PF_EXITING) | 1911 | if (task->flags & PF_EXITING) |
1792 | goto next; | 1912 | goto next; |
1793 | 1913 | ||
1794 | cset = task_css_set(task); | 1914 | cset = task_css_set(task); |
1795 | src_cgrp = task_cgroup_from_root(task, cgrp->root); | 1915 | if (!cset->mg_src_cgrp) |
1796 | |||
1797 | /* nothing to do if this task is already in the cgroup */ | ||
1798 | if (src_cgrp == cgrp) | ||
1799 | goto next; | 1916 | goto next; |
1800 | 1917 | ||
1801 | if (!cset->mg_src_cgrp) { | ||
1802 | WARN_ON(!list_empty(&cset->mg_tasks)); | ||
1803 | WARN_ON(!list_empty(&cset->mg_node)); | ||
1804 | |||
1805 | cset->mg_src_cgrp = src_cgrp; | ||
1806 | list_add(&cset->mg_node, &tset.src_csets); | ||
1807 | get_css_set(cset); | ||
1808 | } | ||
1809 | |||
1810 | list_move(&task->cg_list, &cset->mg_tasks); | 1918 | list_move(&task->cg_list, &cset->mg_tasks); |
1919 | list_move(&cset->mg_node, &tset.src_csets); | ||
1920 | list_move(&cset->mg_dst_cset->mg_node, &tset.dst_csets); | ||
1811 | next: | 1921 | next: |
1812 | if (!threadgroup) | 1922 | if (!threadgroup) |
1813 | break; | 1923 | break; |
@@ -1819,9 +1929,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *leader, | |||
1819 | if (list_empty(&tset.src_csets)) | 1929 | if (list_empty(&tset.src_csets)) |
1820 | return 0; | 1930 | return 0; |
1821 | 1931 | ||
1822 | /* | 1932 | /* check that we can legitimately attach to the cgroup */ |
1823 | * step 1: check that we can legitimately attach to the cgroup. | ||
1824 | */ | ||
1825 | for_each_css(css, i, cgrp) { | 1933 | for_each_css(css, i, cgrp) { |
1826 | if (css->ss->can_attach) { | 1934 | if (css->ss->can_attach) { |
1827 | ret = css->ss->can_attach(css, &tset); | 1935 | ret = css->ss->can_attach(css, &tset); |
@@ -1833,30 +1941,9 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *leader, | |||
1833 | } | 1941 | } |
1834 | 1942 | ||
1835 | /* | 1943 | /* |
1836 | * step 2: make sure css_sets exist for all threads to be migrated. | 1944 | * Now that we're guaranteed success, proceed to move all tasks to |
1837 | * we use find_css_set, which allocates a new one if necessary. | 1945 | * the new cgroup. There are no failure cases after here, so this |
1838 | */ | 1946 | * is the commit point. |
1839 | list_for_each_entry(cset, &tset.src_csets, mg_node) { | ||
1840 | struct css_set *dst_cset; | ||
1841 | |||
1842 | dst_cset = find_css_set(cset, cgrp); | ||
1843 | if (!dst_cset) { | ||
1844 | ret = -ENOMEM; | ||
1845 | goto out_release_tset; | ||
1846 | } | ||
1847 | |||
1848 | if (list_empty(&dst_cset->mg_node)) | ||
1849 | list_add(&dst_cset->mg_node, &tset.dst_csets); | ||
1850 | else | ||
1851 | put_css_set(dst_cset, false); | ||
1852 | |||
1853 | cset->mg_dst_cset = dst_cset; | ||
1854 | } | ||
1855 | |||
1856 | /* | ||
1857 | * step 3: now that we're guaranteed success wrt the css_sets, | ||
1858 | * proceed to move all tasks to the new cgroup. There are no | ||
1859 | * failure cases after here, so this is the commit point. | ||
1860 | */ | 1947 | */ |
1861 | down_write(&css_set_rwsem); | 1948 | down_write(&css_set_rwsem); |
1862 | list_for_each_entry(cset, &tset.src_csets, mg_node) { | 1949 | list_for_each_entry(cset, &tset.src_csets, mg_node) { |
@@ -1866,14 +1953,13 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *leader, | |||
1866 | } | 1953 | } |
1867 | up_write(&css_set_rwsem); | 1954 | up_write(&css_set_rwsem); |
1868 | 1955 | ||
1869 | /* migration is committed, all target tasks are now on dst_csets */ | ||
1870 | tset.csets = &tset.dst_csets; | ||
1871 | |||
1872 | /* nothing is sensitive to fork() after this point */ | ||
1873 | |||
1874 | /* | 1956 | /* |
1875 | * step 4: do subsystem attach callbacks. | 1957 | * Migration is committed, all target tasks are now on dst_csets. |
1958 | * Nothing is sensitive to fork() after this point. Notify | ||
1959 | * controllers that migration is complete. | ||
1876 | */ | 1960 | */ |
1961 | tset.csets = &tset.dst_csets; | ||
1962 | |||
1877 | for_each_css(css, i, cgrp) | 1963 | for_each_css(css, i, cgrp) |
1878 | if (css->ss->attach) | 1964 | if (css->ss->attach) |
1879 | css->ss->attach(css, &tset); | 1965 | css->ss->attach(css, &tset); |
@@ -1893,15 +1979,50 @@ out_release_tset: | |||
1893 | list_splice_init(&tset.dst_csets, &tset.src_csets); | 1979 | list_splice_init(&tset.dst_csets, &tset.src_csets); |
1894 | list_for_each_entry_safe(cset, tmp_cset, &tset.src_csets, mg_node) { | 1980 | list_for_each_entry_safe(cset, tmp_cset, &tset.src_csets, mg_node) { |
1895 | list_splice_init(&cset->mg_tasks, &cset->tasks); | 1981 | list_splice_init(&cset->mg_tasks, &cset->tasks); |
1896 | cset->mg_dst_cset = NULL; | ||
1897 | cset->mg_src_cgrp = NULL; | ||
1898 | list_del_init(&cset->mg_node); | 1982 | list_del_init(&cset->mg_node); |
1899 | put_css_set_locked(cset, false); | ||
1900 | } | 1983 | } |
1901 | up_write(&css_set_rwsem); | 1984 | up_write(&css_set_rwsem); |
1902 | return ret; | 1985 | return ret; |
1903 | } | 1986 | } |
1904 | 1987 | ||
1988 | /** | ||
1989 | * cgroup_attach_task - attach a task or a whole threadgroup to a cgroup | ||
1990 | * @dst_cgrp: the cgroup to attach to | ||
1991 | * @leader: the task or the leader of the threadgroup to be attached | ||
1992 | * @threadgroup: attach the whole threadgroup? | ||
1993 | * | ||
1994 | * Call holding cgroup_mutex and the group_rwsem of the leader. Will take | ||
1995 | * task_lock of @tsk or each thread in the threadgroup individually in turn. | ||
1996 | */ | ||
1997 | static int cgroup_attach_task(struct cgroup *dst_cgrp, | ||
1998 | struct task_struct *leader, bool threadgroup) | ||
1999 | { | ||
2000 | LIST_HEAD(preloaded_csets); | ||
2001 | struct task_struct *task; | ||
2002 | int ret; | ||
2003 | |||
2004 | /* look up all src csets */ | ||
2005 | down_read(&css_set_rwsem); | ||
2006 | rcu_read_lock(); | ||
2007 | task = leader; | ||
2008 | do { | ||
2009 | cgroup_migrate_add_src(task_css_set(task), dst_cgrp, | ||
2010 | &preloaded_csets); | ||
2011 | if (!threadgroup) | ||
2012 | break; | ||
2013 | } while_each_thread(leader, task); | ||
2014 | rcu_read_unlock(); | ||
2015 | up_read(&css_set_rwsem); | ||
2016 | |||
2017 | /* prepare dst csets and commit */ | ||
2018 | ret = cgroup_migrate_prepare_dst(dst_cgrp, &preloaded_csets); | ||
2019 | if (!ret) | ||
2020 | ret = cgroup_migrate(dst_cgrp, leader, threadgroup); | ||
2021 | |||
2022 | cgroup_migrate_finish(&preloaded_csets); | ||
2023 | return ret; | ||
2024 | } | ||
2025 | |||
1905 | /* | 2026 | /* |
1906 | * Find the task_struct of the task to attach by vpid and pass it along to the | 2027 | * Find the task_struct of the task to attach by vpid and pass it along to the |
1907 | * function to attach either it or all tasks in its threadgroup. Will lock | 2028 | * function to attach either it or all tasks in its threadgroup. Will lock |
@@ -3906,6 +4027,7 @@ int __init cgroup_init_early(void) | |||
3906 | INIT_LIST_HEAD(&init_css_set.cgrp_links); | 4027 | INIT_LIST_HEAD(&init_css_set.cgrp_links); |
3907 | INIT_LIST_HEAD(&init_css_set.tasks); | 4028 | INIT_LIST_HEAD(&init_css_set.tasks); |
3908 | INIT_LIST_HEAD(&init_css_set.mg_tasks); | 4029 | INIT_LIST_HEAD(&init_css_set.mg_tasks); |
4030 | INIT_LIST_HEAD(&init_css_set.mg_preload_node); | ||
3909 | INIT_LIST_HEAD(&init_css_set.mg_node); | 4031 | INIT_LIST_HEAD(&init_css_set.mg_node); |
3910 | INIT_HLIST_NODE(&init_css_set.hlist); | 4032 | INIT_HLIST_NODE(&init_css_set.hlist); |
3911 | css_set_count = 1; | 4033 | css_set_count = 1; |