diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 49 |
1 files changed, 48 insertions, 1 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 556721fb0cf6..f853aaf92ec9 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #include "pnode.h" | 27 | #include "pnode.h" |
28 | #include "internal.h" | 28 | #include "internal.h" |
29 | 29 | ||
30 | /* Maximum number of mounts in a mount namespace */ | ||
31 | unsigned int sysctl_mount_max __read_mostly = 100000; | ||
32 | |||
30 | static unsigned int m_hash_mask __read_mostly; | 33 | static unsigned int m_hash_mask __read_mostly; |
31 | static unsigned int m_hash_shift __read_mostly; | 34 | static unsigned int m_hash_shift __read_mostly; |
32 | static unsigned int mp_hash_mask __read_mostly; | 35 | static unsigned int mp_hash_mask __read_mostly; |
@@ -888,6 +891,9 @@ static void commit_tree(struct mount *mnt, struct mount *shadows) | |||
888 | 891 | ||
889 | list_splice(&head, n->list.prev); | 892 | list_splice(&head, n->list.prev); |
890 | 893 | ||
894 | n->mounts += n->pending_mounts; | ||
895 | n->pending_mounts = 0; | ||
896 | |||
891 | attach_shadowed(mnt, parent, shadows); | 897 | attach_shadowed(mnt, parent, shadows); |
892 | touch_mnt_namespace(n); | 898 | touch_mnt_namespace(n); |
893 | } | 899 | } |
@@ -1408,11 +1414,16 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how) | |||
1408 | propagate_umount(&tmp_list); | 1414 | propagate_umount(&tmp_list); |
1409 | 1415 | ||
1410 | while (!list_empty(&tmp_list)) { | 1416 | while (!list_empty(&tmp_list)) { |
1417 | struct mnt_namespace *ns; | ||
1411 | bool disconnect; | 1418 | bool disconnect; |
1412 | p = list_first_entry(&tmp_list, struct mount, mnt_list); | 1419 | p = list_first_entry(&tmp_list, struct mount, mnt_list); |
1413 | list_del_init(&p->mnt_expire); | 1420 | list_del_init(&p->mnt_expire); |
1414 | list_del_init(&p->mnt_list); | 1421 | list_del_init(&p->mnt_list); |
1415 | __touch_mnt_namespace(p->mnt_ns); | 1422 | ns = p->mnt_ns; |
1423 | if (ns) { | ||
1424 | ns->mounts--; | ||
1425 | __touch_mnt_namespace(ns); | ||
1426 | } | ||
1416 | p->mnt_ns = NULL; | 1427 | p->mnt_ns = NULL; |
1417 | if (how & UMOUNT_SYNC) | 1428 | if (how & UMOUNT_SYNC) |
1418 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; | 1429 | p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; |
@@ -1821,6 +1832,28 @@ static int invent_group_ids(struct mount *mnt, bool recurse) | |||
1821 | return 0; | 1832 | return 0; |
1822 | } | 1833 | } |
1823 | 1834 | ||
1835 | int count_mounts(struct mnt_namespace *ns, struct mount *mnt) | ||
1836 | { | ||
1837 | unsigned int max = READ_ONCE(sysctl_mount_max); | ||
1838 | unsigned int mounts = 0, old, pending, sum; | ||
1839 | struct mount *p; | ||
1840 | |||
1841 | for (p = mnt; p; p = next_mnt(p, mnt)) | ||
1842 | mounts++; | ||
1843 | |||
1844 | old = ns->mounts; | ||
1845 | pending = ns->pending_mounts; | ||
1846 | sum = old + pending; | ||
1847 | if ((old > sum) || | ||
1848 | (pending > sum) || | ||
1849 | (max < sum) || | ||
1850 | (mounts > (max - sum))) | ||
1851 | return -ENOSPC; | ||
1852 | |||
1853 | ns->pending_mounts = pending + mounts; | ||
1854 | return 0; | ||
1855 | } | ||
1856 | |||
1824 | /* | 1857 | /* |
1825 | * @source_mnt : mount tree to be attached | 1858 | * @source_mnt : mount tree to be attached |
1826 | * @nd : place the mount tree @source_mnt is attached | 1859 | * @nd : place the mount tree @source_mnt is attached |
@@ -1890,10 +1923,18 @@ static int attach_recursive_mnt(struct mount *source_mnt, | |||
1890 | struct path *parent_path) | 1923 | struct path *parent_path) |
1891 | { | 1924 | { |
1892 | HLIST_HEAD(tree_list); | 1925 | HLIST_HEAD(tree_list); |
1926 | struct mnt_namespace *ns = dest_mnt->mnt_ns; | ||
1893 | struct mount *child, *p; | 1927 | struct mount *child, *p; |
1894 | struct hlist_node *n; | 1928 | struct hlist_node *n; |
1895 | int err; | 1929 | int err; |
1896 | 1930 | ||
1931 | /* Is there space to add these mounts to the mount namespace? */ | ||
1932 | if (!parent_path) { | ||
1933 | err = count_mounts(ns, source_mnt); | ||
1934 | if (err) | ||
1935 | goto out; | ||
1936 | } | ||
1937 | |||
1897 | if (IS_MNT_SHARED(dest_mnt)) { | 1938 | if (IS_MNT_SHARED(dest_mnt)) { |
1898 | err = invent_group_ids(source_mnt, true); | 1939 | err = invent_group_ids(source_mnt, true); |
1899 | if (err) | 1940 | if (err) |
@@ -1930,11 +1971,13 @@ static int attach_recursive_mnt(struct mount *source_mnt, | |||
1930 | out_cleanup_ids: | 1971 | out_cleanup_ids: |
1931 | while (!hlist_empty(&tree_list)) { | 1972 | while (!hlist_empty(&tree_list)) { |
1932 | child = hlist_entry(tree_list.first, struct mount, mnt_hash); | 1973 | child = hlist_entry(tree_list.first, struct mount, mnt_hash); |
1974 | child->mnt_parent->mnt_ns->pending_mounts = 0; | ||
1933 | umount_tree(child, UMOUNT_SYNC); | 1975 | umount_tree(child, UMOUNT_SYNC); |
1934 | } | 1976 | } |
1935 | unlock_mount_hash(); | 1977 | unlock_mount_hash(); |
1936 | cleanup_group_ids(source_mnt, NULL); | 1978 | cleanup_group_ids(source_mnt, NULL); |
1937 | out: | 1979 | out: |
1980 | ns->pending_mounts = 0; | ||
1938 | return err; | 1981 | return err; |
1939 | } | 1982 | } |
1940 | 1983 | ||
@@ -2758,6 +2801,8 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) | |||
2758 | init_waitqueue_head(&new_ns->poll); | 2801 | init_waitqueue_head(&new_ns->poll); |
2759 | new_ns->event = 0; | 2802 | new_ns->event = 0; |
2760 | new_ns->user_ns = get_user_ns(user_ns); | 2803 | new_ns->user_ns = get_user_ns(user_ns); |
2804 | new_ns->mounts = 0; | ||
2805 | new_ns->pending_mounts = 0; | ||
2761 | return new_ns; | 2806 | return new_ns; |
2762 | } | 2807 | } |
2763 | 2808 | ||
@@ -2807,6 +2852,7 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2807 | q = new; | 2852 | q = new; |
2808 | while (p) { | 2853 | while (p) { |
2809 | q->mnt_ns = new_ns; | 2854 | q->mnt_ns = new_ns; |
2855 | new_ns->mounts++; | ||
2810 | if (new_fs) { | 2856 | if (new_fs) { |
2811 | if (&p->mnt == new_fs->root.mnt) { | 2857 | if (&p->mnt == new_fs->root.mnt) { |
2812 | new_fs->root.mnt = mntget(&q->mnt); | 2858 | new_fs->root.mnt = mntget(&q->mnt); |
@@ -2845,6 +2891,7 @@ static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) | |||
2845 | struct mount *mnt = real_mount(m); | 2891 | struct mount *mnt = real_mount(m); |
2846 | mnt->mnt_ns = new_ns; | 2892 | mnt->mnt_ns = new_ns; |
2847 | new_ns->root = mnt; | 2893 | new_ns->root = mnt; |
2894 | new_ns->mounts++; | ||
2848 | list_add(&mnt->mnt_list, &new_ns->list); | 2895 | list_add(&mnt->mnt_list, &new_ns->list); |
2849 | } else { | 2896 | } else { |
2850 | mntput(m); | 2897 | mntput(m); |