Pull one more egcs 1.1.2 workaround.
[linux-2.6/linux-mips.git] / fs / quota.c
blob0cc95fe48a91d5add444a0db708d5850b1d39a41
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 */
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/kernel.h>
14 #include <linux/smp_lock.h>
15 #include <linux/security.h>
17 /* Check validity of quotactl */
18 static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)
20 if (type >= MAXQUOTAS)
21 return -EINVAL;
22 /* Is operation supported? */
23 if (!sb->s_qcop)
24 return -ENOSYS;
26 switch (cmd) {
27 case Q_GETFMT:
28 break;
29 case Q_QUOTAON:
30 if (!sb->s_qcop->quota_on)
31 return -ENOSYS;
32 break;
33 case Q_QUOTAOFF:
34 if (!sb->s_qcop->quota_off)
35 return -ENOSYS;
36 break;
37 case Q_SETINFO:
38 if (!sb->s_qcop->set_info)
39 return -ENOSYS;
40 break;
41 case Q_GETINFO:
42 if (!sb->s_qcop->get_info)
43 return -ENOSYS;
44 break;
45 case Q_SETQUOTA:
46 if (!sb->s_qcop->set_dqblk)
47 return -ENOSYS;
48 break;
49 case Q_GETQUOTA:
50 if (!sb->s_qcop->get_dqblk)
51 return -ENOSYS;
52 break;
53 case Q_SYNC:
54 if (!sb->s_qcop->quota_sync)
55 return -ENOSYS;
56 break;
57 case Q_XQUOTAON:
58 case Q_XQUOTAOFF:
59 case Q_XQUOTARM:
60 if (!sb->s_qcop->set_xstate)
61 return -ENOSYS;
62 break;
63 case Q_XGETQSTAT:
64 if (!sb->s_qcop->get_xstate)
65 return -ENOSYS;
66 break;
67 case Q_XSETQLIM:
68 if (!sb->s_qcop->set_xquota)
69 return -ENOSYS;
70 break;
71 case Q_XGETQUOTA:
72 if (!sb->s_qcop->get_xquota)
73 return -ENOSYS;
74 break;
75 default:
76 return -EINVAL;
79 /* Is quota turned on for commands which need it? */
80 switch (cmd) {
81 case Q_GETFMT:
82 case Q_GETINFO:
83 case Q_QUOTAOFF:
84 case Q_SETINFO:
85 case Q_SETQUOTA:
86 case Q_GETQUOTA:
87 if (!sb_has_quota_enabled(sb, type))
88 return -ESRCH;
90 /* Check privileges */
91 if (cmd == Q_GETQUOTA || cmd == Q_XGETQUOTA) {
92 if (((type == USRQUOTA && current->euid != id) ||
93 (type == GRPQUOTA && !in_egroup_p(id))) &&
94 !capable(CAP_SYS_ADMIN))
95 return -EPERM;
97 else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO && cmd != Q_XGETQSTAT)
98 if (!capable(CAP_SYS_ADMIN))
99 return -EPERM;
101 return security_ops->quotactl (cmd, type, id, sb);
104 /* Resolve device pathname to superblock */
105 static struct super_block *resolve_dev(const char *path)
107 int ret;
108 mode_t mode;
109 struct nameidata nd;
110 struct block_device *bdev;
111 struct super_block *sb;
113 ret = user_path_walk(path, &nd);
114 if (ret)
115 goto out;
117 bdev = nd.dentry->d_inode->i_bdev;
118 mode = nd.dentry->d_inode->i_mode;
119 path_release(&nd);
121 ret = -ENOTBLK;
122 if (!S_ISBLK(mode))
123 goto out;
124 ret = -ENODEV;
125 sb = get_super(bdev);
126 if (!sb)
127 goto out;
128 return sb;
129 out:
130 return ERR_PTR(ret);
133 /* Copy parameters and call proper function */
134 static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr)
136 int ret;
138 switch (cmd) {
139 case Q_QUOTAON: {
140 char *pathname;
142 if (IS_ERR(pathname = getname(addr)))
143 return PTR_ERR(pathname);
144 ret = sb->s_qcop->quota_on(sb, type, id, pathname);
145 putname(pathname);
146 return ret;
148 case Q_QUOTAOFF:
149 return sb->s_qcop->quota_off(sb, type);
151 case Q_GETFMT: {
152 __u32 fmt;
154 fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
155 if (copy_to_user(addr, &fmt, sizeof(fmt)))
156 return -EFAULT;
157 return 0;
159 case Q_GETINFO: {
160 struct if_dqinfo info;
162 if ((ret = sb->s_qcop->get_info(sb, type, &info)))
163 return ret;
164 if (copy_to_user(addr, &info, sizeof(info)))
165 return -EFAULT;
166 return 0;
168 case Q_SETINFO: {
169 struct if_dqinfo info;
171 if (copy_from_user(&info, addr, sizeof(info)))
172 return -EFAULT;
173 return sb->s_qcop->set_info(sb, type, &info);
175 case Q_GETQUOTA: {
176 struct if_dqblk idq;
178 if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq)))
179 return ret;
180 if (copy_to_user(addr, &idq, sizeof(idq)))
181 return -EFAULT;
182 return 0;
184 case Q_SETQUOTA: {
185 struct if_dqblk idq;
187 if (copy_from_user(&idq, addr, sizeof(idq)))
188 return -EFAULT;
189 return sb->s_qcop->set_dqblk(sb, type, id, &idq);
191 case Q_SYNC:
192 return sb->s_qcop->quota_sync(sb, type);
194 case Q_XQUOTAON:
195 case Q_XQUOTAOFF:
196 case Q_XQUOTARM: {
197 __u32 flags;
199 if (copy_from_user(&flags, addr, sizeof(flags)))
200 return -EFAULT;
201 return sb->s_qcop->set_xstate(sb, flags, cmd);
203 case Q_XGETQSTAT: {
204 struct fs_quota_stat fqs;
206 if ((ret = sb->s_qcop->get_xstate(sb, &fqs)))
207 return ret;
208 if (copy_to_user(addr, &fqs, sizeof(fqs)))
209 return -EFAULT;
210 return 0;
212 case Q_XSETQLIM: {
213 struct fs_disk_quota fdq;
215 if (copy_from_user(&fdq, addr, sizeof(fdq)))
216 return -EFAULT;
217 return sb->s_qcop->set_xquota(sb, type, id, &fdq);
219 case Q_XGETQUOTA: {
220 struct fs_disk_quota fdq;
222 if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq)))
223 return ret;
224 if (copy_to_user(addr, &fdq, sizeof(fdq)))
225 return -EFAULT;
226 return 0;
228 /* We never reach here unless validity check is broken */
229 default:
230 BUG();
232 return 0;
236 * This is the system call interface. This communicates with
237 * the user-level programs. Currently this only supports diskquota
238 * calls. Maybe we need to add the process quotas etc. in the future,
239 * but we probably should use rlimits for that.
241 asmlinkage long sys_quotactl(unsigned int cmd, const char *special, qid_t id, caddr_t addr)
243 uint cmds, type;
244 struct super_block *sb = NULL;
245 int ret = -EINVAL;
247 lock_kernel();
248 cmds = cmd >> SUBCMDSHIFT;
249 type = cmd & SUBCMDMASK;
251 if (IS_ERR(sb = resolve_dev(special))) {
252 ret = PTR_ERR(sb);
253 sb = NULL;
254 goto out;
256 if ((ret = check_quotactl_valid(sb, type, cmds, id)) < 0)
257 goto out;
258 ret = do_quotactl(sb, type, cmds, id, addr);
259 out:
260 if (sb)
261 drop_super(sb);
262 unlock_kernel();
263 return ret;