OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [quota.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.