This commit was manufactured by cvs2svn to create branch 'vserver'.
[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  Herbert Pƶtzl
7  *
8  *  V0.01  separated from vcontext V0.05
9  *
10  */
11
12 #include <linux/config.h>
13 #include <linux/vinline.h>
14 #include <linux/fs.h>
15 #include <linux/proc_fs.h>
16 #include <linux/namei.h>
17 #include <linux/vserver/inode.h>
18
19 #include <asm/errno.h>
20 #include <asm/uaccess.h>
21
22
23 static int __vc_get_iattr(struct inode *in, uint32_t *xid, uint32_t *flags, uint32_t *mask)
24 {
25         if (!in || !in->i_sb)
26                 return -ESRCH;
27
28         *flags = IATTR_XID
29                 | (IS_BARRIER(in) ? IATTR_BARRIER : 0)
30                 | (IS_IUNLINK(in) ? IATTR_IUNLINK : 0)
31                 | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0);     
32         *mask = IATTR_IUNLINK | IATTR_IMMUTABLE;
33
34         if (S_ISDIR(in->i_mode))
35                 *mask |= IATTR_BARRIER;
36
37         if (in->i_sb->s_flags & MS_TAGXID) {
38                 *xid = in->i_xid;
39                 *mask |= IATTR_XID;
40         }
41
42         if (in->i_sb->s_magic == PROC_SUPER_MAGIC) {
43                 struct proc_dir_entry *entry = PROC_I(in)->pde;
44                 
45                 // check for specific inodes ?
46                 if (entry)
47                         *mask |= IATTR_FLAGS;
48                 if (entry)
49                         *flags |= (entry->vx_flags & IATTR_FLAGS);      
50                 else
51                         *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS);
52         }
53         return 0;
54 }
55
56 int vc_get_iattr(uint32_t id, void __user *data)
57 {
58         struct nameidata nd;
59         struct vcmd_ctx_iattr_v1 vc_data;
60         int ret;
61
62         if (!vx_check(0, VX_ADMIN))
63                 return -ENOSYS;
64         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
65                 return -EFAULT;
66
67         ret = user_path_walk_link(vc_data.name, &nd);
68         if (!ret) {
69                 ret = __vc_get_iattr(nd.dentry->d_inode,
70                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
71                 path_release(&nd);
72         }
73
74         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
75                 ret = -EFAULT;
76         return ret;
77 }
78
79 static int __vc_set_iattr(struct dentry *de, uint32_t *xid, uint32_t *flags, uint32_t *mask)
80 {
81         struct inode *in = de->d_inode;
82         int error = 0, is_proc = 0;
83
84         if (!in || !in->i_sb)
85                 return -ESRCH;
86
87         is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC);
88         if ((*mask & IATTR_FLAGS) && !is_proc)
89                 return -EINVAL;
90         if ((*mask & IATTR_XID) && !(in->i_sb->s_flags & MS_TAGXID))
91                 return -EINVAL;
92
93         down(&in->i_sem);
94         if (*mask & IATTR_XID)
95                 in->i_xid = *xid;
96
97         if (*mask & IATTR_FLAGS) {
98                 struct proc_dir_entry *entry = PROC_I(in)->pde;
99                 unsigned int iflags = PROC_I(in)->vx_flags;
100
101                 iflags = (iflags & ~(*mask & IATTR_FLAGS))
102                         | (*flags & IATTR_FLAGS);
103                 PROC_I(in)->vx_flags = iflags;
104                 if (entry)
105                         entry->vx_flags = iflags;
106         }
107         
108         if (*mask & (IATTR_BARRIER | IATTR_IUNLINK | IATTR_IMMUTABLE)) {
109                 struct iattr attr;
110
111                 attr.ia_valid = ATTR_ATTR_FLAG;
112                 attr.ia_attr_flags =
113                         (IS_IMMUTABLE(in) ? ATTR_FLAG_IMMUTABLE : 0) |
114                         (IS_IUNLINK(in) ? ATTR_FLAG_IUNLINK : 0) |
115                         (IS_BARRIER(in) ? ATTR_FLAG_BARRIER : 0);
116
117                 if (*mask & IATTR_IMMUTABLE) {
118                         if (*flags & IATTR_IMMUTABLE)
119                                 attr.ia_attr_flags |= ATTR_FLAG_IMMUTABLE;
120                         else
121                                 attr.ia_attr_flags &= ~ATTR_FLAG_IMMUTABLE;
122                 }
123                 if (*mask & IATTR_IUNLINK) {
124                         if (*flags & IATTR_IUNLINK)
125                                 attr.ia_attr_flags |= ATTR_FLAG_IUNLINK;
126                         else
127                                 attr.ia_attr_flags &= ~ATTR_FLAG_IUNLINK;
128                 }
129                 if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) {
130                         if (*flags & IATTR_BARRIER)
131                                 attr.ia_attr_flags |= ATTR_FLAG_BARRIER;
132                         else
133                                 attr.ia_attr_flags &= ~ATTR_FLAG_BARRIER;
134                 }
135                 if (in->i_op && in->i_op->setattr)
136                         error = in->i_op->setattr(de, &attr);
137                 else {
138                         error = inode_change_ok(in, &attr);
139                         if (!error)
140                                 error = inode_setattr(in, &attr);
141                 }
142         }
143                 
144         mark_inode_dirty(in);
145         up(&in->i_sem);
146         return 0;
147 }
148
149 int vc_set_iattr(uint32_t id, void __user *data)
150 {
151         struct nameidata nd;
152         struct vcmd_ctx_iattr_v1 vc_data;
153         int ret;
154
155         if (!capable(CAP_SYS_ADMIN) || !capable(CAP_LINUX_IMMUTABLE))
156                 return -EPERM;
157         if (copy_from_user (&vc_data, data, sizeof(vc_data)))
158                 return -EFAULT;
159
160         ret = user_path_walk_link(vc_data.name, &nd);
161         if (!ret) {
162                 ret = __vc_set_iattr(nd.dentry,
163                         &vc_data.xid, &vc_data.flags, &vc_data.mask);
164                 path_release(&nd);
165         }
166
167         if (copy_to_user (data, &vc_data, sizeof(vc_data)))
168                 ret = -EFAULT;
169         return ret;
170 }
171
172
173 #ifdef  CONFIG_VSERVER_LEGACY           
174 #include <linux/proc_fs.h>
175
176 #define PROC_DYNAMIC_FIRST 0xF0000000UL
177
178 int vx_proc_ioctl(struct inode * inode, struct file * filp,
179         unsigned int cmd, unsigned long arg)
180 {
181         struct proc_dir_entry *entry;
182         int error = 0;
183         int flags;
184
185         if (inode->i_ino < PROC_DYNAMIC_FIRST)
186                 return -ENOTTY;
187
188         entry = PROC_I(inode)->pde;
189
190         switch(cmd) {
191         case FIOC_GETXFLG: {
192                 /* fixme: if stealth, return -ENOTTY */
193                 error = -EPERM;
194                 flags = entry->vx_flags;
195                 if (capable(CAP_CONTEXT))
196                         error = put_user(flags, (int *) arg);
197                 break;
198         }
199         case FIOC_SETXFLG: {
200                 /* fixme: if stealth, return -ENOTTY */
201                 error = -EPERM;
202                 if (!capable(CAP_CONTEXT))
203                         break;
204                 error = -EROFS;
205                 if (IS_RDONLY(inode))
206                         break;
207                 error = -EFAULT;
208                 if (get_user(flags, (int *) arg))
209                         break;
210                 error = 0;
211                 entry->vx_flags = flags;
212                 break;
213         }
214         default:
215                 return -ENOTTY;
216         }
217         return error;
218 }
219 #endif
220