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