OSDN Git Service

[GCC4] add preliminary support for GCC 4 (Mikael Pettersson)
[linux-kernel-docs/linux-2.4.36.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/slab.h>
10 #include <asm/current.h>
11 #include <asm/uaccess.h>
12 #include <linux/kernel.h>
13 #include <linux/smp_lock.h>
14 #include <linux/quotaops.h>
15 #include <linux/quotacompat.h>
16
17 struct dqstats dqstats;
18
19 /* Check validity of quotactl */
20 static int check_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                 case Q_XQUOTAON:
62                 case Q_XQUOTAOFF:
63                 case Q_XQUOTARM:
64                         if (!sb->s_qcop->set_xstate)
65                                 return -ENOSYS;
66                         break;
67                 case Q_XGETQSTAT:
68                         if (!sb->s_qcop->get_xstate)
69                                 return -ENOSYS;
70                         break;
71                 case Q_XSETQLIM:
72                         if (!sb->s_qcop->set_xquota)
73                                 return -ENOSYS;
74                         break;
75                 case Q_XGETQUOTA:
76                         if (!sb->s_qcop->get_xquota)
77                                 return -ENOSYS;
78                         break;
79                 default:
80                         return -EINVAL;
81         }
82
83         /* Is quota turned on for commands which need it? */
84         switch (cmd) {
85                 case Q_GETFMT:
86                 case Q_GETINFO:
87                 case Q_QUOTAOFF:
88                 case Q_SETINFO:
89                 case Q_SETQUOTA:
90                 case Q_GETQUOTA:
91                         if (!sb_has_quota_enabled(sb, type))
92                                 return -ESRCH;
93         }
94         /* Check privileges */
95         if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
96                 if (((type == USRQUOTA && current->euid != id) ||
97                      (type == GRPQUOTA && !in_egroup_p(id))) &&
98                     !capable(CAP_SYS_ADMIN))
99                         return -EPERM;
100         }
101         else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
102                 if (!capable(CAP_SYS_ADMIN))
103                         return -EPERM;
104         return 0;
105 }
106
107 /* Resolve device pathname to superblock */
108 static struct super_block *resolve_dev(const char *path)
109 {
110         int ret;
111         mode_t mode;
112         struct nameidata nd;
113         kdev_t dev;
114         struct super_block *sb;
115
116         ret = user_path_walk(path, &nd);
117         if (ret)
118                 goto out;
119
120         dev = nd.dentry->d_inode->i_rdev;
121         mode = nd.dentry->d_inode->i_mode;
122         path_release(&nd);
123
124         ret = -ENOTBLK;
125         if (!S_ISBLK(mode))
126                 goto out;
127         ret = -ENODEV;
128         sb = get_super(dev);
129         if (!sb)
130                 goto out;
131         return sb;
132 out:
133         return ERR_PTR(ret);
134 }
135
136 /* Copy parameters and call proper function */
137 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
138 {
139         int ret;
140
141         switch (cmd) {
142                 case Q_QUOTAON: {
143                         char *pathname;
144
145                         if (IS_ERR(pathname = getname(addr)))
146                                 return PTR_ERR(pathname);
147                         ret = sb->s_qcop->quota_on(sb, type, id, pathname);
148                         putname(pathname);
149                         return ret;
150                 }
151                 case Q_QUOTAOFF:
152                         return sb->s_qcop->quota_off(sb, type);
153
154                 case Q_GETFMT: {
155                         __u32 fmt;
156
157                         fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
158                         if (copy_to_user(addr, &fmt, sizeof(fmt)))
159                                 return -EFAULT;
160                         return 0;
161                 }
162                 case Q_GETINFO: {
163                         struct if_dqinfo info;
164
165                         if ((ret = sb->s_qcop->get_info(sb, type, &info)))
166                                 return ret;
167                         if (copy_to_user(addr, &info, sizeof(info)))
168                                 return -EFAULT;
169                         return 0;
170                 }
171                 case Q_SETINFO: {
172                         struct if_dqinfo info;
173
174                         if (copy_from_user(&info, addr, sizeof(info)))
175                                 return -EFAULT;
176                         return sb->s_qcop->set_info(sb, type, &info);
177                 }
178                 case Q_GETQUOTA: {
179                         struct if_dqblk idq;
180
181                         if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
182                                 return ret;
183                         if (copy_to_user(addr, &idq, sizeof(idq)))
184                                 return -EFAULT;
185                         return 0;
186                 }
187                 case Q_SETQUOTA: {
188                         struct if_dqblk idq;
189
190                         if (copy_from_user(&idq, addr, sizeof(idq)))
191                                 return -EFAULT;
192                         return sb->s_qcop->set_dqblk(sb, type, id, &idq);
193                 }
194                 case Q_SYNC:
195                         if (sb)
196                                 return sb->s_qcop->quota_sync(sb, type);
197                         sync_dquots_dev(NODEV, type);
198                         return 0;
199                 case Q_XQUOTAON:
200                 case Q_XQUOTAOFF:
201                 case Q_XQUOTARM: {
202                         __u32 flags;
203
204                         if (copy_from_user(&flags, addr, sizeof(flags)))
205                                 return -EFAULT;
206                         return sb->s_qcop->set_xstate(sb, flags, cmd);
207                 }
208                 case Q_XGETQSTAT: {
209                         struct fs_quota_stat fqs;
210                 
211                         if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
212                                 return ret;
213                         if (copy_to_user(addr, &fqs, sizeof(fqs)))
214                                 return -EFAULT;
215                         return 0;
216                 }
217                 case Q_XSETQLIM: {
218                         struct fs_disk_quota fdq;
219
220                         if (copy_from_user(&fdq, addr, sizeof(fdq)))
221                                 return -EFAULT;
222                        return sb->s_qcop->set_xquota(sb, type, id, &fdq);
223                 }
224                 case Q_XGETQUOTA: {
225                         struct fs_disk_quota fdq;
226
227                         if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
228                                 return ret;
229                         if (copy_to_user(addr, &fdq, sizeof(fdq)))
230                                 return -EFAULT;
231                         return 0;
232                 }
233                 /* We never reach here unless validity check is broken */
234                 default:
235                         BUG();
236         }
237         return 0;
238 }
239
240 static int check_compat_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
241 {
242         if (type >= MAXQUOTAS)
243                 return -EINVAL;
244         /* Is operation supported? */
245         /* sb==NULL for GETSTATS calls */
246         if (sb && !sb->s_qcop)
247                 return -ENOSYS;
248
249         switch (cmd) {
250                 case Q_COMP_QUOTAON:
251                         if (!sb->s_qcop->quota_on)
252                                 return -ENOSYS;
253                         break;
254                 case Q_COMP_QUOTAOFF:
255                         if (!sb->s_qcop->quota_off)
256                                 return -ENOSYS;
257                         break;
258                 case Q_COMP_SYNC:
259                         if (sb && !sb->s_qcop->quota_sync)
260                                 return -ENOSYS;
261                         break;
262                 case Q_V1_SETQLIM:
263                 case Q_V1_SETUSE:
264                 case Q_V1_SETQUOTA:
265                         if (!sb->s_qcop->set_dqblk)
266                                 return -ENOSYS;
267                         break;
268                 case Q_V1_GETQUOTA:
269                         if (!sb->s_qcop->get_dqblk)
270                                 return -ENOSYS;
271                         break;
272                 case Q_V1_RSQUASH:
273                         if (!sb->s_qcop->set_info)
274                                 return -ENOSYS;
275                         break;
276                 case Q_V1_GETSTATS:
277                         return 0;       /* GETSTATS need no other checks */
278                 default:
279                         return -EINVAL;
280         }
281
282         /* Is quota turned on for commands which need it? */
283         switch (cmd) {
284                 case Q_V2_SETFLAGS:
285                 case Q_V2_SETGRACE:
286                 case Q_V2_SETINFO:
287                 case Q_V2_GETINFO:
288                 case Q_COMP_QUOTAOFF:
289                 case Q_V1_RSQUASH:
290                 case Q_V1_SETQUOTA:
291                 case Q_V1_SETQLIM:
292                 case Q_V1_SETUSE:
293                 case Q_V2_SETQUOTA:
294                 /* Q_V2_SETQLIM: collision with Q_V1_SETQLIM */
295                 case Q_V2_SETUSE:
296                 case Q_V1_GETQUOTA:
297                 case Q_V2_GETQUOTA:
298                         if (!sb_has_quota_enabled(sb, type))
299                                 return -ESRCH;
300         }
301         if (cmd != Q_COMP_QUOTAON &&
302             cmd != Q_COMP_QUOTAOFF &&
303             cmd != Q_COMP_SYNC &&
304             sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id != QFMT_VFS_OLD)
305                 return -ESRCH;
306
307         /* Check privileges */
308         if (cmd == Q_V1_GETQUOTA || cmd == Q_V2_GETQUOTA) {
309                 if (((type == USRQUOTA && current->euid != id) ||
310                      (type == GRPQUOTA && !in_egroup_p(id))) &&
311                     !capable(CAP_SYS_ADMIN))
312                         return -EPERM;
313         }
314         else if (cmd != Q_V1_GETSTATS && cmd != Q_V2_GETSTATS && cmd != Q_V2_GETINFO && cmd != Q_COMP_SYNC)
315                 if (!capable(CAP_SYS_ADMIN))
316                         return -EPERM;
317         return 0;
318 }
319
320 static int v1_set_rsquash(struct super_block *sb, int type, int flag)
321 {
322         struct if_dqinfo info;
323
324         info.dqi_valid = IIF_FLAGS;
325         info.dqi_flags = flag ? V1_DQF_RSQUASH : 0;
326         return sb->s_qcop->set_info(sb, type, &info);
327 }
328
329 static int v1_get_dqblk(struct super_block *sb, int type, qid_t id, struct v1c_mem_dqblk *mdq)
330 {
331         struct if_dqblk idq;
332         int ret;
333
334         if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)) < 0)
335                 return ret;
336         mdq->dqb_ihardlimit = idq.dqb_ihardlimit;
337         mdq->dqb_isoftlimit = idq.dqb_isoftlimit;
338         mdq->dqb_curinodes = idq.dqb_curinodes;
339         mdq->dqb_bhardlimit = idq.dqb_bhardlimit;
340         mdq->dqb_bsoftlimit = idq.dqb_bsoftlimit;
341         mdq->dqb_curblocks = toqb(idq.dqb_curspace);
342         mdq->dqb_itime = idq.dqb_itime;
343         mdq->dqb_btime = idq.dqb_btime;
344         if (id == 0) {  /* Times for id 0 are in fact grace times */
345                 struct if_dqinfo info;
346
347                 if ((ret = sb->s_qcop->get_info(sb, type, &info)) < 0)
348                         return ret;
349                 mdq->dqb_btime = info.dqi_bgrace;
350                 mdq->dqb_itime = info.dqi_igrace;
351         }
352         return 0;
353 }
354
355 static int v1_set_dqblk(struct super_block *sb, int type, int cmd, qid_t id, struct v1c_mem_dqblk *mdq)
356 {
357         struct if_dqblk idq;
358         int ret;
359
360         idq.dqb_valid = 0;
361         if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETQLIM) {
362                 idq.dqb_ihardlimit = mdq->dqb_ihardlimit;
363                 idq.dqb_isoftlimit = mdq->dqb_isoftlimit;
364                 idq.dqb_bhardlimit = mdq->dqb_bhardlimit;
365                 idq.dqb_bsoftlimit = mdq->dqb_bsoftlimit;
366                 idq.dqb_valid |= QIF_LIMITS;
367         }
368         if (cmd == Q_V1_SETQUOTA || cmd == Q_V1_SETUSE) {
369                 idq.dqb_curinodes = mdq->dqb_curinodes;
370                 idq.dqb_curspace = ((qsize_t)mdq->dqb_curblocks) << QUOTABLOCK_BITS;
371                 idq.dqb_valid |= QIF_USAGE;
372         }
373         ret = sb->s_qcop->set_dqblk(sb, type, id, &idq);
374         if (!ret && id == 0 && cmd == Q_V1_SETQUOTA) {  /* Times for id 0 are in fact grace times */
375                 struct if_dqinfo info;
376
377                 info.dqi_bgrace = mdq->dqb_btime;
378                 info.dqi_igrace = mdq->dqb_itime;
379                 info.dqi_valid = IIF_BGRACE | IIF_IGRACE;
380                 ret = sb->s_qcop->set_info(sb, type, &info);
381         }
382         return ret;
383 }
384
385 static void v1_get_stats(struct v1c_dqstats *dst)
386 {
387         memcpy(dst, &dqstats, sizeof(dqstats));
388 }
389
390 /* Handle requests to old interface */
391 static int do_compat_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
392 {
393         int ret;
394
395         switch (cmd) {
396                 case Q_COMP_QUOTAON: {
397                         char *pathname;
398
399                         if (IS_ERR(pathname = getname(addr)))
400                                 return PTR_ERR(pathname);
401                         ret = sb->s_qcop->quota_on(sb, type, QFMT_VFS_OLD, pathname);
402                         putname(pathname);
403                         return ret;
404                 }
405                 case Q_COMP_QUOTAOFF:
406                         return sb->s_qcop->quota_off(sb, type);
407                 case Q_COMP_SYNC:
408                         if (sb)
409                                 return sb->s_qcop->quota_sync(sb, type);
410                         sync_dquots_dev(NODEV, type);
411                         return 0;
412                 case Q_V1_RSQUASH: {
413                         int flag;
414
415                         if (copy_from_user(&flag, addr, sizeof(flag)))
416                                 return -EFAULT;
417                         return v1_set_rsquash(sb, type, flag);
418                 }
419                 case Q_V1_GETQUOTA: {
420                         struct v1c_mem_dqblk mdq;
421
422                         if ((ret = v1_get_dqblk(sb, type, id, &mdq)))
423                                 return ret;
424                         if (copy_to_user(addr, &mdq, sizeof(mdq)))
425                                 return -EFAULT;
426                         return 0;
427                 }
428                 case Q_V1_SETQLIM:
429                 case Q_V1_SETUSE:
430                 case Q_V1_SETQUOTA: {
431                         struct v1c_mem_dqblk mdq;
432
433                         if (copy_from_user(&mdq, addr, sizeof(mdq)))
434                                 return -EFAULT;
435                         return v1_set_dqblk(sb, type, cmd, id, &mdq);
436                 }
437                 case Q_V1_GETSTATS: {
438                         struct v1c_dqstats dst;
439
440                         v1_get_stats(&dst);
441                         if (copy_to_user(addr, &dst, sizeof(dst)))
442                                 return -EFAULT;
443                         return 0;
444                 }
445         }
446         BUG();
447         return 0;
448 }
449
450 /* Macros for short-circuiting the compatibility tests */
451 #define NEW_COMMAND(c) ((c) & (0x80 << 16))
452 #define XQM_COMMAND(c) (((c) & ('X' << 8)) == ('X' << 8))
453
454 /*
455  * This is the system call interface. This communicates with
456  * the user-level programs. Currently this only supports diskquota
457  * calls. Maybe we need to add the process quotas etc. in the future,
458  * but we probably should use rlimits for that.
459  */
460 asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
461 {
462         uint cmds, type;
463         struct super_block *sb = NULL;
464         int ret = -EINVAL;
465
466         lock_kernel();
467         cmds = cmd >> SUBCMDSHIFT;
468         type = cmd & SUBCMDMASK;
469
470         if (cmds != Q_V1_GETSTATS && cmds != Q_V2_GETSTATS && IS_ERR(sb = resolve_dev(special))) {
471                 ret = PTR_ERR(sb);
472                 sb = NULL;
473                 goto out;
474         }
475         if (!NEW_COMMAND(cmds) && !XQM_COMMAND(cmds)) {
476                 if ((ret = check_compat_quotactl_valid(sb, type, cmds, id)) < 0)
477                         goto out;
478                 ret = do_compat_quotactl(sb, type, cmds, id, addr);
479                 goto out;
480         }
481         if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
482                 goto out;
483         ret = do_quotactl(sb, type, cmds, id, addr);
484 out:
485         if (sb)
486                 drop_super(sb);
487         unlock_kernel();
488         return ret;
489 }