blob: 4506c6596347986740fb15309cb2bc566c5b48ed [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Vasily Tarasovb7163952007-07-15 23:41:12 -070013#include <linux/compat.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/security.h>
16#include <linux/syscalls.h>
17#include <linux/buffer_head.h>
Randy Dunlap16f7e0f2006-01-11 12:17:46 -080018#include <linux/capability.h>
Adrian Bunkbe586ba2005-11-07 00:59:35 -080019#include <linux/quotaops.h>
Vasily Tarasovb7163952007-07-15 23:41:12 -070020#include <linux/types.h>
Christoph Hellwig8c4e4ac2010-02-16 03:44:51 -050021#include <linux/writeback.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022
Christoph Hellwigc988afb2010-02-16 03:44:50 -050023static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
24 qid_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070025{
Christoph Hellwigc988afb2010-02-16 03:44:50 -050026 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:
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 if (!capable(CAP_SYS_ADMIN))
43 return -EPERM;
44 }
45
Christoph Hellwigc988afb2010-02-16 03:44:50 -050046 return security_quotactl(cmd, type, id, sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070047}
48
Christoph Hellwig6ae09572010-02-16 03:44:49 -050049static int quota_sync_all(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070050{
Christoph Hellwig850b2012009-04-27 16:43:54 +020051 struct super_block *sb;
Christoph Hellwig6ae09572010-02-16 03:44:49 -050052 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;
Kirill Korotaev618f0632005-06-23 00:09:54 -070059
Kirill Korotaev618f0632005-06-23 00:09:54 -070060 spin_lock(&sb_lock);
61restart:
62 list_for_each_entry(sb, &super_blocks, s_list) {
Christoph Hellwig5fb324a2010-02-16 03:44:52 -050063 if (!sb->s_qcop || !sb->s_qcop->quota_sync)
64 continue;
65
Kirill Korotaev618f0632005-06-23 00:09:54 -070066 sb->s_count++;
67 spin_unlock(&sb_lock);
68 down_read(&sb->s_umount);
Christoph Hellwig850b2012009-04-27 16:43:54 +020069 if (sb->s_root)
Christoph Hellwig5fb324a2010-02-16 03:44:52 -050070 sb->s_qcop->quota_sync(sb, type, 1);
Kirill Korotaev618f0632005-06-23 00:09:54 -070071 up_read(&sb->s_umount);
72 spin_lock(&sb_lock);
73 if (__put_super_and_need_restart(sb))
74 goto restart;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 }
Kirill Korotaev618f0632005-06-23 00:09:54 -070076 spin_unlock(&sb_lock);
Christoph Hellwig6ae09572010-02-16 03:44:49 -050077
78 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -070079}
80
Christoph Hellwigc411e5f2010-02-16 03:44:47 -050081static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
82 void __user *addr)
83{
84 char *pathname;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -050085 int ret = -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -050086
87 pathname = getname(addr);
88 if (IS_ERR(pathname))
89 return PTR_ERR(pathname);
Christoph Hellwigf450d4f2010-02-16 03:44:48 -050090 if (sb->s_qcop->quota_on)
91 ret = sb->s_qcop->quota_on(sb, type, id, pathname, 0);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -050092 putname(pathname);
93 return ret;
94}
95
96static 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
112static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
113{
114 struct if_dqinfo info;
115 int ret;
116
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500117 if (!sb_has_quota_active(sb, type))
118 return -ESRCH;
119 if (!sb->s_qcop->get_info)
120 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500121 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
127static 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;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500133 if (!sb_has_quota_active(sb, type))
134 return -ESRCH;
135 if (!sb->s_qcop->set_info)
136 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500137 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
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500146 if (!sb_has_quota_active(sb, type))
147 return -ESRCH;
148 if (!sb->s_qcop->get_dqblk)
149 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500150 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;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500165 if (!sb_has_quota_active(sb, type))
166 return -ESRCH;
167 if (!sb->s_qcop->set_dqblk)
168 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500169 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;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500178 if (!sb->s_qcop->set_xstate)
179 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500180 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;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500187
188 if (!sb->s_qcop->get_xstate)
189 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500190 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
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;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500203 if (!sb->s_qcop->set_xquota)
204 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500205 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
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500214 if (!sb->s_qcop->get_xquota)
215 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500216 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700222/* Copy parameters and call proper function */
Jan Kara268157b2009-01-27 15:47:22 +0100223static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
224 void __user *addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225{
Christoph Hellwigc988afb2010-02-16 03:44:50 -0500226 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
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237 switch (cmd) {
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500238 case Q_QUOTAON:
239 return quota_quotaon(sb, type, cmd, id, addr);
240 case Q_QUOTAOFF:
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500241 if (!sb->s_qcop->quota_off)
242 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500243 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:
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500255 if (!sb->s_qcop->quota_sync)
256 return -ENOSYS;
Christoph Hellwig5fb324a2010-02-16 03:44:52 -0500257 return sb->s_qcop->quota_sync(sb, type, 1);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500258 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:
Christoph Hellwig8c4e4ac2010-02-16 03:44:51 -0500269 /* caller already holds s_umount */
270 if (sb->s_flags & MS_RDONLY)
271 return -EROFS;
272 writeback_inodes_sb(sb);
273 return 0;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500274 default:
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500275 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277}
278
279/*
David Howells93614012006-09-30 20:45:40 +0200280 * 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 */
Jan Kara7a2435d2009-01-27 01:47:11 +0100283static struct super_block *quotactl_block(const char __user *special)
David Howells93614012006-09-30 20:45:40 +0200284{
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))
David Howellse231c2e2008-02-07 00:15:26 -0800291 return ERR_CAST(tmp);
David Howells93614012006-09-30 20:45:40 +0200292 bdev = lookup_bdev(tmp);
293 putname(tmp);
294 if (IS_ERR(bdev))
David Howellse231c2e2008-02-07 00:15:26 -0800295 return ERR_CAST(bdev);
David Howells93614012006-09-30 20:45:40 +0200296 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/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700308 * 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 */
Heiko Carstens3cdad422009-01-14 14:14:22 +0100313SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
314 qid_t, id, void __user *, addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700315{
316 uint cmds, type;
317 struct super_block *sb = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 int ret;
319
320 cmds = cmd >> SUBCMDSHIFT;
321 type = cmd & SUBCMDMASK;
322
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500323 /*
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;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700332 }
333
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500334 sb = quotactl_block(special);
335 if (IS_ERR(sb))
336 return PTR_ERR(sb);
337
Christoph Hellwigc988afb2010-02-16 03:44:50 -0500338 ret = do_quotactl(sb, type, cmds, id, addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500340 drop_super(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 return ret;
342}
Vasily Tarasovb7163952007-07-15 23:41:12 -0700343
Tony Luck7a6c8132007-07-27 15:35:43 -0700344#if defined(CONFIG_COMPAT_FOR_U64_ALIGNMENT)
Vasily Tarasovb7163952007-07-15 23:41:12 -0700345/*
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