diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 90 |
1 files changed, 67 insertions, 23 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 2dd333b0fe7f..3dc283fd4716 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -42,6 +42,8 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); | |||
42 | static int event; | 42 | static int event; |
43 | static DEFINE_IDA(mnt_id_ida); | 43 | static DEFINE_IDA(mnt_id_ida); |
44 | static DEFINE_IDA(mnt_group_ida); | 44 | static DEFINE_IDA(mnt_group_ida); |
45 | static int mnt_id_start = 0; | ||
46 | static int mnt_group_start = 1; | ||
45 | 47 | ||
46 | static struct list_head *mount_hashtable __read_mostly; | 48 | static struct list_head *mount_hashtable __read_mostly; |
47 | static struct kmem_cache *mnt_cache __read_mostly; | 49 | static struct kmem_cache *mnt_cache __read_mostly; |
@@ -69,7 +71,9 @@ static int mnt_alloc_id(struct vfsmount *mnt) | |||
69 | retry: | 71 | retry: |
70 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); | 72 | ida_pre_get(&mnt_id_ida, GFP_KERNEL); |
71 | spin_lock(&vfsmount_lock); | 73 | spin_lock(&vfsmount_lock); |
72 | res = ida_get_new(&mnt_id_ida, &mnt->mnt_id); | 74 | res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); |
75 | if (!res) | ||
76 | mnt_id_start = mnt->mnt_id + 1; | ||
73 | spin_unlock(&vfsmount_lock); | 77 | spin_unlock(&vfsmount_lock); |
74 | if (res == -EAGAIN) | 78 | if (res == -EAGAIN) |
75 | goto retry; | 79 | goto retry; |
@@ -79,8 +83,11 @@ retry: | |||
79 | 83 | ||
80 | static void mnt_free_id(struct vfsmount *mnt) | 84 | static void mnt_free_id(struct vfsmount *mnt) |
81 | { | 85 | { |
86 | int id = mnt->mnt_id; | ||
82 | spin_lock(&vfsmount_lock); | 87 | spin_lock(&vfsmount_lock); |
83 | ida_remove(&mnt_id_ida, mnt->mnt_id); | 88 | ida_remove(&mnt_id_ida, id); |
89 | if (mnt_id_start > id) | ||
90 | mnt_id_start = id; | ||
84 | spin_unlock(&vfsmount_lock); | 91 | spin_unlock(&vfsmount_lock); |
85 | } | 92 | } |
86 | 93 | ||
@@ -91,10 +98,18 @@ static void mnt_free_id(struct vfsmount *mnt) | |||
91 | */ | 98 | */ |
92 | static int mnt_alloc_group_id(struct vfsmount *mnt) | 99 | static int mnt_alloc_group_id(struct vfsmount *mnt) |
93 | { | 100 | { |
101 | int res; | ||
102 | |||
94 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) | 103 | if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) |
95 | return -ENOMEM; | 104 | return -ENOMEM; |
96 | 105 | ||
97 | return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id); | 106 | res = ida_get_new_above(&mnt_group_ida, |
107 | mnt_group_start, | ||
108 | &mnt->mnt_group_id); | ||
109 | if (!res) | ||
110 | mnt_group_start = mnt->mnt_group_id + 1; | ||
111 | |||
112 | return res; | ||
98 | } | 113 | } |
99 | 114 | ||
100 | /* | 115 | /* |
@@ -102,7 +117,10 @@ static int mnt_alloc_group_id(struct vfsmount *mnt) | |||
102 | */ | 117 | */ |
103 | void mnt_release_group_id(struct vfsmount *mnt) | 118 | void mnt_release_group_id(struct vfsmount *mnt) |
104 | { | 119 | { |
105 | ida_remove(&mnt_group_ida, mnt->mnt_group_id); | 120 | int id = mnt->mnt_group_id; |
121 | ida_remove(&mnt_group_ida, id); | ||
122 | if (mnt_group_start > id) | ||
123 | mnt_group_start = id; | ||
106 | mnt->mnt_group_id = 0; | 124 | mnt->mnt_group_id = 0; |
107 | } | 125 | } |
108 | 126 | ||
@@ -1937,6 +1955,21 @@ dput_out: | |||
1937 | return retval; | 1955 | return retval; |
1938 | } | 1956 | } |
1939 | 1957 | ||
1958 | static struct mnt_namespace *alloc_mnt_ns(void) | ||
1959 | { | ||
1960 | struct mnt_namespace *new_ns; | ||
1961 | |||
1962 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | ||
1963 | if (!new_ns) | ||
1964 | return ERR_PTR(-ENOMEM); | ||
1965 | atomic_set(&new_ns->count, 1); | ||
1966 | new_ns->root = NULL; | ||
1967 | INIT_LIST_HEAD(&new_ns->list); | ||
1968 | init_waitqueue_head(&new_ns->poll); | ||
1969 | new_ns->event = 0; | ||
1970 | return new_ns; | ||
1971 | } | ||
1972 | |||
1940 | /* | 1973 | /* |
1941 | * Allocate a new namespace structure and populate it with contents | 1974 | * Allocate a new namespace structure and populate it with contents |
1942 | * copied from the namespace of the passed in task structure. | 1975 | * copied from the namespace of the passed in task structure. |
@@ -1948,14 +1981,9 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns, | |||
1948 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; | 1981 | struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; |
1949 | struct vfsmount *p, *q; | 1982 | struct vfsmount *p, *q; |
1950 | 1983 | ||
1951 | new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); | 1984 | new_ns = alloc_mnt_ns(); |
1952 | if (!new_ns) | 1985 | if (IS_ERR(new_ns)) |
1953 | return ERR_PTR(-ENOMEM); | 1986 | return new_ns; |
1954 | |||
1955 | atomic_set(&new_ns->count, 1); | ||
1956 | INIT_LIST_HEAD(&new_ns->list); | ||
1957 | init_waitqueue_head(&new_ns->poll); | ||
1958 | new_ns->event = 0; | ||
1959 | 1987 | ||
1960 | down_write(&namespace_sem); | 1988 | down_write(&namespace_sem); |
1961 | /* First pass: copy the tree topology */ | 1989 | /* First pass: copy the tree topology */ |
@@ -2019,6 +2047,24 @@ struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, | |||
2019 | return new_ns; | 2047 | return new_ns; |
2020 | } | 2048 | } |
2021 | 2049 | ||
2050 | /** | ||
2051 | * create_mnt_ns - creates a private namespace and adds a root filesystem | ||
2052 | * @mnt: pointer to the new root filesystem mountpoint | ||
2053 | */ | ||
2054 | struct mnt_namespace *create_mnt_ns(struct vfsmount *mnt) | ||
2055 | { | ||
2056 | struct mnt_namespace *new_ns; | ||
2057 | |||
2058 | new_ns = alloc_mnt_ns(); | ||
2059 | if (!IS_ERR(new_ns)) { | ||
2060 | mnt->mnt_ns = new_ns; | ||
2061 | new_ns->root = mnt; | ||
2062 | list_add(&new_ns->list, &new_ns->root->mnt_list); | ||
2063 | } | ||
2064 | return new_ns; | ||
2065 | } | ||
2066 | EXPORT_SYMBOL(create_mnt_ns); | ||
2067 | |||
2022 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, | 2068 | SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, |
2023 | char __user *, type, unsigned long, flags, void __user *, data) | 2069 | char __user *, type, unsigned long, flags, void __user *, data) |
2024 | { | 2070 | { |
@@ -2194,16 +2240,9 @@ static void __init init_mount_tree(void) | |||
2194 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); | 2240 | mnt = do_kern_mount("rootfs", 0, "rootfs", NULL); |
2195 | if (IS_ERR(mnt)) | 2241 | if (IS_ERR(mnt)) |
2196 | panic("Can't create rootfs"); | 2242 | panic("Can't create rootfs"); |
2197 | ns = kmalloc(sizeof(*ns), GFP_KERNEL); | 2243 | ns = create_mnt_ns(mnt); |
2198 | if (!ns) | 2244 | if (IS_ERR(ns)) |
2199 | panic("Can't allocate initial namespace"); | 2245 | panic("Can't allocate initial namespace"); |
2200 | atomic_set(&ns->count, 1); | ||
2201 | INIT_LIST_HEAD(&ns->list); | ||
2202 | init_waitqueue_head(&ns->poll); | ||
2203 | ns->event = 0; | ||
2204 | list_add(&mnt->mnt_list, &ns->list); | ||
2205 | ns->root = mnt; | ||
2206 | mnt->mnt_ns = ns; | ||
2207 | 2246 | ||
2208 | init_task.nsproxy->mnt_ns = ns; | 2247 | init_task.nsproxy->mnt_ns = ns; |
2209 | get_mnt_ns(ns); | 2248 | get_mnt_ns(ns); |
@@ -2246,10 +2285,14 @@ void __init mnt_init(void) | |||
2246 | init_mount_tree(); | 2285 | init_mount_tree(); |
2247 | } | 2286 | } |
2248 | 2287 | ||
2249 | void __put_mnt_ns(struct mnt_namespace *ns) | 2288 | void put_mnt_ns(struct mnt_namespace *ns) |
2250 | { | 2289 | { |
2251 | struct vfsmount *root = ns->root; | 2290 | struct vfsmount *root; |
2252 | LIST_HEAD(umount_list); | 2291 | LIST_HEAD(umount_list); |
2292 | |||
2293 | if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock)) | ||
2294 | return; | ||
2295 | root = ns->root; | ||
2253 | ns->root = NULL; | 2296 | ns->root = NULL; |
2254 | spin_unlock(&vfsmount_lock); | 2297 | spin_unlock(&vfsmount_lock); |
2255 | down_write(&namespace_sem); | 2298 | down_write(&namespace_sem); |
@@ -2260,3 +2303,4 @@ void __put_mnt_ns(struct mnt_namespace *ns) | |||
2260 | release_mounts(&umount_list); | 2303 | release_mounts(&umount_list); |
2261 | kfree(ns); | 2304 | kfree(ns); |
2262 | } | 2305 | } |
2306 | EXPORT_SYMBOL(put_mnt_ns); | ||