FreeBSD/Linux Kernel Cross Reference
sys/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 }
Cache object: 77f89f0ed6d0fcf3f19d040dd43391e4
|