quota: split out netlink notification support from quota.c
[deliverable/linux.git] / fs / quota / quota.c
CommitLineData
1da177e4
LT
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>
b716395e 13#include <linux/compat.h>
1da177e4 14#include <linux/kernel.h>
1da177e4
LT
15#include <linux/security.h>
16#include <linux/syscalls.h>
17#include <linux/buffer_head.h>
16f7e0fe 18#include <linux/capability.h>
be586bab 19#include <linux/quotaops.h>
b716395e 20#include <linux/types.h>
8c4e4acd 21#include <linux/writeback.h>
1da177e4 22
c988afb5
CH
23static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
24 qid_t id)
1da177e4 25{
c988afb5
CH
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:
1da177e4
LT
42 if (!capable(CAP_SYS_ADMIN))
43 return -EPERM;
44 }
45
c988afb5 46 return security_quotactl(cmd, type, id, sb);
1da177e4
LT
47}
48
6ae09575 49static int quota_sync_all(int type)
1da177e4 50{
850b201b 51 struct super_block *sb;
6ae09575
CH
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;
618f0636 59
618f0636
KK
60 spin_lock(&sb_lock);
61restart:
62 list_for_each_entry(sb, &super_blocks, s_list) {
5fb324ad
CH
63 if (!sb->s_qcop || !sb->s_qcop->quota_sync)
64 continue;
65
618f0636
KK
66 sb->s_count++;
67 spin_unlock(&sb_lock);
68 down_read(&sb->s_umount);
850b201b 69 if (sb->s_root)
5fb324ad 70 sb->s_qcop->quota_sync(sb, type, 1);
618f0636
KK
71 up_read(&sb->s_umount);
72 spin_lock(&sb_lock);
73 if (__put_super_and_need_restart(sb))
74 goto restart;
1da177e4 75 }
618f0636 76 spin_unlock(&sb_lock);
6ae09575
CH
77
78 return 0;
1da177e4
LT
79}
80
c411e5f6
CH
81static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
82 void __user *addr)
1da177e4 83{
c411e5f6 84 char *pathname;
f450d4fe 85 int ret = -ENOSYS;
1da177e4 86
c411e5f6
CH
87 pathname = getname(addr);
88 if (IS_ERR(pathname))
89 return PTR_ERR(pathname);
f450d4fe
CH
90 if (sb->s_qcop->quota_on)
91 ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
c411e5f6
CH
92 putname(pathname);
93 return ret;
94}
1da177e4 95
c411e5f6
CH
96static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
97{
98 __u32 fmt;
1da177e4 99
c411e5f6
CH
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}
1da177e4 111
c411e5f6
CH
112static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
113{
114 struct if_dqinfo info;
115 int ret;
1da177e4 116
f450d4fe
CH
117 if (!sb_has_quota_active(sb, type))
118 return -ESRCH;
119 if (!sb->s_qcop->get_info)
120 return -ENOSYS;
c411e5f6
CH
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}
1da177e4 126
c411e5f6
CH
127static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
128{
129 struct if_dqinfo info;
1da177e4 130
c411e5f6
CH
131 if (copy_from_user(&info, addr, sizeof(info)))
132 return -EFAULT;
f450d4fe
CH
133 if (!sb_has_quota_active(sb, type))
134 return -ESRCH;
135 if (!sb->s_qcop->set_info)
136 return -ENOSYS;
c411e5f6
CH
137 return sb->s_qcop->set_info(sb, type, &info);
138}
139
140static 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
f450d4fe
CH
146 if (!sb_has_quota_active(sb, type))
147 return -ESRCH;
148 if (!sb->s_qcop->get_dqblk)
149 return -ENOSYS;
c411e5f6
CH
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
158static 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;
f450d4fe
CH
165 if (!sb_has_quota_active(sb, type))
166 return -ESRCH;
167 if (!sb->s_qcop->set_dqblk)
168 return -ENOSYS;
c411e5f6
CH
169 return sb->s_qcop->set_dqblk(sb, type, id, &idq);
170}
171
172static 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;
f450d4fe
CH
178 if (!sb->s_qcop->set_xstate)
179 return -ENOSYS;
c411e5f6
CH
180 return sb->s_qcop->set_xstate(sb, flags, cmd);
181}
182
183static int quota_getxstate(struct super_block *sb, void __user *addr)
184{
185 struct fs_quota_stat fqs;
186 int ret;
f450d4fe
CH
187
188 if (!sb->s_qcop->get_xstate)
189 return -ENOSYS;
c411e5f6
CH
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}
1da177e4 195
c411e5f6
CH
196static 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;
f450d4fe
CH
203 if (!sb->s_qcop->set_xquota)
204 return -ENOSYS;
c411e5f6
CH
205 return sb->s_qcop->set_xquota(sb, type, id, &fdq);
206}
207
208static 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
f450d4fe
CH
214 if (!sb->s_qcop->get_xquota)
215 return -ENOSYS;
c411e5f6
CH
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 */
223static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
224 void __user *addr)
225{
c988afb5
CH
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
c411e5f6
CH
237 switch (cmd) {
238 case Q_QUOTAON:
239 return quota_quotaon(sb, type, cmd, id, addr);
240 case Q_QUOTAOFF:
f450d4fe
CH
241 if (!sb->s_qcop->quota_off)
242 return -ENOSYS;
c411e5f6
CH
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:
6ae09575
CH
255 if (!sb->s_qcop->quota_sync)
256 return -ENOSYS;
5fb324ad 257 return sb->s_qcop->quota_sync(sb, type, 1);
c411e5f6
CH
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:
8c4e4acd
CH
269 /* caller already holds s_umount */
270 if (sb->s_flags & MS_RDONLY)
271 return -EROFS;
272 writeback_inodes_sb(sb);
273 return 0;
c411e5f6 274 default:
f450d4fe 275 return -EINVAL;
1da177e4 276 }
1da177e4
LT
277}
278
9361401e
DH
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 */
7a2435d8 283static struct super_block *quotactl_block(const char __user *special)
9361401e
DH
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))
e231c2ee 291 return ERR_CAST(tmp);
9361401e
DH
292 bdev = lookup_bdev(tmp);
293 putname(tmp);
294 if (IS_ERR(bdev))
e231c2ee 295 return ERR_CAST(bdev);
9361401e
DH
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
1da177e4
LT
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 */
3cdad428
HC
313SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
314 qid_t, id, void __user *, addr)
1da177e4
LT
315{
316 uint cmds, type;
317 struct super_block *sb = NULL;
1da177e4
LT
318 int ret;
319
320 cmds = cmd >> SUBCMDSHIFT;
321 type = cmd & SUBCMDMASK;
322
6ae09575
CH
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;
1da177e4
LT
332 }
333
6ae09575
CH
334 sb = quotactl_block(special);
335 if (IS_ERR(sb))
336 return PTR_ERR(sb);
337
c988afb5 338 ret = do_quotactl(sb, type, cmds, id, addr);
1da177e4 339
6ae09575 340 drop_super(sb);
1da177e4
LT
341 return ret;
342}
b716395e 343
7a6c8135 344#if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT)
b716395e
VT
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 */
349struct 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 */
362struct compat_fs_qfilestat {
363 compat_u64 dqb_bhardlimit;
364 compat_u64 qfs_nblks;
365 compat_uint_t qfs_nextents;
366};
367
368struct 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
382asmlinkage 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
This page took 0.459039 seconds and 5 git commands to generate.