Change #include statements to match the fc+vs version.
[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 /* required by PLK */
253 int vc_iattr_ioctl(struct dentry *de, unsigned int cmd, unsigned long arg)
254 {
255         void __user *data = (void __user *)arg;
256         struct vcmd_ctx_iattr_v1 vc_data;
257         int ret;
258
259         /*
260          * I don't think we need any dget/dput pairs in here as long as
261          * this function is always called from sys_ioctl i.e., de is
262          * a field of a struct file that is guaranteed not to be freed.
263          */
264         if (cmd == FIOC_SETIATTR) {
265                 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
266                         return -EPERM;
267                 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
268                         return -EFAULT;
269                 ret = __vc_set_iattr(de,
270                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
271         }
272         else {
273                 if (!vx_check(0, VS_ADMIN))
274                         return -ENOSYS;
275                 ret = __vc_get_iattr(de->d_inode,
276                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
277         }
278
279         if (!ret && copy_to_user (data, &vc_data, sizeof(vc_data)))
280                 ret = -EFAULT;
281         return ret;
282 }
283
284 #ifdef  CONFIG_VSERVER_LEGACY
285
286 #define PROC_DYNAMIC_FIRST 0xF0000000UL
287
288 int vx_proc_ioctl(struct inode * inode, struct file * filp,
289         unsigned int cmd, unsigned long arg)
290 {
291         struct proc_dir_entry *entry;
292         int error = 0;
293         int flags;
294
295         if (inode->i_ino < PROC_DYNAMIC_FIRST)
296                 return -ENOTTY;
297
298         entry = PROC_I(inode)->pde;
299         if (!entry)
300                 return -ENOTTY;
301
302         switch(cmd) {
303         case FIOC_GETXFLG: {
304                 /* fixme: if stealth, return -ENOTTY */
305                 error = -EPERM;
306                 flags = entry->vx_flags;
307                 if (capable(CAP_CONTEXT))
308                         error = put_user(flags, (int __user *) arg);
309                 break;
310         }
311         case FIOC_SETXFLG: {
312                 /* fixme: if stealth, return -ENOTTY */
313                 error = -EPERM;
314                 if (!capable(CAP_CONTEXT))
315                         break;
316                 error = -EROFS;
317                 if (IS_RDONLY(inode))
318                         break;
319                 error = -EFAULT;
320                 if (get_user(flags, (int __user *) arg))
321                         break;
322                 error = 0;
323                 entry->vx_flags = flags;
324                 break;
325         }
326         default:
327                 return -ENOTTY;
328         }
329         return error;
330 }
331 #endif  /* CONFIG_VSERVER_LEGACY */
332
333 #ifdef  CONFIG_PROPAGATE
334
335 int dx_parse_tag(char *string, tag_t *tag, int remove)
336 {
337         static match_table_t tokens = {
338                 {1, "tagid=%u"},
339                 {0, NULL}
340         };
341         substring_t args[MAX_OPT_ARGS];
342         int token, option = 0;
343
344         if (!string)
345                 return 0;
346
347         token = match_token(string, tokens, args);
348         if (token && tag && !match_int(args, &option))
349                 *tag = option;
350
351         vxdprintk(VXD_CBIT(tag, 7),
352                 "dx_parse_tag(»%s«): %d:#%d",
353                 string, token, option);
354
355         if ((token == 1) && remove) {
356                 char *p = strstr(string, "tagid=");
357                 char *q = p;
358
359                 if (p) {
360                         while (*q != '\0' && *q != ',')
361                                 q++;
362                         while (*q)
363                                 *p++ = *q++;
364                         while (*p)
365                                 *p++ = '\0';
366                 }
367         }
368         return token;
369 }
370
371 void __dx_propagate_tag(struct nameidata *nd, struct inode *inode)
372 {
373         tag_t new_tag = 0;
374         struct vfsmount *mnt;
375         int propagate;
376
377         if (!nd)
378                 return;
379         mnt = nd->mnt;
380         if (!mnt)
381                 return;
382
383         propagate = (mnt->mnt_flags & MNT_TAGID);
384         if (propagate)
385                 new_tag = mnt->mnt_tag;
386
387         vxdprintk(VXD_CBIT(tag, 7),
388                 "dx_propagate_tag(%p[#%lu.%d]): %d,%d",
389                 inode, inode->i_ino, inode->i_tag,
390                 new_tag, (propagate)?1:0);
391
392         if (propagate)
393                 inode->i_tag = new_tag;
394 }
395
396 #include <linux/module.h>
397
398 EXPORT_SYMBOL_GPL(__dx_propagate_tag);
399
400 #endif  /* CONFIG_PROPAGATE */
401