*
* Virtual Server: File System Support
*
- * Copyright (C) 2004 Herbert Pötzl
+ * Copyright (C) 2004-2007 Herbert Pötzl
*
* V0.01 separated from vcontext V0.05
*
*/
-#include <linux/config.h>
-#include <linux/vinline.h>
-#include <linux/fs.h>
+#include <linux/sched.h>
#include <linux/proc_fs.h>
+#include <linux/devpts_fs.h>
#include <linux/namei.h>
+#include <linux/mount.h>
+#include <linux/parser.h>
+#include <linux/compat.h>
#include <linux/vserver/inode.h>
+#include <linux/vserver/inode_cmd.h>
+#include <linux/vs_base.h>
+#include <linux/vs_tag.h>
#include <asm/errno.h>
#include <asm/uaccess.h>
-static int __vc_get_iattr(struct inode *in, uint32_t *xid, uint32_t *flags, uint32_t *mask)
+static int __vc_get_iattr(struct inode *in, uint32_t *tag, uint32_t *flags, uint32_t *mask)
{
+ struct proc_dir_entry *entry;
+
if (!in || !in->i_sb)
return -ESRCH;
- *flags = IATTR_XID
+ *flags = IATTR_TAG
| (IS_BARRIER(in) ? IATTR_BARRIER : 0)
| (IS_IUNLINK(in) ? IATTR_IUNLINK : 0)
- | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0);
+ | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0);
*mask = IATTR_IUNLINK | IATTR_IMMUTABLE;
if (S_ISDIR(in->i_mode))
*mask |= IATTR_BARRIER;
- if (in->i_sb->s_flags & MS_TAGXID) {
- *xid = in->i_xid;
- *mask |= IATTR_XID;
+ if (IS_TAGGED(in)) {
+ *tag = in->i_tag;
+ *mask |= IATTR_TAG;
}
- if (in->i_sb->s_magic == PROC_SUPER_MAGIC) {
- struct proc_dir_entry *entry = PROC_I(in)->pde;
-
- // check for specific inodes ?
+ switch (in->i_sb->s_magic) {
+ case PROC_SUPER_MAGIC:
+ entry = PROC_I(in)->pde;
+
+ /* check for specific inodes? */
if (entry)
*mask |= IATTR_FLAGS;
if (entry)
- *flags |= (entry->vx_flags & IATTR_FLAGS);
+ *flags |= (entry->vx_flags & IATTR_FLAGS);
else
*flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS);
+ break;
+
+ case DEVPTS_SUPER_MAGIC:
+ *tag = in->i_tag;
+ *mask |= IATTR_TAG;
+ break;
+
+ default:
+ break;
}
return 0;
}
int vc_get_iattr(uint32_t id, void __user *data)
{
struct nameidata nd;
- struct vcmd_ctx_iattr_v1 vc_data;
+ struct vcmd_ctx_iattr_v1 vc_data = { .xid = -1 };
int ret;
- if (!vx_check(0, VX_ADMIN))
- return -ENOSYS;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
&vc_data.xid, &vc_data.flags, &vc_data.mask);
path_release(&nd);
}
+ if (ret)
+ return ret;
+
+ if (copy_to_user (data, &vc_data, sizeof(vc_data)))
+ ret = -EFAULT;
+ return ret;
+}
+
+#ifdef CONFIG_COMPAT
+
+int vc_get_iattr_x32(uint32_t id, void __user *data)
+{
+ struct nameidata nd;
+ struct vcmd_ctx_iattr_v1_x32 vc_data = { .xid = -1 };
+ int ret;
+
+ if (!vx_check(0, VS_ADMIN))
+ return -ENOSYS;
+ if (copy_from_user (&vc_data, data, sizeof(vc_data)))
+ return -EFAULT;
+
+ ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
+ if (!ret) {
+ ret = __vc_get_iattr(nd.dentry->d_inode,
+ &vc_data.xid, &vc_data.flags, &vc_data.mask);
+ path_release(&nd);
+ }
+ if (ret)
+ return ret;
if (copy_to_user (data, &vc_data, sizeof(vc_data)))
ret = -EFAULT;
return ret;
}
-static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uint32_t *mask)
+#endif /* CONFIG_COMPAT */
+
+
+static int __vc_set_iattr(struct dentry *de, uint32_t *tag, uint32_t *flags, uint32_t *mask)
{
struct inode *in = de->d_inode;
- int error = 0, is_proc = 0;
+ int error = 0, is_proc = 0, has_tag = 0;
+ struct iattr attr = { 0 };
if (!in || !in->i_sb)
return -ESRCH;
is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
if ((*mask & IATTR_FLAGS) && !is_proc)
return -EINVAL;
- if ((*mask & IATTR_XID) && !(in->i_sb->s_flags & MS_TAGXID))
+
+ has_tag = IS_TAGGED(in) ||
+ (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC);
+ if ((*mask & IATTR_TAG) && !has_tag)
return -EINVAL;
- down(&in->i_sem);
- if (*mask & IATTR_XID)
- in->i_xid = *xid;
+ mutex_lock(&in->i_mutex);
+ if (*mask & IATTR_TAG) {
+ attr.ia_tag = *tag;
+ attr.ia_valid |= ATTR_TAG;
+ }
if (*mask & IATTR_FLAGS) {
struct proc_dir_entry *entry = PROC_I(in)->pde;
if (entry)
entry->vx_flags = iflags;
}
-
- if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
- struct iattr attr;
-
- attr.ia_valid = ATTR_ATTR_FLAG;
- attr.ia_attr_flags =
- (IS_IMMUTABLE(in) ? ATTR_FLAG_IMMUTABLE : 0) |
- (IS_IUNLINK(in) ? ATTR_FLAG_IUNLINK : 0) |
- (IS_BARRIER(in) ? ATTR_FLAG_BARRIER : 0);
+ if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
if (*mask & IATTR_IMMUTABLE) {
if (*flags & IATTR_IMMUTABLE)
- attr.ia_attr_flags |= ATTR_FLAG_IMMUTABLE;
+ in->i_flags |= S_IMMUTABLE;
else
- attr.ia_attr_flags &= ~ATTR_FLAG_IMMUTABLE;
+ in->i_flags &= ~S_IMMUTABLE;
}
if (*mask & IATTR_IUNLINK) {
if (*flags & IATTR_IUNLINK)
- attr.ia_attr_flags |= ATTR_FLAG_IUNLINK;
+ in->i_flags |= S_IUNLINK;
else
- attr.ia_attr_flags &= ~ATTR_FLAG_IUNLINK;
+ in->i_flags &= ~S_IUNLINK;
}
if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
if (*flags & IATTR_BARRIER)
- attr.ia_attr_flags |= ATTR_FLAG_BARRIER;
+ in->i_flags |= S_BARRIER;
else
- attr.ia_attr_flags &= ~ATTR_FLAG_BARRIER;
+ in->i_flags &= ~S_BARRIER;
+ }
+ if (in->i_op && in->i_op->sync_flags) {
+ error = in->i_op->sync_flags(in);
+ if (error)
+ goto out;
}
+ }
+
+ if (attr.ia_valid) {
if (in->i_op && in->i_op->setattr)
error = in->i_op->setattr(de, &attr);
else {
error = inode_setattr(in, &attr);
}
}
-
- mark_inode_dirty(in);
- up(&in->i_sem);
- return 0;
+
+out:
+ mutex_unlock(&in->i_mutex);
+ return error;
}
int vc_set_iattr(uint32_t id, void __user *data)
struct vcmd_ctx_iattr_v1 vc_data;
int ret;
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
+ if (!capable(CAP_LINUX_IMMUTABLE))
return -EPERM;
if (copy_from_user (&vc_data, data, sizeof(vc_data)))
return -EFAULT;
return ret;
}
+#ifdef CONFIG_COMPAT
-#ifdef CONFIG_VSERVER_LEGACY
-#include <linux/proc_fs.h>
+int vc_set_iattr_x32(uint32_t id, void __user *data)
+{
+ struct nameidata nd;
+ struct vcmd_ctx_iattr_v1_x32 vc_data;
+ int ret;
+
+ if (!capable(CAP_LINUX_IMMUTABLE))
+ return -EPERM;
+ if (copy_from_user (&vc_data, data, sizeof(vc_data)))
+ return -EFAULT;
+
+ ret = user_path_walk_link(compat_ptr(vc_data.name_ptr), &nd);
+ if (!ret) {
+ ret = __vc_set_iattr(nd.dentry,
+ &vc_data.xid, &vc_data.flags, &vc_data.mask);
+ path_release(&nd);
+ }
+
+ if (copy_to_user (data, &vc_data, sizeof(vc_data)))
+ ret = -EFAULT;
+ return ret;
+}
+
+#endif /* CONFIG_COMPAT */
+
+#ifdef CONFIG_VSERVER_LEGACY
#define PROC_DYNAMIC_FIRST 0xF0000000UL
return -ENOTTY;
entry = PROC_I(inode)->pde;
+ if (!entry)
+ return -ENOTTY;
switch(cmd) {
case FIOC_GETXFLG: {
error = -EPERM;
flags = entry->vx_flags;
if (capable(CAP_CONTEXT))
- error = put_user(flags, (int *) arg);
+ error = put_user(flags, (int __user *) arg);
break;
}
case FIOC_SETXFLG: {
if (IS_RDONLY(inode))
break;
error = -EFAULT;
- if (get_user(flags, (int *) arg))
+ if (get_user(flags, (int __user *) arg))
break;
error = 0;
entry->vx_flags = flags;
}
return error;
}
-#endif
+#endif /* CONFIG_VSERVER_LEGACY */
+
+#ifdef CONFIG_PROPAGATE
+
+int dx_parse_tag(char *string, tag_t *tag, int remove)
+{
+ static match_table_t tokens = {
+ {1, "tagid=%u"},
+ {0, NULL}
+ };
+ substring_t args[MAX_OPT_ARGS];
+ int token, option = 0;
+
+ if (!string)
+ return 0;
+
+ token = match_token(string, tokens, args);
+ if (token && tag && !match_int(args, &option))
+ *tag = option;
+
+ vxdprintk(VXD_CBIT(tag, 7),
+ "dx_parse_tag(»%s«): %d:#%d",
+ string, token, option);
+
+ if ((token == 1) && remove) {
+ char *p = strstr(string, "tagid=");
+ char *q = p;
+
+ if (p) {
+ while (*q != '\0' && *q != ',')
+ q++;
+ while (*q)
+ *p++ = *q++;
+ while (*p)
+ *p++ = '\0';
+ }
+ }
+ return token;
+}
+
+void __dx_propagate_tag(struct nameidata *nd, struct inode *inode)
+{
+ tag_t new_tag = 0;
+ struct vfsmount *mnt;
+ int propagate;
+
+ if (!nd)
+ return;
+ mnt = nd->mnt;
+ if (!mnt)
+ return;
+
+ propagate = (mnt->mnt_flags & MNT_TAGID);
+ if (propagate)
+ new_tag = mnt->mnt_tag;
+
+ vxdprintk(VXD_CBIT(tag, 7),
+ "dx_propagate_tag(%p[#%lu.%d]): %d,%d",
+ inode, inode->i_ino, inode->i_tag,
+ new_tag, (propagate)?1:0);
+
+ if (propagate)
+ inode->i_tag = new_tag;
+}
+
+#include <linux/module.h>
+
+EXPORT_SYMBOL_GPL(__dx_propagate_tag);
+
+#endif /* CONFIG_PROPAGATE */