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