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