quota: split out netlink notification support from quota.c
[safe/jmp/linux-2.6] / fs / quota / 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/compat.h>
14 #include <linux/kernel.h>
15 #include <linux/security.h>
16 #include <linux/syscalls.h>
17 #include <linux/buffer_head.h>
18 #include <linux/capability.h>
19 #include <linux/quotaops.h>
20 #include <linux/types.h>
21 #include <linux/writeback.h>
22
23 static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
24                                      qid_t id)
25 {
26         switch (cmd) {
27         /* these commands do not require any special privilegues */
28         case Q_GETFMT:
29         case Q_SYNC:
30         case Q_GETINFO:
31         case Q_XGETQSTAT:
32         case Q_XQUOTASYNC:
33                 break;
34         /* allow to query information for dquots we "own" */
35         case Q_GETQUOTA:
36         case Q_XGETQUOTA:
37                 if ((type == USRQUOTA && current_euid() == id) ||
38                     (type == GRPQUOTA && in_egroup_p(id)))
39                         break;
40                 /*FALLTHROUGH*/
41         default:
42                 if (!capable(CAP_SYS_ADMIN))
43                         return -EPERM;
44         }
45
46         return security_quotactl(cmd, type, id, sb);
47 }
48
49 static int quota_sync_all(int type)
50 {
51         struct super_block *sb;
52         int ret;
53
54         if (type >= MAXQUOTAS)
55                 return -EINVAL;
56         ret = security_quotactl(Q_SYNC, type, 0, NULL);
57         if (ret)
58                 return ret;
59
60         spin_lock(&sb_lock);
61 restart:
62         list_for_each_entry(sb, &super_blocks, s_list) {
63                 if (!sb->s_qcop || !sb->s_qcop->quota_sync)
64                         continue;
65
66                 sb->s_count++;
67                 spin_unlock(&sb_lock);
68                 down_read(&sb->s_umount);
69                 if (sb->s_root)
70                         sb->s_qcop->quota_sync(sb, type, 1);
71                 up_read(&sb->s_umount);
72                 spin_lock(&sb_lock);
73                 if (__put_super_and_need_restart(sb))
74                         goto restart;
75         }
76         spin_unlock(&sb_lock);
77
78         return 0;
79 }
80
81 static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
82                          void __user *addr)
83 {
84         char *pathname;
85         int ret = -ENOSYS;
86
87         pathname = getname(addr);
88         if (IS_ERR(pathname))
89                 return PTR_ERR(pathname);
90         if (sb->s_qcop->quota_on)
91                 ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
92         putname(pathname);
93         return ret;
94 }
95
96 static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
97 {
98         __u32 fmt;
99
100         down_read(&sb_dqopt(sb)->dqptr_sem);
101         if (!sb_has_quota_active(sb, type)) {
102                 up_read(&sb_dqopt(sb)->dqptr_sem);
103                 return -ESRCH;
104         }
105         fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
106         up_read(&sb_dqopt(sb)->dqptr_sem);
107         if (copy_to_user(addr, &fmt, sizeof(fmt)))
108                 return -EFAULT;
109         return 0;
110 }
111
112 static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
113 {
114         struct if_dqinfo info;
115         int ret;
116
117         if (!sb_has_quota_active(sb, type))
118                 return -ESRCH;
119         if (!sb->s_qcop->get_info)
120                 return -ENOSYS;
121         ret = sb->s_qcop->get_info(sb, type, &info);
122         if (!ret && copy_to_user(addr, &info, sizeof(info)))
123                 return -EFAULT;
124         return ret;
125 }
126
127 static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
128 {
129         struct if_dqinfo info;
130
131         if (copy_from_user(&info, addr, sizeof(info)))
132                 return -EFAULT;
133         if (!sb_has_quota_active(sb, type))
134                 return -ESRCH;
135         if (!sb->s_qcop->set_info)
136                 return -ENOSYS;
137         return sb->s_qcop->set_info(sb, type, &info);
138 }
139
140 static int quota_getquota(struct super_block *sb, int type, qid_t id,
141                           void __user *addr)
142 {
143         struct if_dqblk idq;
144         int ret;
145
146         if (!sb_has_quota_active(sb, type))
147                 return -ESRCH;
148         if (!sb->s_qcop->get_dqblk)
149                 return -ENOSYS;
150         ret = sb->s_qcop->get_dqblk(sb, type, id, &idq);
151         if (ret)
152                 return ret;
153         if (copy_to_user(addr, &idq, sizeof(idq)))
154                 return -EFAULT;
155         return 0;
156 }
157
158 static int quota_setquota(struct super_block *sb, int type, qid_t id,
159                           void __user *addr)
160 {
161         struct if_dqblk idq;
162
163         if (copy_from_user(&idq, addr, sizeof(idq)))
164                 return -EFAULT;
165         if (!sb_has_quota_active(sb, type))
166                 return -ESRCH;
167         if (!sb->s_qcop->set_dqblk)
168                 return -ENOSYS;
169         return sb->s_qcop->set_dqblk(sb, type, id, &idq);
170 }
171
172 static int quota_setxstate(struct super_block *sb, int cmd, void __user *addr)
173 {
174         __u32 flags;
175
176         if (copy_from_user(&flags, addr, sizeof(flags)))
177                 return -EFAULT;
178         if (!sb->s_qcop->set_xstate)
179                 return -ENOSYS;
180         return sb->s_qcop->set_xstate(sb, flags, cmd);
181 }
182
183 static int quota_getxstate(struct super_block *sb, void __user *addr)
184 {
185         struct fs_quota_stat fqs;
186         int ret;
187
188         if (!sb->s_qcop->get_xstate)
189                 return -ENOSYS;
190         ret = sb->s_qcop->get_xstate(sb, &fqs);
191         if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
192                 return -EFAULT;
193         return ret;
194 }
195
196 static int quota_setxquota(struct super_block *sb, int type, qid_t id,
197                            void __user *addr)
198 {
199         struct fs_disk_quota fdq;
200
201         if (copy_from_user(&fdq, addr, sizeof(fdq)))
202                 return -EFAULT;
203         if (!sb->s_qcop->set_xquota)
204                 return -ENOSYS;
205         return sb->s_qcop->set_xquota(sb, type, id, &fdq);
206 }
207
208 static int quota_getxquota(struct super_block *sb, int type, qid_t id,
209                            void __user *addr)
210 {
211         struct fs_disk_quota fdq;
212         int ret;
213
214         if (!sb->s_qcop->get_xquota)
215                 return -ENOSYS;
216         ret = sb->s_qcop->get_xquota(sb, type, id, &fdq);
217         if (!ret && copy_to_user(addr, &fdq, sizeof(fdq)))
218                 return -EFAULT;
219         return ret;
220 }
221
222 /* Copy parameters and call proper function */
223 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
224                        void __user *addr)
225 {
226         int ret;
227
228         if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
229                 return -EINVAL;
230         if (!sb->s_qcop)
231                 return -ENOSYS;
232
233         ret = check_quotactl_permission(sb, type, cmd, id);
234         if (ret < 0)
235                 return ret;
236
237         switch (cmd) {
238         case Q_QUOTAON:
239                 return quota_quotaon(sb, type, cmd, id, addr);
240         case Q_QUOTAOFF:
241                 if (!sb->s_qcop->quota_off)
242                         return -ENOSYS;
243                 return sb->s_qcop->quota_off(sb, type, 0);
244         case Q_GETFMT:
245                 return quota_getfmt(sb, type, addr);
246         case Q_GETINFO:
247                 return quota_getinfo(sb, type, addr);
248         case Q_SETINFO:
249                 return quota_setinfo(sb, type, addr);
250         case Q_GETQUOTA:
251                 return quota_getquota(sb, type, id, addr);
252         case Q_SETQUOTA:
253                 return quota_setquota(sb, type, id, addr);
254         case Q_SYNC:
255                 if (!sb->s_qcop->quota_sync)
256                         return -ENOSYS;
257                 return sb->s_qcop->quota_sync(sb, type, 1);
258         case Q_XQUOTAON:
259         case Q_XQUOTAOFF:
260         case Q_XQUOTARM:
261                 return quota_setxstate(sb, cmd, addr);
262         case Q_XGETQSTAT:
263                 return quota_getxstate(sb, addr);
264         case Q_XSETQLIM:
265                 return quota_setxquota(sb, type, id, addr);
266         case Q_XGETQUOTA:
267                 return quota_getxquota(sb, type, id, addr);
268         case Q_XQUOTASYNC:
269                 /* caller already holds s_umount */
270                 if (sb->s_flags & MS_RDONLY)
271                         return -EROFS;
272                 writeback_inodes_sb(sb);
273                 return 0;
274         default:
275                 return -EINVAL;
276         }
277 }
278
279 /*
280  * look up a superblock on which quota ops will be performed
281  * - use the name of a block device to find the superblock thereon
282  */
283 static struct super_block *quotactl_block(const char __user *special)
284 {
285 #ifdef CONFIG_BLOCK
286         struct block_device *bdev;
287         struct super_block *sb;
288         char *tmp = getname(special);
289
290         if (IS_ERR(tmp))
291                 return ERR_CAST(tmp);
292         bdev = lookup_bdev(tmp);
293         putname(tmp);
294         if (IS_ERR(bdev))
295                 return ERR_CAST(bdev);
296         sb = get_super(bdev);
297         bdput(bdev);
298         if (!sb)
299                 return ERR_PTR(-ENODEV);
300
301         return sb;
302 #else
303         return ERR_PTR(-ENODEV);
304 #endif
305 }
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 SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
314                 qid_t, id, void __user *, addr)
315 {
316         uint cmds, type;
317         struct super_block *sb = NULL;
318         int ret;
319
320         cmds = cmd >> SUBCMDSHIFT;
321         type = cmd & SUBCMDMASK;
322
323         /*
324          * As a special case Q_SYNC can be called without a specific device.
325          * It will iterate all superblocks that have quota enabled and call
326          * the sync action on each of them.
327          */
328         if (!special) {
329                 if (cmds == Q_SYNC)
330                         return quota_sync_all(type);
331                 return -ENODEV;
332         }
333
334         sb = quotactl_block(special);
335         if (IS_ERR(sb))
336                 return PTR_ERR(sb);
337
338         ret = do_quotactl(sb, type, cmds, id, addr);
339
340         drop_super(sb);
341         return ret;
342 }
343
344 #if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT)
345 /*
346  * This code works only for 32 bit quota tools over 64 bit OS (x86_64, ia64)
347  * and is necessary due to alignment problems.
348  */
349 struct compat_if_dqblk {
350         compat_u64 dqb_bhardlimit;
351         compat_u64 dqb_bsoftlimit;
352         compat_u64 dqb_curspace;
353         compat_u64 dqb_ihardlimit;
354         compat_u64 dqb_isoftlimit;
355         compat_u64 dqb_curinodes;
356         compat_u64 dqb_btime;
357         compat_u64 dqb_itime;
358         compat_uint_t dqb_valid;
359 };
360
361 /* XFS structures */
362 struct compat_fs_qfilestat {
363         compat_u64 dqb_bhardlimit;
364         compat_u64 qfs_nblks;
365         compat_uint_t qfs_nextents;
366 };
367
368 struct compat_fs_quota_stat {
369         __s8            qs_version;
370         __u16           qs_flags;
371         __s8            qs_pad;
372         struct compat_fs_qfilestat      qs_uquota;
373         struct compat_fs_qfilestat      qs_gquota;
374         compat_uint_t   qs_incoredqs;
375         compat_int_t    qs_btimelimit;
376         compat_int_t    qs_itimelimit;
377         compat_int_t    qs_rtbtimelimit;
378         __u16           qs_bwarnlimit;
379         __u16           qs_iwarnlimit;
380 };
381
382 asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special,
383                                                 qid_t id, void __user *addr)
384 {
385         unsigned int cmds;
386         struct if_dqblk __user *dqblk;
387         struct compat_if_dqblk __user *compat_dqblk;
388         struct fs_quota_stat __user *fsqstat;
389         struct compat_fs_quota_stat __user *compat_fsqstat;
390         compat_uint_t data;
391         u16 xdata;
392         long ret;
393
394         cmds = cmd >> SUBCMDSHIFT;
395
396         switch (cmds) {
397         case Q_GETQUOTA:
398                 dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
399                 compat_dqblk = addr;
400                 ret = sys_quotactl(cmd, special, id, dqblk);
401                 if (ret)
402                         break;
403                 if (copy_in_user(compat_dqblk, dqblk, sizeof(*compat_dqblk)) ||
404                         get_user(data, &dqblk->dqb_valid) ||
405                         put_user(data, &compat_dqblk->dqb_valid))
406                         ret = -EFAULT;
407                 break;
408         case Q_SETQUOTA:
409                 dqblk = compat_alloc_user_space(sizeof(struct if_dqblk));
410                 compat_dqblk = addr;
411                 ret = -EFAULT;
412                 if (copy_in_user(dqblk, compat_dqblk, sizeof(*compat_dqblk)) ||
413                         get_user(data, &compat_dqblk->dqb_valid) ||
414                         put_user(data, &dqblk->dqb_valid))
415                         break;
416                 ret = sys_quotactl(cmd, special, id, dqblk);
417                 break;
418         case Q_XGETQSTAT:
419                 fsqstat = compat_alloc_user_space(sizeof(struct fs_quota_stat));
420                 compat_fsqstat = addr;
421                 ret = sys_quotactl(cmd, special, id, fsqstat);
422                 if (ret)
423                         break;
424                 ret = -EFAULT;
425                 /* Copying qs_version, qs_flags, qs_pad */
426                 if (copy_in_user(compat_fsqstat, fsqstat,
427                         offsetof(struct compat_fs_quota_stat, qs_uquota)))
428                         break;
429                 /* Copying qs_uquota */
430                 if (copy_in_user(&compat_fsqstat->qs_uquota,
431                         &fsqstat->qs_uquota,
432                         sizeof(compat_fsqstat->qs_uquota)) ||
433                         get_user(data, &fsqstat->qs_uquota.qfs_nextents) ||
434                         put_user(data, &compat_fsqstat->qs_uquota.qfs_nextents))
435                         break;
436                 /* Copying qs_gquota */
437                 if (copy_in_user(&compat_fsqstat->qs_gquota,
438                         &fsqstat->qs_gquota,
439                         sizeof(compat_fsqstat->qs_gquota)) ||
440                         get_user(data, &fsqstat->qs_gquota.qfs_nextents) ||
441                         put_user(data, &compat_fsqstat->qs_gquota.qfs_nextents))
442                         break;
443                 /* Copying the rest */
444                 if (copy_in_user(&compat_fsqstat->qs_incoredqs,
445                         &fsqstat->qs_incoredqs,
446                         sizeof(struct compat_fs_quota_stat) -
447                         offsetof(struct compat_fs_quota_stat, qs_incoredqs)) ||
448                         get_user(xdata, &fsqstat->qs_iwarnlimit) ||
449                         put_user(xdata, &compat_fsqstat->qs_iwarnlimit))
450                         break;
451                 ret = 0;
452                 break;
453         default:
454                 ret = sys_quotactl(cmd, special, id, addr);
455         }
456         return ret;
457 }
458 #endif