bb41a144b7835eb67601b96bdeaa1ff1cc084e7e
[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/config.h>
13 #include <linux/sched.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/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 (in->i_sb->s_flags & MS_TAGXID) {
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
91         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
92                 ret = -EFAULT;
93         return ret;
94 }
95
96 static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uint32_t *mask)
97 {
98         struct inode *in = de->d_inode;
99         int error = 0, is_proc = 0, has_xid = 0;
100
101         if (!in || !in->i_sb)
102                 return -ESRCH;
103
104         is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
105         if ((*mask & IATTR_FLAGS) && !is_proc)
106                 return -EINVAL;
107
108         has_xid = (in->i_sb->s_flags & MS_TAGXID) ||
109                 (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC);
110         if ((*mask & IATTR_XID) && !has_xid)
111                 return -EINVAL;
112
113         down(&in->i_sem);
114         if (*mask & IATTR_XID)
115                 in->i_xid = *xid;
116
117         if (*mask & IATTR_FLAGS) {
118                 struct proc_dir_entry *entry = PROC_I(in)->pde;
119                 unsigned int iflags = PROC_I(in)->vx_flags;
120
121                 iflags = (iflags & ~(*mask & IATTR_FLAGS))
122                         | (*flags & IATTR_FLAGS);
123                 PROC_I(in)->vx_flags = iflags;
124                 if (entry)
125                         entry->vx_flags = iflags;
126         }
127
128         if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
129                 struct iattr attr;
130
131                 attr.ia_valid = ATTR_ATTR_FLAG;
132                 attr.ia_attr_flags =
133                         (IS_IMMUTABLE(in) ? ATTR_FLAG_IMMUTABLE : 0) |
134                         (IS_IUNLINK(in) ? ATTR_FLAG_IUNLINK : 0) |
135                         (IS_BARRIER(in) ? ATTR_FLAG_BARRIER : 0);
136
137                 if (*mask & IATTR_IMMUTABLE) {
138                         if (*flags & IATTR_IMMUTABLE)
139                                 attr.ia_attr_flags |= ATTR_FLAG_IMMUTABLE;
140                         else
141                                 attr.ia_attr_flags &= ~ATTR_FLAG_IMMUTABLE;
142                 }
143                 if (*mask & IATTR_IUNLINK) {
144                         if (*flags & IATTR_IUNLINK)
145                                 attr.ia_attr_flags |= ATTR_FLAG_IUNLINK;
146                         else
147                                 attr.ia_attr_flags &= ~ATTR_FLAG_IUNLINK;
148                 }
149                 if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
150                         if (*flags & IATTR_BARRIER)
151                                 attr.ia_attr_flags |= ATTR_FLAG_BARRIER;
152                         else
153                                 attr.ia_attr_flags &= ~ATTR_FLAG_BARRIER;
154                 }
155                 if (in->i_op && in->i_op->setattr)
156                         error = in->i_op->setattr(de, &attr);
157                 else {
158                         error = inode_change_ok(in, &attr);
159                         if (!error)
160                                 error = inode_setattr(in, &attr);
161                 }
162         }
163
164         mark_inode_dirty(in);
165         up(&in->i_sem);
166         return 0;
167 }
168
169 int vc_set_iattr(uint32_t id, void __user *data)
170 {
171         struct nameidata nd;
172         struct vcmd_ctx_iattr_v1 vc_data;
173         int ret;
174
175         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
176                 return -EPERM;
177         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
178                 return -EFAULT;
179
180         ret = user_path_walk_link(vc_data.name, &nd);
181         if (!ret) {
182                 ret = __vc_set_iattr(nd.dentry,
183                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
184                 path_release(&nd);
185         }
186
187         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
188                 ret = -EFAULT;
189         return ret;
190 }
191
192
193 #ifdef  CONFIG_VSERVER_LEGACY
194
195 #define PROC_DYNAMIC_FIRST 0xF0000000UL
196
197 int vx_proc_ioctl(struct inode * inode, struct file * filp,
198         unsigned int cmd, unsigned long arg)
199 {
200         struct proc_dir_entry *entry;
201         int error = 0;
202         int flags;
203
204         if (inode->i_ino < PROC_DYNAMIC_FIRST)
205                 return -ENOTTY;
206
207         entry = PROC_I(inode)->pde;
208         if (!entry)
209                 return -ENOTTY;
210
211         switch(cmd) {
212         case FIOC_GETXFLG: {
213                 /* fixme: if stealth, return -ENOTTY */
214                 error = -EPERM;
215                 flags = entry->vx_flags;
216                 if (capable(CAP_CONTEXT))
217                         error = put_user(flags, (int *) arg);
218                 break;
219         }
220         case FIOC_SETXFLG: {
221                 /* fixme: if stealth, return -ENOTTY */
222                 error = -EPERM;
223                 if (!capable(CAP_CONTEXT))
224                         break;
225                 error = -EROFS;
226                 if (IS_RDONLY(inode))
227                         break;
228                 error = -EFAULT;
229                 if (get_user(flags, (int *) arg))
230                         break;
231                 error = 0;
232                 entry->vx_flags = flags;
233                 break;
234         }
235         default:
236                 return -ENOTTY;
237         }
238         return error;
239 }
240 #endif
241
242
243 int vx_parse_xid(char *string, xid_t *xid, int remove)
244 {
245         static match_table_t tokens = {
246                 {1, "xid=%u"},
247                 {0, NULL}
248         };
249         substring_t args[MAX_OPT_ARGS];
250         int token, option = 0;
251
252         if (!string)
253                 return 0;
254
255         token = match_token(string, tokens, args);
256         if (token && xid && !match_int(args, &option))
257                 *xid = option;
258
259         vxdprintk(VXD_CBIT(xid, 7),
260                 "vx_parse_xid(»%s«): %d:#%d",
261                 string, token, option);
262
263         if (token && remove) {
264                 char *p = strstr(string, "xid=");
265                 char *q = p;
266
267                 if (p) {
268                         while (*q != '\0' && *q != ',')
269                                 q++;
270                         while (*q)
271                                 *p++ = *q++;
272                         while (*p)
273                                 *p++ = '\0';
274                 }
275         }
276         return token;
277 }
278
279 void vx_propagate_xid(struct nameidata *nd, struct inode *inode)
280 {
281         xid_t new_xid = 0;
282         struct vfsmount *mnt;
283         int propagate;
284
285         if (!nd)
286                 return;
287         mnt = nd->mnt;
288         if (!mnt)
289                 return;
290
291         propagate = (mnt->mnt_flags & MNT_XID);
292         if (propagate)
293                 new_xid = mnt->mnt_xid;
294
295         vxdprintk(VXD_CBIT(xid, 7),
296                 "vx_propagate_xid(%p[#%lu.%d]): %d,%d",
297                 inode, inode->i_ino, inode->i_xid,
298                 new_xid, (propagate)?1:0);
299
300         if (propagate)
301                 inode->i_xid = new_xid;
302 }
303
304 #include <linux/module.h>
305
306 EXPORT_SYMBOL_GPL(vx_propagate_xid);
307