fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / kernel / vserver / inode.c
index 87e2849..274d05e 100644 (file)
@@ -3,52 +3,69 @@
  *
  *  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;
 }
@@ -56,11 +73,9 @@ static int __vc_get_iattr(struct inode *in, uint32_t *xid, uint32_t *flags, uint
 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;
 
@@ -70,16 +85,49 @@ int vc_get_iattr(uint32_t id, void __user *data)
                        &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;
@@ -87,12 +135,17 @@ static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uin
        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;
@@ -104,34 +157,34 @@ static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uin
                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 {
@@ -140,10 +193,10 @@ static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uin
                                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)
@@ -152,7 +205,7 @@ 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;
@@ -169,9 +222,34 @@ int vc_set_iattr(uint32_t id, void __user *data)
        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
 
@@ -186,6 +264,8 @@ int vx_proc_ioctl(struct inode * inode, struct file * filp,
                return -ENOTTY;
 
        entry = PROC_I(inode)->pde;
+       if (!entry)
+               return -ENOTTY;
 
        switch(cmd) {
        case FIOC_GETXFLG: {
@@ -193,7 +273,7 @@ int vx_proc_ioctl(struct inode * inode, struct file * filp,
                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: {
@@ -205,7 +285,7 @@ int vx_proc_ioctl(struct inode * inode, struct file * filp,
                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;
@@ -216,5 +296,74 @@ int vx_proc_ioctl(struct inode * inode, struct file * filp,
        }
        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 */