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