vserver 2.0-pre4
[linux-2.6.git] / fs / quota.c
1 /*
2  * Quota code necessary even when VFS quota support is not compiled
3  * into the kernel.  The interesting stuff is over in dquot.c, here
4  * we have symbols for initial quotactl(2) handling, the sysctl(2)
5  * variables, etc - things needed even when quota support disabled.
6  */
7
8 #include <linux/fs.h>
9 #include <linux/namei.h>
10 #include <linux/slab.h>
11 #include <asm/current.h>
12 #include <asm/uaccess.h>
13 #include <linux/kernel.h>
14 #include <linux/smp_lock.h>
15 #include <linux/security.h>
16 #include <linux/syscalls.h>
17 #include <linux/buffer_head.h>
18 #include <linux/major.h>
19 #include <linux/blkdev.h>
20
21 /* Check validity of quotactl */
22 static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
23 {
24         if (type >= MAXQUOTAS)
25                 return -EINVAL;
26         if (!sb && cmd != Q_SYNC)
27                 return -ENODEV;
28         /* Is operation supported? */
29         if (sb && !sb->s_qcop)
30                 return -ENOSYS;
31
32         switch (cmd) {
33                 case Q_GETFMT:
34                         break;
35                 case Q_QUOTAON:
36                         if (!sb->s_qcop->quota_on)
37                                 return -ENOSYS;
38                         break;
39                 case Q_QUOTAOFF:
40                         if (!sb->s_qcop->quota_off)
41                                 return -ENOSYS;
42                         break;
43                 case Q_SETINFO:
44                         if (!sb->s_qcop->set_info)
45                                 return -ENOSYS;
46                         break;
47                 case Q_GETINFO:
48                         if (!sb->s_qcop->get_info)
49                                 return -ENOSYS;
50                         break;
51                 case Q_SETQUOTA:
52                         if (!sb->s_qcop->set_dqblk)
53                                 return -ENOSYS;
54                         break;
55                 case Q_GETQUOTA:
56                         if (!sb->s_qcop->get_dqblk)
57                                 return -ENOSYS;
58                         break;
59                 case Q_SYNC:
60                         if (sb && !sb->s_qcop->quota_sync)
61                                 return -ENOSYS;
62                         break;
63                 case Q_XQUOTAON:
64                 case Q_XQUOTAOFF:
65                 case Q_XQUOTARM:
66                         if (!sb->s_qcop->set_xstate)
67                                 return -ENOSYS;
68                         break;
69                 case Q_XGETQSTAT:
70                         if (!sb->s_qcop->get_xstate)
71                                 return -ENOSYS;
72                         break;
73                 case Q_XSETQLIM:
74                         if (!sb->s_qcop->set_xquota)
75                                 return -ENOSYS;
76                         break;
77                 case Q_XGETQUOTA:
78                         if (!sb->s_qcop->get_xquota)
79                                 return -ENOSYS;
80                         break;
81                 default:
82                         return -EINVAL;
83         }
84
85         /* Is quota turned on for commands which need it? */
86         switch (cmd) {
87                 case Q_GETFMT:
88                 case Q_GETINFO:
89                 case Q_QUOTAOFF:
90                 case Q_SETINFO:
91                 case Q_SETQUOTA:
92                 case Q_GETQUOTA:
93                         /* This is just informative test so we are satisfied without a lock */
94                         if (!sb_has_quota_enabled(sb, type))
95                                 return -ESRCH;
96         }
97         /* Check privileges */
98         if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
99                 if (((type == USRQUOTA && current->euid != id) ||
100                      (type == GRPQUOTA && !in_egroup_p(id))) &&
101                     !capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_QUOTA_CTL))
102                         return -EPERM;
103         }
104         else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
105                 if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_QUOTA_CTL))
106                         return -EPERM;
107
108         return security_quotactl (cmd, type, id, sb);
109 }
110
111 static struct super_block *get_super_to_sync(int type)
112 {
113         struct list_head *head;
114         int cnt, dirty;
115
116 restart:
117         spin_lock(&sb_lock);
118         list_for_each(head, &super_blocks) {
119                 struct super_block *sb = list_entry(head, struct super_block, s_list);
120
121                 /* This test just improves performance so it needn't be reliable... */
122                 for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++)
123                         if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt)
124                             && info_any_dirty(&sb_dqopt(sb)->info[cnt]))
125                                 dirty = 1;
126                 if (!dirty)
127                         continue;
128                 sb->s_count++;
129                 spin_unlock(&sb_lock);
130                 down_read(&sb->s_umount);
131                 if (!sb->s_root) {
132                         drop_super(sb);
133                         goto restart;
134                 }
135                 return sb;
136         }
137         spin_unlock(&sb_lock);
138         return NULL;
139 }
140
141 static void quota_sync_sb(struct super_block *sb, int type)
142 {
143         int cnt;
144         struct inode *discard[MAXQUOTAS];
145
146         sb->s_qcop->quota_sync(sb, type);
147         /* This is not very clever (and fast) but currently I don't know about
148          * any other simple way of getting quota data to disk and we must get
149          * them there for userspace to be visible... */
150         if (sb->s_op->sync_fs)
151                 sb->s_op->sync_fs(sb, 1);
152         sync_blockdev(sb->s_bdev);
153
154         /* Now when everything is written we can discard the pagecache so
155          * that userspace sees the changes. We need i_sem and so we could
156          * not do it inside dqonoff_sem. Moreover we need to be carefull
157          * about races with quotaoff() (that is the reason why we have own
158          * reference to inode). */
159         down(&sb_dqopt(sb)->dqonoff_sem);
160         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
161                 discard[cnt] = NULL;
162                 if (type != -1 && cnt != type)
163                         continue;
164                 if (!sb_has_quota_enabled(sb, cnt))
165                         continue;
166                 discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]);
167         }
168         up(&sb_dqopt(sb)->dqonoff_sem);
169         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
170                 if (discard[cnt]) {
171                         down(&discard[cnt]->i_sem);
172                         truncate_inode_pages(&discard[cnt]->i_data, 0);
173                         up(&discard[cnt]->i_sem);
174                         iput(discard[cnt]);
175                 }
176         }
177 }
178
179 void sync_dquots(struct super_block *sb, int type)
180 {
181         if (sb) {
182                 if (sb->s_qcop->quota_sync)
183                         quota_sync_sb(sb, type);
184         }
185         else {
186                 while ((sb = get_super_to_sync(type)) != NULL) {
187                         if (sb->s_qcop->quota_sync)
188                                 quota_sync_sb(sb, type);
189                         drop_super(sb);
190                 }
191         }
192 }
193
194 /* Copy parameters and call proper function */
195 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, void __user *addr)
196 {
197         int ret;
198
199         switch (cmd) {
200                 case Q_QUOTAON: {
201                         char *pathname;
202
203                         if (IS_ERR(pathname = getname(addr)))
204                                 return PTR_ERR(pathname);
205                         ret = sb->s_qcop->quota_on(sb, type, id, pathname);
206                         putname(pathname);
207                         return ret;
208                 }
209                 case Q_QUOTAOFF:
210                         return sb->s_qcop->quota_off(sb, type);
211
212                 case Q_GETFMT: {
213                         __u32 fmt;
214
215                         down_read(&sb_dqopt(sb)->dqptr_sem);
216                         if (!sb_has_quota_enabled(sb, type)) {
217                                 up_read(&sb_dqopt(sb)->dqptr_sem);
218                                 return -ESRCH;
219                         }
220                         fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
221                         up_read(&sb_dqopt(sb)->dqptr_sem);
222                         if (copy_to_user(addr, &fmt, sizeof(fmt)))
223                                 return -EFAULT;
224                         return 0;
225                 }
226                 case Q_GETINFO: {
227                         struct if_dqinfo info;
228
229                         if ((ret = sb->s_qcop->get_info(sb, type, &info)))
230                                 return ret;
231                         if (copy_to_user(addr, &info, sizeof(info)))
232                                 return -EFAULT;
233                         return 0;
234                 }
235                 case Q_SETINFO: {
236                         struct if_dqinfo info;
237
238                         if (copy_from_user(&info, addr, sizeof(info)))
239                                 return -EFAULT;
240                         return sb->s_qcop->set_info(sb, type, &info);
241                 }
242                 case Q_GETQUOTA: {
243                         struct if_dqblk idq;
244
245                         if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
246                                 return ret;
247                         if (copy_to_user(addr, &idq, sizeof(idq)))
248                                 return -EFAULT;
249                         return 0;
250                 }
251                 case Q_SETQUOTA: {
252                         struct if_dqblk idq;
253
254                         if (copy_from_user(&idq, addr, sizeof(idq)))
255                                 return -EFAULT;
256                         return sb->s_qcop->set_dqblk(sb, type, id, &idq);
257                 }
258                 case Q_SYNC:
259                         sync_dquots(sb, type);
260                         return 0;
261
262                 case Q_XQUOTAON:
263                 case Q_XQUOTAOFF:
264                 case Q_XQUOTARM: {
265                         __u32 flags;
266
267                         if (copy_from_user(&flags, addr, sizeof(flags)))
268                                 return -EFAULT;
269                         return sb->s_qcop->set_xstate(sb, flags, cmd);
270                 }
271                 case Q_XGETQSTAT: {
272                         struct fs_quota_stat fqs;
273                 
274                         if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
275                                 return ret;
276                         if (copy_to_user(addr, &fqs, sizeof(fqs)))
277                                 return -EFAULT;
278                         return 0;
279                 }
280                 case Q_XSETQLIM: {
281                         struct fs_disk_quota fdq;
282
283                         if (copy_from_user(&fdq, addr, sizeof(fdq)))
284                                 return -EFAULT;
285                        return sb->s_qcop->set_xquota(sb, type, id, &fdq);
286                 }
287                 case Q_XGETQUOTA: {
288                         struct fs_disk_quota fdq;
289
290                         if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
291                                 return ret;
292                         if (copy_to_user(addr, &fdq, sizeof(fdq)))
293                                 return -EFAULT;
294                         return 0;
295                 }
296                 /* We never reach here unless validity check is broken */
297                 default:
298                         BUG();
299         }
300         return 0;
301 }
302
303 #ifdef CONFIG_BLK_DEV_VROOT
304 extern struct block_device *vroot_get_real_bdev(struct block_device *);
305 #endif
306
307 /*
308  * This is the system call interface. This communicates with
309  * the user-level programs. Currently this only supports diskquota
310  * calls. Maybe we need to add the process quotas etc. in the future,
311  * but we probably should use rlimits for that.
312  */
313 asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, qid_t id, void __user *addr)
314 {
315         uint cmds, type;
316         struct super_block *sb = NULL;
317         struct block_device *bdev;
318         char *tmp;
319         int ret;
320
321         cmds = cmd >> SUBCMDSHIFT;
322         type = cmd & SUBCMDMASK;
323
324         if (cmds != Q_SYNC || special) {
325                 tmp = getname(special);
326                 if (IS_ERR(tmp))
327                         return PTR_ERR(tmp);
328                 bdev = lookup_bdev(tmp);
329                 putname(tmp);
330                 if (IS_ERR(bdev))
331                         return PTR_ERR(bdev);
332 #ifdef CONFIG_BLK_DEV_VROOT
333                 if (bdev && bdev->bd_inode &&
334                         imajor(bdev->bd_inode) == VROOT_MAJOR) {
335                         struct block_device *bdnew =
336                                 vroot_get_real_bdev(bdev);
337
338                         bdput(bdev);
339                         if (IS_ERR(bdnew))
340                                 return PTR_ERR(bdnew);
341                         bdev = bdnew;
342                 }
343 #endif
344                 sb = get_super(bdev);
345                 bdput(bdev);
346                 if (!sb)
347                         return -ENODEV;
348         }
349
350         ret = check_quotactl_valid(sb, type, cmds, id);
351         if (ret >= 0)
352                 ret = do_quotactl(sb, type, cmds, id, addr);
353         if (sb)
354                 drop_super(sb);
355
356         return ret;
357 }