2 * linux/kernel/vserver/inode.c
4 * Virtual Server: File System Support
6 * Copyright (C) 2004-2007 Herbert Pötzl
8 * V0.01 separated from vcontext V0.05
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>
25 #include <asm/errno.h>
26 #include <asm/uaccess.h>
29 static int __vc_get_iattr(struct inode *in, uint32_t *tag, uint32_t *flags, uint32_t *mask)
31 struct proc_dir_entry *entry;
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;
42 if (S_ISDIR(in->i_mode))
43 *mask |= IATTR_BARRIER;
50 switch (in->i_sb->s_magic) {
51 case PROC_SUPER_MAGIC:
52 entry = PROC_I(in)->pde;
54 /* check for specific inodes? */
58 *flags |= (entry->vx_flags & IATTR_FLAGS);
60 *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS);
63 case DEVPTS_SUPER_MAGIC:
74 int vc_get_iattr(uint32_t id, void __user *data)
77 struct vcmd_ctx_iattr_v1 vc_data = { .xid = -1 };
80 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
83 ret = user_path_walk_link(vc_data.name, &nd);
85 ret = __vc_get_iattr(nd.dentry->d_inode,
86 &vc_data.xid, &vc_data.flags, &vc_data.mask);
92 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
99 int vc_get_iattr_x32(uint32_t id, void __user *data)
102 struct vcmd_ctx_iattr_v1_x32 vc_data = { .xid = -1 };
105 if (!vx_check(0, VS_ADMIN))
107 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
110 ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
112 ret = __vc_get_iattr(nd.dentry->d_inode,
113 &vc_data.xid, &vc_data.flags, &vc_data.mask);
119 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
124 #endif /* CONFIG_COMPAT */
127 int vc_fget_iattr(uint32_t fd, void __user *data)
130 struct vcmd_ctx_fiattr_v0 vc_data = { .xid = -1 };
133 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
137 if (!filp || !filp->f_dentry || !filp->f_dentry->d_inode)
140 ret = __vc_get_iattr(filp->f_dentry->d_inode,
141 &vc_data.xid, &vc_data.flags, &vc_data.mask);
145 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
151 static int __vc_set_iattr(struct dentry *de, uint32_t *tag, uint32_t *flags, uint32_t *mask)
153 struct inode *in = de->d_inode;
154 int error = 0, is_proc = 0, has_tag = 0;
155 struct iattr attr = { 0 };
157 if (!in || !in->i_sb)
160 is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
161 if ((*mask & IATTR_FLAGS) && !is_proc)
164 has_tag = IS_TAGGED(in) ||
165 (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC);
166 if ((*mask & IATTR_TAG) && !has_tag)
169 mutex_lock(&in->i_mutex);
170 if (*mask & IATTR_TAG) {
172 attr.ia_valid |= ATTR_TAG;
175 if (*mask & IATTR_FLAGS) {
176 struct proc_dir_entry *entry = PROC_I(in)->pde;
177 unsigned int iflags = PROC_I(in)->vx_flags;
179 iflags = (iflags & ~(*mask & IATTR_FLAGS))
180 | (*flags & IATTR_FLAGS);
181 PROC_I(in)->vx_flags = iflags;
183 entry->vx_flags = iflags;
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;
191 in->i_flags &= ~S_IMMUTABLE;
193 if (*mask & IATTR_IUNLINK) {
194 if (*flags & IATTR_IUNLINK)
195 in->i_flags |= S_IUNLINK;
197 in->i_flags &= ~S_IUNLINK;
199 if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
200 if (*flags & IATTR_BARRIER)
201 in->i_flags |= S_BARRIER;
203 in->i_flags &= ~S_BARRIER;
205 if (in->i_op && in->i_op->sync_flags) {
206 error = in->i_op->sync_flags(in);
213 if (in->i_op && in->i_op->setattr)
214 error = in->i_op->setattr(de, &attr);
216 error = inode_change_ok(in, &attr);
218 error = inode_setattr(in, &attr);
223 mutex_unlock(&in->i_mutex);
227 int vc_set_iattr(uint32_t id, void __user *data)
230 struct vcmd_ctx_iattr_v1 vc_data;
233 if (!capable(CAP_LINUX_IMMUTABLE))
235 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
238 ret = user_path_walk_link(vc_data.name, &nd);
240 ret = __vc_set_iattr(nd.dentry,
241 &vc_data.xid, &vc_data.flags, &vc_data.mask);
245 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
252 int vc_set_iattr_x32(uint32_t id, void __user *data)
255 struct vcmd_ctx_iattr_v1_x32 vc_data;
258 if (!capable(CAP_LINUX_IMMUTABLE))
260 if (copy_from_user (&vc_data, data, sizeof(vc_data)))
263 ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
265 ret = __vc_set_iattr(nd.dentry,
266 &vc_data.xid, &vc_data.flags, &vc_data.mask);
270 if (copy_to_user (data, &vc_data, sizeof(vc_data)))
275 #endif /* CONFIG_COMPAT */
277 int vc_fset_iattr(uint32_t fd, void __user *data)
280 struct vcmd_ctx_fiattr_v0 vc_data;
283 if (!capable(CAP_LINUX_IMMUTABLE))
285 if (copy_from_user(&vc_data, data, sizeof(vc_data)))
289 if (!filp || !filp->f_dentry || !filp->f_dentry->d_inode)
292 ret = __vc_set_iattr(filp->f_dentry, &vc_data.xid,
293 &vc_data.flags, &vc_data.mask);
297 if (copy_to_user(data, &vc_data, sizeof(vc_data)))
302 #ifdef CONFIG_VSERVER_LEGACY
304 #define PROC_DYNAMIC_FIRST 0xF0000000UL
306 int vx_proc_ioctl(struct inode * inode, struct file * filp,
307 unsigned int cmd, unsigned long arg)
309 struct proc_dir_entry *entry;
313 if (inode->i_ino < PROC_DYNAMIC_FIRST)
316 entry = PROC_I(inode)->pde;
322 /* fixme: if stealth, return -ENOTTY */
324 flags = entry->vx_flags;
325 if (capable(CAP_CONTEXT))
326 error = put_user(flags, (int __user *) arg);
330 /* fixme: if stealth, return -ENOTTY */
332 if (!capable(CAP_CONTEXT))
335 if (IS_RDONLY(inode))
338 if (get_user(flags, (int __user *) arg))
341 entry->vx_flags = flags;
349 #endif /* CONFIG_VSERVER_LEGACY */
351 #ifdef CONFIG_PROPAGATE
353 int dx_parse_tag(char *string, tag_t *tag, int remove)
355 static match_table_t tokens = {
359 substring_t args[MAX_OPT_ARGS];
360 int token, option = 0;
365 token = match_token(string, tokens, args);
366 if (token && tag && !match_int(args, &option))
369 vxdprintk(VXD_CBIT(tag, 7),
370 "dx_parse_tag(»%s«): %d:#%d",
371 string, token, option);
373 if ((token == 1) && remove) {
374 char *p = strstr(string, "tagid=");
378 while (*q != '\0' && *q != ',')
389 void __dx_propagate_tag(struct nameidata *nd, struct inode *inode)
392 struct vfsmount *mnt;
401 propagate = (mnt->mnt_flags & MNT_TAGID);
403 new_tag = mnt->mnt_tag;
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);
411 inode->i_tag = new_tag;
414 #include <linux/module.h>
416 EXPORT_SYMBOL_GPL(__dx_propagate_tag);
418 #endif /* CONFIG_PROPAGATE */