backported vs2.1.x fix to irq handling, which caused incorrect scheduler behavior
[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-2005  Herbert Pötzl
7  *
8  *  V0.01  separated from vcontext V0.05
9  *
10  */
11
12 #include <linux/sched.h>
13 #include <linux/vs_base.h>
14 #include <linux/vs_context.h>
15 #include <linux/proc_fs.h>
16 #include <linux/devpts_fs.h>
17 #include <linux/namei.h>
18 #include <linux/mount.h>
19 #include <linux/parser.h>
20 #include <linux/compat.h>
21 #include <linux/vserver/inode.h>
22 #include <linux/vserver/inode_cmd.h>
23 #include <linux/vserver/xid.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 *xid, 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_XID
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_TAGXID(in)) {
46                 *xid = in->i_xid;
47                 *mask |= IATTR_XID;
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                 *xid = in->i_xid;
65                 *mask |= IATTR_XID;
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 (!vx_check(0, VX_ADMIN))
81                 return -ENOSYS;
82         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
83                 return -EFAULT;
84
85         ret = user_path_walk_link(vc_data.name, &nd);
86         if (!ret) {
87                 ret = __vc_get_iattr(nd.dentry->d_inode,
88                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
89                 path_release(&nd);
90         }
91         if (ret)
92                 return ret;
93
94         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
95                 ret = -EFAULT;
96         return ret;
97 }
98
99 #ifdef  CONFIG_COMPAT
100
101 int vc_get_iattr_x32(uint32_t id, void __user *data)
102 {
103         struct nameidata nd;
104         struct vcmd_ctx_iattr_v1_x32 vc_data = { .xid = -1 };
105         int ret;
106
107         if (!vx_check(0, VX_ADMIN))
108                 return -ENOSYS;
109         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
110                 return -EFAULT;
111
112         ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
113         if (!ret) {
114                 ret = __vc_get_iattr(nd.dentry->d_inode,
115                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
116                 path_release(&nd);
117         }
118         if (ret)
119                 return ret;
120
121         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
122                 ret = -EFAULT;
123         return ret;
124 }
125
126 #endif  /* CONFIG_COMPAT */
127
128
129 static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uint32_t *mask)
130 {
131         struct inode *in = de->d_inode;
132         int error = 0, is_proc = 0, has_xid = 0;
133         struct iattr attr = { 0 };
134
135         if (!in || !in->i_sb)
136                 return -ESRCH;
137
138         is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
139         if ((*mask & IATTR_FLAGS) && !is_proc)
140                 return -EINVAL;
141
142         has_xid = IS_TAGXID(in) ||
143                 (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC);
144         if ((*mask & IATTR_XID) && !has_xid)
145                 return -EINVAL;
146
147         mutex_lock(&in->i_mutex);
148         if (*mask & IATTR_XID) {
149                 attr.ia_xid = *xid;
150                 attr.ia_valid |= ATTR_XID;
151         }
152
153         if (*mask & IATTR_FLAGS) {
154                 struct proc_dir_entry *entry = PROC_I(in)->pde;
155                 unsigned int iflags = PROC_I(in)->vx_flags;
156
157                 iflags = (iflags & ~(*mask & IATTR_FLAGS))
158                         | (*flags & IATTR_FLAGS);
159                 PROC_I(in)->vx_flags = iflags;
160                 if (entry)
161                         entry->vx_flags = iflags;
162         }
163
164         if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
165                 if (*mask & IATTR_IMMUTABLE) {
166                         if (*flags & IATTR_IMMUTABLE)
167                                 in->i_flags |= S_IMMUTABLE;
168                         else
169                                 in->i_flags &= ~S_IMMUTABLE;
170                 }
171                 if (*mask & IATTR_IUNLINK) {
172                         if (*flags & IATTR_IUNLINK)
173                                 in->i_flags |= S_IUNLINK;
174                         else
175                                 in->i_flags &= ~S_IUNLINK;
176                 }
177                 if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
178                         if (*flags & IATTR_BARRIER)
179                                 in->i_flags |= S_BARRIER;
180                         else
181                                 in->i_flags &= ~S_BARRIER;
182                 }
183                 if (in->i_op && in->i_op->sync_flags) {
184                         error = in->i_op->sync_flags(in);
185                         if (error)
186                                 goto out;
187                 }
188         }
189
190         if (attr.ia_valid) {
191                 if (in->i_op && in->i_op->setattr)
192                         error = in->i_op->setattr(de, &attr);
193                 else {
194                         error = inode_change_ok(in, &attr);
195                         if (!error)
196                                 error = inode_setattr(in, &attr);
197                 }
198         }
199
200 out:
201         mutex_unlock(&in->i_mutex);
202         return error;
203 }
204
205 int vc_set_iattr(uint32_t id, void __user *data)
206 {
207         struct nameidata nd;
208         struct vcmd_ctx_iattr_v1 vc_data;
209         int ret;
210
211         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
212                 return -EPERM;
213         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
214                 return -EFAULT;
215
216         ret = user_path_walk_link(vc_data.name, &nd);
217         if (!ret) {
218                 ret = __vc_set_iattr(nd.dentry,
219                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
220                 path_release(&nd);
221         }
222
223         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
224                 ret = -EFAULT;
225         return ret;
226 }
227
228 #ifdef  CONFIG_COMPAT
229
230 int vc_set_iattr_x32(uint32_t id, void __user *data)
231 {
232         struct nameidata nd;
233         struct vcmd_ctx_iattr_v1_x32 vc_data;
234         int ret;
235
236         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
237                 return -EPERM;
238         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
239                 return -EFAULT;
240
241         ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
242         if (!ret) {
243                 ret = __vc_set_iattr(nd.dentry,
244                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
245                 path_release(&nd);
246         }
247
248         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
249                 ret = -EFAULT;
250         return ret;
251 }
252
253 #endif  /* CONFIG_COMPAT */
254
255 /* required by PLK */
256 int vc_iattr_ioctl(struct dentry *de, unsigned int cmd, unsigned long arg)
257 {
258         void __user *data = (void __user *)arg;
259         struct vcmd_ctx_iattr_v1 vc_data;
260         int ret;
261
262         /*
263          * I don't think we need any dget/dput pairs in here as long as
264          * this function is always called from sys_ioctl i.e., de is
265          * a field of a struct file that is guaranteed not to be freed.
266          */
267         if (cmd == FIOC_SETIATTR) {
268                 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
269                         return -EPERM;
270                 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
271                         return -EFAULT;
272                 ret = __vc_set_iattr(de,
273                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
274         }
275         else {
276                 if (!vx_check(0, VX_ADMIN))
277                         return -ENOSYS;
278                 ret = __vc_get_iattr(de->d_inode,
279                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
280         }
281
282         if (!ret && copy_to_user (data, &vc_data, sizeof(vc_data)))
283                 ret = -EFAULT;
284         return ret;
285 }
286
287 #ifdef  CONFIG_VSERVER_LEGACY
288
289 #define PROC_DYNAMIC_FIRST 0xF0000000UL
290
291 int vx_proc_ioctl(struct inode * inode, struct file * filp,
292         unsigned int cmd, unsigned long arg)
293 {
294         struct proc_dir_entry *entry;
295         int error = 0;
296         int flags;
297
298         if (inode->i_ino < PROC_DYNAMIC_FIRST)
299                 return -ENOTTY;
300
301         entry = PROC_I(inode)->pde;
302         if (!entry)
303                 return -ENOTTY;
304
305         switch(cmd) {
306         case FIOC_GETXFLG: {
307                 /* fixme: if stealth, return -ENOTTY */
308                 error = -EPERM;
309                 flags = entry->vx_flags;
310                 if (capable(CAP_CONTEXT))
311                         error = put_user(flags, (int __user *) arg);
312                 break;
313         }
314         case FIOC_SETXFLG: {
315                 /* fixme: if stealth, return -ENOTTY */
316                 error = -EPERM;
317                 if (!capable(CAP_CONTEXT))
318                         break;
319                 error = -EROFS;
320                 if (IS_RDONLY(inode))
321                         break;
322                 error = -EFAULT;
323                 if (get_user(flags, (int __user *) arg))
324                         break;
325                 error = 0;
326                 entry->vx_flags = flags;
327                 break;
328         }
329         default:
330                 return -ENOTTY;
331         }
332         return error;
333 }
334 #endif
335
336
337 int vx_parse_xid(char *string, xid_t *xid, int remove)
338 {
339         static match_table_t tokens = {
340                 {1, "xid=%u"},
341                 {0, NULL}
342         };
343         substring_t args[MAX_OPT_ARGS];
344         int token, option = 0;
345
346         if (!string)
347                 return 0;
348
349         token = match_token(string, tokens, args);
350         if (token && xid && !match_int(args, &option))
351                 *xid = option;
352
353         vxdprintk(VXD_CBIT(xid, 7),
354                 "vx_parse_xid(»%s«): %d:#%d",
355                 string, token, option);
356
357         if (token && remove) {
358                 char *p = strstr(string, "xid=");
359                 char *q = p;
360
361                 if (p) {
362                         while (*q != '\0' && *q != ',')
363                                 q++;
364                         while (*q)
365                                 *p++ = *q++;
366                         while (*p)
367                                 *p++ = '\0';
368                 }
369         }
370         return token;
371 }
372
373 void vx_propagate_xid(struct nameidata *nd, struct inode *inode)
374 {
375         xid_t new_xid = 0;
376         struct vfsmount *mnt;
377         int propagate;
378
379         if (!nd)
380                 return;
381         mnt = nd->mnt;
382         if (!mnt)
383                 return;
384
385         propagate = (mnt->mnt_flags & MNT_XID);
386         if (propagate)
387                 new_xid = mnt->mnt_xid;
388
389         vxdprintk(VXD_CBIT(xid, 7),
390                 "vx_propagate_xid(%p[#%lu.%d]): %d,%d",
391                 inode, inode->i_ino, inode->i_xid,
392                 new_xid, (propagate)?1:0);
393
394         if (propagate)
395                 inode->i_xid = new_xid;
396 }
397
398 #include <linux/module.h>
399
400 EXPORT_SYMBOL_GPL(vx_propagate_xid);
401