vserver 1.9.3
[linux-2.6.git] / kernel / vserver / namespace.c
1 /*
2  *  linux/kernel/vserver/namespace.c
3  *
4  *  Virtual Server: Context Namespace Support
5  *
6  *  Copyright (C) 2003-2004  Herbert Pötzl
7  *
8  *  V0.01  broken out from context.c 0.07
9  *  V0.02  added task locking for namespace
10  *
11  */
12
13 #include <linux/config.h>
14 #include <linux/utsname.h>
15 #include <linux/vserver/namespace.h>
16 #include <linux/vs_base.h>
17 #include <linux/vs_context.h>
18 #include <linux/namespace.h>
19 #include <linux/dcache.h>
20 #include <linux/fs.h>
21
22 #include <asm/errno.h>
23 #include <asm/uaccess.h>
24
25
26 int vx_check_vfsmount(struct vx_info *vxi, struct vfsmount *mnt)
27 {
28         struct vfsmount *root_mnt, *altroot_mnt;
29         struct dentry *root, *altroot, *point;
30         int r1, r2, s1, s2, ret = 0;
31
32         if (!vxi || !mnt)
33                 return 1;
34
35         spin_lock(&dcache_lock);
36         altroot_mnt = current->fs->rootmnt;
37         altroot = current->fs->root;
38         point = altroot;
39
40         if (vxi->vx_fs) {
41                 root_mnt = vxi->vx_fs->rootmnt;
42                 root = vxi->vx_fs->root;
43         } else {
44                 root_mnt = altroot_mnt;
45                 root = altroot;
46         }
47         /* printk("··· %p:%p/%p:%p ",
48                 root_mnt, root, altroot_mnt, altroot);  */
49
50         while ((mnt != mnt->mnt_parent) &&
51                 (mnt != root_mnt) && (mnt != altroot_mnt)) {
52                 point = mnt->mnt_mountpoint;
53                 mnt = mnt->mnt_parent;
54         }
55
56         r1 = (mnt == root_mnt);
57         s1 = is_subdir(point, root);
58         r2 = (mnt == altroot_mnt);
59         s2 = is_subdir(point, altroot);
60
61         ret = (((mnt == root_mnt) && is_subdir(point, root)) ||
62                 ((mnt == altroot_mnt) && is_subdir(point, altroot)));
63         /* printk("··· for %p:%p -> %d:%d/%d:%d = %d\n",
64                 mnt, point, r1, s1, r2, s2, ret);       */
65         spin_unlock(&dcache_lock);
66
67         return (r2 && s2);
68 }
69
70
71 /* virtual host info names */
72
73 static char * vx_vhi_name(struct vx_info *vxi, int id)
74 {
75         switch (id) {
76                 case VHIN_CONTEXT:
77                         return vxi->vx_name;
78                 case VHIN_SYSNAME:
79                         return vxi->cvirt.utsname.sysname;
80                 case VHIN_NODENAME:
81                         return vxi->cvirt.utsname.nodename;
82                 case VHIN_RELEASE:
83                         return vxi->cvirt.utsname.release;
84                 case VHIN_VERSION:
85                         return vxi->cvirt.utsname.version;
86                 case VHIN_MACHINE:
87                         return vxi->cvirt.utsname.machine;
88                 case VHIN_DOMAINNAME:
89                         return vxi->cvirt.utsname.domainname;
90                 default:
91                         return NULL;
92         }
93         return NULL;
94 }
95
96 int vc_set_vhi_name(uint32_t id, void __user *data)
97 {
98         struct vx_info *vxi;
99         struct vcmd_vx_vhi_name_v0 vc_data;
100         char *name;
101
102         if (!capable(CAP_SYS_ADMIN))
103                 return -EPERM;
104         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
105                 return -EFAULT;
106
107         vxi = locate_vx_info(id);
108         if (!vxi)
109                 return -ESRCH;
110
111         name = vx_vhi_name(vxi, vc_data.field);
112         if (name)
113                 memcpy(name, vc_data.name, 65);
114         put_vx_info(vxi);
115         return (name ? 0 : -EFAULT);
116 }
117
118 int vc_get_vhi_name(uint32_t id, void __user *data)
119 {
120         struct vx_info *vxi;
121         struct vcmd_vx_vhi_name_v0 vc_data;
122         char *name;
123
124         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
125                 return -EFAULT;
126
127         vxi = locate_vx_info(id);
128         if (!vxi)
129                 return -ESRCH;
130
131         name = vx_vhi_name(vxi, vc_data.field);
132         if (!name)
133                 goto out_put;
134
135         memcpy(vc_data.name, name, 65);
136         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
137                 return -EFAULT;
138 out_put:
139         put_vx_info(vxi);
140         return (name ? 0 : -EFAULT);
141 }
142
143 /* namespace functions */
144
145 #include <linux/namespace.h>
146
147 int vx_set_namespace(struct vx_info *vxi, struct namespace *ns, struct fs_struct *fs)
148 {
149         struct fs_struct *fs_copy;
150
151         if (vxi->vx_namespace)
152                 return -EPERM;
153         if (!ns || !fs)
154                 return -EINVAL;
155
156         fs_copy = copy_fs_struct(fs);
157         if (!fs_copy)
158                 return -ENOMEM;
159
160         get_namespace(ns);
161         vxi->vx_namespace = ns;
162         vxi->vx_fs = fs_copy;
163         return 0;
164 }
165
166 int vc_enter_namespace(uint32_t id, void *data)
167 {
168         struct vx_info *vxi;
169         struct fs_struct *old_fs, *fs;
170         struct namespace *old_ns;
171         int ret = 0;
172
173         if (!vx_check(0, VX_ADMIN))
174                 return -ENOSYS;
175
176         vxi = locate_vx_info(id);
177         if (!vxi)
178                 return -ESRCH;
179
180         ret = -EINVAL;
181         if (!vxi->vx_namespace)
182                 goto out_put;
183
184         ret = -ENOMEM;
185         fs = copy_fs_struct(vxi->vx_fs);
186         if (!fs)
187                 goto out_put;
188
189         ret = 0;
190         task_lock(current);
191         old_ns = current->namespace;
192         old_fs = current->fs;
193         get_namespace(vxi->vx_namespace);
194         current->namespace = vxi->vx_namespace;
195         current->fs = fs;
196         task_unlock(current);
197
198         put_namespace(old_ns);
199         put_fs_struct(old_fs);
200 out_put:
201         put_vx_info(vxi);
202         return ret;
203 }
204
205 int vc_cleanup_namespace(uint32_t id, void *data)
206 {
207         down_write(&current->namespace->sem);
208         spin_lock(&vfsmount_lock);
209         umount_unused(current->namespace->root, current->fs);
210         spin_unlock(&vfsmount_lock);
211         up_write(&current->namespace->sem);
212         return 0;
213 }
214
215 int vc_set_namespace(uint32_t id, void __user *data)
216 {
217         struct fs_struct *fs;
218         struct namespace *ns;
219         struct vx_info *vxi;
220         int ret;
221
222         if (vx_check(0, VX_ADMIN|VX_WATCH))
223                 return -ENOSYS;
224
225         task_lock(current);
226         vxi = get_vx_info(current->vx_info);
227         fs = current->fs;
228         atomic_inc(&fs->count);
229         ns = current->namespace;
230         get_namespace(current->namespace);
231         task_unlock(current);
232
233         ret = vx_set_namespace(vxi, ns, fs);
234
235         put_namespace(ns);
236         put_fs_struct(fs);
237         put_vx_info(vxi);
238         return ret;
239 }
240