fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / kernel / vserver / inode.c
1 /*
2  *  linux/kernel/vserver/inode.c
3  *
4  *  Virtual Server: File System Support
5  *
6  *  Copyright (C) 2004-2007  Herbert Pötzl
7  *
8  *  V0.01  separated from vcontext V0.05
9  *
10  */
11
12 #include <linux/sched.h>
13 #include <linux/proc_fs.h>
14 #include <linux/devpts_fs.h>
15 #include <linux/namei.h>
16 #include <linux/mount.h>
17 #include <linux/parser.h>
18 #include <linux/compat.h>
19 #include <linux/vserver/inode.h>
20 #include <linux/vserver/inode_cmd.h>
21 #include <linux/vs_base.h>
22 #include <linux/vs_tag.h>
23
24 #include <asm/errno.h>
25 #include <asm/uaccess.h>
26
27
28 static int __vc_get_iattr(struct inode *in, uint32_t *tag, uint32_t *flags, uint32_t *mask)
29 {
30         struct proc_dir_entry *entry;
31
32         if (!in || !in->i_sb)
33                 return -ESRCH;
34
35         *flags = IATTR_TAG
36                 | (IS_BARRIER(in) ? IATTR_BARRIER : 0)
37                 | (IS_IUNLINK(in) ? IATTR_IUNLINK : 0)
38                 | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0);
39         *mask = IATTR_IUNLINK | IATTR_IMMUTABLE;
40
41         if (S_ISDIR(in->i_mode))
42                 *mask |= IATTR_BARRIER;
43
44         if (IS_TAGGED(in)) {
45                 *tag = in->i_tag;
46                 *mask |= IATTR_TAG;
47         }
48
49         switch (in->i_sb->s_magic) {
50         case PROC_SUPER_MAGIC:
51                 entry = PROC_I(in)->pde;
52
53                 /* check for specific inodes? */
54                 if (entry)
55                         *mask |= IATTR_FLAGS;
56                 if (entry)
57                         *flags |= (entry->vx_flags & IATTR_FLAGS);
58                 else
59                         *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS);
60                 break;
61
62         case DEVPTS_SUPER_MAGIC:
63                 *tag = in->i_tag;
64                 *mask |= IATTR_TAG;
65                 break;
66
67         default:
68                 break;
69         }
70         return 0;
71 }
72
73 int vc_get_iattr(uint32_t id, void __user *data)
74 {
75         struct nameidata nd;
76         struct vcmd_ctx_iattr_v1 vc_data = { .xid = -1 };
77         int ret;
78
79         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
80                 return -EFAULT;
81
82         ret = user_path_walk_link(vc_data.name, &nd);
83         if (!ret) {
84                 ret = __vc_get_iattr(nd.dentry->d_inode,
85                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
86                 path_release(&nd);
87         }
88         if (ret)
89                 return ret;
90
91         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
92                 ret = -EFAULT;
93         return ret;
94 }
95
96 #ifdef  CONFIG_COMPAT
97
98 int vc_get_iattr_x32(uint32_t id, void __user *data)
99 {
100         struct nameidata nd;
101         struct vcmd_ctx_iattr_v1_x32 vc_data = { .xid = -1 };
102         int ret;
103
104         if (!vx_check(0, VS_ADMIN))
105                 return -ENOSYS;
106         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
107                 return -EFAULT;
108
109         ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
110         if (!ret) {
111                 ret = __vc_get_iattr(nd.dentry->d_inode,
112                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
113                 path_release(&nd);
114         }
115         if (ret)
116                 return ret;
117
118         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
119                 ret = -EFAULT;
120         return ret;
121 }
122
123 #endif  /* CONFIG_COMPAT */
124
125
126 static int __vc_set_iattr(struct dentry *de, uint32_t *tag, uint32_t *flags, uint32_t *mask)
127 {
128         struct inode *in = de->d_inode;
129         int error = 0, is_proc = 0, has_tag = 0;
130         struct iattr attr = { 0 };
131
132         if (!in || !in->i_sb)
133                 return -ESRCH;
134
135         is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
136         if ((*mask & IATTR_FLAGS) && !is_proc)
137                 return -EINVAL;
138
139         has_tag = IS_TAGGED(in) ||
140                 (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC);
141         if ((*mask & IATTR_TAG) && !has_tag)
142                 return -EINVAL;
143
144         mutex_lock(&in->i_mutex);
145         if (*mask & IATTR_TAG) {
146                 attr.ia_tag = *tag;
147                 attr.ia_valid |= ATTR_TAG;
148         }
149
150         if (*mask & IATTR_FLAGS) {
151                 struct proc_dir_entry *entry = PROC_I(in)->pde;
152                 unsigned int iflags = PROC_I(in)->vx_flags;
153
154                 iflags = (iflags & ~(*mask & IATTR_FLAGS))
155                         | (*flags & IATTR_FLAGS);
156                 PROC_I(in)->vx_flags = iflags;
157                 if (entry)
158                         entry->vx_flags = iflags;
159         }
160
161         if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
162                 if (*mask & IATTR_IMMUTABLE) {
163                         if (*flags & IATTR_IMMUTABLE)
164                                 in->i_flags |= S_IMMUTABLE;
165                         else
166                                 in->i_flags &= ~S_IMMUTABLE;
167                 }
168                 if (*mask & IATTR_IUNLINK) {
169                         if (*flags & IATTR_IUNLINK)
170                                 in->i_flags |= S_IUNLINK;
171                         else
172                                 in->i_flags &= ~S_IUNLINK;
173                 }
174                 if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
175                         if (*flags & IATTR_BARRIER)
176                                 in->i_flags |= S_BARRIER;
177                         else
178                                 in->i_flags &= ~S_BARRIER;
179                 }
180                 if (in->i_op && in->i_op->sync_flags) {
181                         error = in->i_op->sync_flags(in);
182                         if (error)
183                                 goto out;
184                 }
185         }
186
187         if (attr.ia_valid) {
188                 if (in->i_op && in->i_op->setattr)
189                         error = in->i_op->setattr(de, &attr);
190                 else {
191                         error = inode_change_ok(in, &attr);
192                         if (!error)
193                                 error = inode_setattr(in, &attr);
194                 }
195         }
196
197 out:
198         mutex_unlock(&in->i_mutex);
199         return error;
200 }
201
202 int vc_set_iattr(uint32_t id, void __user *data)
203 {
204         struct nameidata nd;
205         struct vcmd_ctx_iattr_v1 vc_data;
206         int ret;
207
208         if (!capable(CAP_LINUX_IMMUTABLE))
209                 return -EPERM;
210         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
211                 return -EFAULT;
212
213         ret = user_path_walk_link(vc_data.name, &nd);
214         if (!ret) {
215                 ret = __vc_set_iattr(nd.dentry,
216                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
217                 path_release(&nd);
218         }
219
220         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
221                 ret = -EFAULT;
222         return ret;
223 }
224
225 #ifdef  CONFIG_COMPAT
226
227 int vc_set_iattr_x32(uint32_t id, void __user *data)
228 {
229         struct nameidata nd;
230         struct vcmd_ctx_iattr_v1_x32 vc_data;
231         int ret;
232
233         if (!capable(CAP_LINUX_IMMUTABLE))
234                 return -EPERM;
235         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
236                 return -EFAULT;
237
238         ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
239         if (!ret) {
240                 ret = __vc_set_iattr(nd.dentry,
241                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
242                 path_release(&nd);
243         }
244
245         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
246                 ret = -EFAULT;
247         return ret;
248 }
249
250 #endif  /* CONFIG_COMPAT */
251
252 #ifdef  CONFIG_VSERVER_LEGACY
253
254 #define PROC_DYNAMIC_FIRST 0xF0000000UL
255
256 int vx_proc_ioctl(struct inode * inode, struct file * filp,
257         unsigned int cmd, unsigned long arg)
258 {
259         struct proc_dir_entry *entry;
260         int error = 0;
261         int flags;
262
263         if (inode->i_ino < PROC_DYNAMIC_FIRST)
264                 return -ENOTTY;
265
266         entry = PROC_I(inode)->pde;
267         if (!entry)
268                 return -ENOTTY;
269
270         switch(cmd) {
271         case FIOC_GETXFLG: {
272                 /* fixme: if stealth, return -ENOTTY */
273                 error = -EPERM;
274                 flags = entry->vx_flags;
275                 if (capable(CAP_CONTEXT))
276                         error = put_user(flags, (int __user *) arg);
277                 break;
278         }
279         case FIOC_SETXFLG: {
280                 /* fixme: if stealth, return -ENOTTY */
281                 error = -EPERM;
282                 if (!capable(CAP_CONTEXT))
283                         break;
284                 error = -EROFS;
285                 if (IS_RDONLY(inode))
286                         break;
287                 error = -EFAULT;
288                 if (get_user(flags, (int __user *) arg))
289                         break;
290                 error = 0;
291                 entry->vx_flags = flags;
292                 break;
293         }
294         default:
295                 return -ENOTTY;
296         }
297         return error;
298 }
299 #endif  /* CONFIG_VSERVER_LEGACY */
300
301 #ifdef  CONFIG_PROPAGATE
302
303 int dx_parse_tag(char *string, tag_t *tag, int remove)
304 {
305         static match_table_t tokens = {
306                 {1, "tagid=%u"},
307                 {0, NULL}
308         };
309         substring_t args[MAX_OPT_ARGS];
310         int token, option = 0;
311
312         if (!string)
313                 return 0;
314
315         token = match_token(string, tokens, args);
316         if (token && tag && !match_int(args, &option))
317                 *tag = option;
318
319         vxdprintk(VXD_CBIT(tag, 7),
320                 "dx_parse_tag(»%s«): %d:#%d",
321                 string, token, option);
322
323         if ((token == 1) && remove) {
324                 char *p = strstr(string, "tagid=");
325                 char *q = p;
326
327                 if (p) {
328                         while (*q != '\0' && *q != ',')
329                                 q++;
330                         while (*q)
331                                 *p++ = *q++;
332                         while (*p)
333                                 *p++ = '\0';
334                 }
335         }
336         return token;
337 }
338
339 void __dx_propagate_tag(struct nameidata *nd, struct inode *inode)
340 {
341         tag_t new_tag = 0;
342         struct vfsmount *mnt;
343         int propagate;
344
345         if (!nd)
346                 return;
347         mnt = nd->mnt;
348         if (!mnt)
349                 return;
350
351         propagate = (mnt->mnt_flags & MNT_TAGID);
352         if (propagate)
353                 new_tag = mnt->mnt_tag;
354
355         vxdprintk(VXD_CBIT(tag, 7),
356                 "dx_propagate_tag(%p[#%lu.%d]): %d,%d",
357                 inode, inode->i_ino, inode->i_tag,
358                 new_tag, (propagate)?1:0);
359
360         if (propagate)
361                 inode->i_tag = new_tag;
362 }
363
364 #include <linux/module.h>
365
366 EXPORT_SYMBOL_GPL(__dx_propagate_tag);
367
368 #endif  /* CONFIG_PROPAGATE */
369