blob: ce78a70a596fb4e78a85e752e8548dc746fa1720 [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>
Jeff Liuf3da9312012-05-28 23:40:17 +080012#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include <linux/security.h>
15#include <linux/syscalls.h>
Randy Dunlap16f7e0f2006-01-11 12:17:46 -080016#include <linux/capability.h>
Adrian Bunkbe586ba2005-11-07 00:59:35 -080017#include <linux/quotaops.h>
Vasily Tarasovb7163952007-07-15 23:41:12 -070018#include <linux/types.h>
Christoph Hellwig8c4e4ac2010-02-16 03:44:51 -050019#include <linux/writeback.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Christoph Hellwigc988afb2010-02-16 03:44:50 -050021static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
22 qid_t id)
Linus Torvalds1da177e2005-04-16 15:20:36 -070023{
Christoph Hellwigc988afb2010-02-16 03:44:50 -050024 switch (cmd) {
25 /* these commands do not require any special privilegues */
26 case Q_GETFMT:
27 case Q_SYNC:
28 case Q_GETINFO:
29 case Q_XGETQSTAT:
Chandra Seetharamanaf30cb42013-08-06 17:27:07 -050030 case Q_XGETQSTATV:
Christoph Hellwigc988afb2010-02-16 03:44:50 -050031 case Q_XQUOTASYNC:
32 break;
33 /* allow to query information for dquots we "own" */
34 case Q_GETQUOTA:
35 case Q_XGETQUOTA:
Eric W. Biederman74a8a102012-09-16 02:07:49 -070036 if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
37 (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
Christoph Hellwigc988afb2010-02-16 03:44:50 -050038 break;
39 /*FALLTHROUGH*/
40 default:
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 if (!capable(CAP_SYS_ADMIN))
42 return -EPERM;
43 }
44
Christoph Hellwigc988afb2010-02-16 03:44:50 -050045 return security_quotactl(cmd, type, id, sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046}
47
Al Viro01a05b32010-03-23 06:06:58 -040048static void quota_sync_one(struct super_block *sb, void *arg)
49{
Jan Kara2c5f6482014-09-30 10:43:09 +020050 int type = *(int *)arg;
51
52 if (sb->s_qcop && sb->s_qcop->quota_sync &&
53 (sb->s_quota_types & (1 << type)))
54 sb->s_qcop->quota_sync(sb, type);
Al Viro01a05b32010-03-23 06:06:58 -040055}
56
Christoph Hellwig6ae09572010-02-16 03:44:49 -050057static int quota_sync_all(int type)
Linus Torvalds1da177e2005-04-16 15:20:36 -070058{
Christoph Hellwig6ae09572010-02-16 03:44:49 -050059 int ret;
60
61 if (type >= MAXQUOTAS)
62 return -EINVAL;
63 ret = security_quotactl(Q_SYNC, type, 0, NULL);
Al Viro01a05b32010-03-23 06:06:58 -040064 if (!ret)
65 iterate_supers(quota_sync_one, &type);
66 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -070067}
68
Jan Karad3b86322014-10-08 16:07:12 +020069unsigned int qtype_enforce_flag(int type)
70{
71 switch (type) {
72 case USRQUOTA:
73 return FS_QUOTA_UDQ_ENFD;
74 case GRPQUOTA:
75 return FS_QUOTA_GDQ_ENFD;
76 case PRJQUOTA:
77 return FS_QUOTA_PDQ_ENFD;
78 }
79 return 0;
80}
81
Christoph Hellwigc411e5f2010-02-16 03:44:47 -050082static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
Jan Karaf00c9e42010-09-15 17:38:58 +020083 struct path *path)
Christoph Hellwigc411e5f2010-02-16 03:44:47 -050084{
Jan Karad3b86322014-10-08 16:07:12 +020085 if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta &&
86 !sb->s_qcop->quota_enable)
Jan Karaf00c9e42010-09-15 17:38:58 +020087 return -ENOSYS;
88 if (sb->s_qcop->quota_on_meta)
89 return sb->s_qcop->quota_on_meta(sb, type, id);
Jan Karad3b86322014-10-08 16:07:12 +020090 if (sb->s_qcop->quota_enable)
91 return sb->s_qcop->quota_enable(sb, qtype_enforce_flag(type));
Jan Karaf00c9e42010-09-15 17:38:58 +020092 if (IS_ERR(path))
93 return PTR_ERR(path);
94 return sb->s_qcop->quota_on(sb, type, id, path);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -050095}
96
Jan Karad3b86322014-10-08 16:07:12 +020097static int quota_quotaoff(struct super_block *sb, int type)
98{
99 if (!sb->s_qcop->quota_off && !sb->s_qcop->quota_disable)
100 return -ENOSYS;
101 if (sb->s_qcop->quota_disable)
102 return sb->s_qcop->quota_disable(sb, qtype_enforce_flag(type));
103 return sb->s_qcop->quota_off(sb, type);
104}
105
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500106static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
107{
108 __u32 fmt;
109
Niu Yawei606cdcc2014-06-04 12:19:12 +0800110 mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500111 if (!sb_has_quota_active(sb, type)) {
Niu Yawei606cdcc2014-06-04 12:19:12 +0800112 mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500113 return -ESRCH;
114 }
115 fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
Niu Yawei606cdcc2014-06-04 12:19:12 +0800116 mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500117 if (copy_to_user(addr, &fmt, sizeof(fmt)))
118 return -EFAULT;
119 return 0;
120}
121
122static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
123{
124 struct if_dqinfo info;
125 int ret;
126
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500127 if (!sb->s_qcop->get_info)
128 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500129 ret = sb->s_qcop->get_info(sb, type, &info);
130 if (!ret && copy_to_user(addr, &info, sizeof(info)))
131 return -EFAULT;
132 return ret;
133}
134
135static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
136{
137 struct if_dqinfo info;
138
139 if (copy_from_user(&info, addr, sizeof(info)))
140 return -EFAULT;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500141 if (!sb->s_qcop->set_info)
142 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500143 return sb->s_qcop->set_info(sb, type, &info);
144}
145
Jan Kara14bf61f2014-10-09 16:03:13 +0200146static inline qsize_t qbtos(qsize_t blocks)
147{
148 return blocks << QIF_DQBLKSIZE_BITS;
149}
150
151static inline qsize_t stoqb(qsize_t space)
152{
153 return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
154}
155
156static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src)
Christoph Hellwigb9b2dd32010-05-06 17:04:58 -0400157{
Dan Carpenter18da65e2013-11-01 13:21:54 +0300158 memset(dst, 0, sizeof(*dst));
Jan Kara14bf61f2014-10-09 16:03:13 +0200159 dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
160 dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
161 dst->dqb_curspace = src->d_space;
Christoph Hellwigb9b2dd32010-05-06 17:04:58 -0400162 dst->dqb_ihardlimit = src->d_ino_hardlimit;
163 dst->dqb_isoftlimit = src->d_ino_softlimit;
Jan Kara14bf61f2014-10-09 16:03:13 +0200164 dst->dqb_curinodes = src->d_ino_count;
165 dst->dqb_btime = src->d_spc_timer;
166 dst->dqb_itime = src->d_ino_timer;
Christoph Hellwigb9b2dd32010-05-06 17:04:58 -0400167 dst->dqb_valid = QIF_ALL;
168}
169
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500170static int quota_getquota(struct super_block *sb, int type, qid_t id,
171 void __user *addr)
172{
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700173 struct kqid qid;
Jan Kara14bf61f2014-10-09 16:03:13 +0200174 struct qc_dqblk fdq;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500175 struct if_dqblk idq;
176 int ret;
177
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500178 if (!sb->s_qcop->get_dqblk)
179 return -ENOSYS;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700180 qid = make_kqid(current_user_ns(), type, id);
181 if (!qid_valid(qid))
182 return -EINVAL;
183 ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500184 if (ret)
185 return ret;
Christoph Hellwigb9b2dd32010-05-06 17:04:58 -0400186 copy_to_if_dqblk(&idq, &fdq);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500187 if (copy_to_user(addr, &idq, sizeof(idq)))
188 return -EFAULT;
189 return 0;
190}
191
Jan Kara14bf61f2014-10-09 16:03:13 +0200192static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
Christoph Hellwigc472b432010-05-06 17:05:17 -0400193{
Jan Kara14bf61f2014-10-09 16:03:13 +0200194 dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
195 dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
196 dst->d_space = src->dqb_curspace;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400197 dst->d_ino_hardlimit = src->dqb_ihardlimit;
198 dst->d_ino_softlimit = src->dqb_isoftlimit;
Jan Kara14bf61f2014-10-09 16:03:13 +0200199 dst->d_ino_count = src->dqb_curinodes;
200 dst->d_spc_timer = src->dqb_btime;
201 dst->d_ino_timer = src->dqb_itime;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400202
203 dst->d_fieldmask = 0;
204 if (src->dqb_valid & QIF_BLIMITS)
Jan Kara14bf61f2014-10-09 16:03:13 +0200205 dst->d_fieldmask |= QC_SPC_SOFT | QC_SPC_HARD;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400206 if (src->dqb_valid & QIF_SPACE)
Jan Kara14bf61f2014-10-09 16:03:13 +0200207 dst->d_fieldmask |= QC_SPACE;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400208 if (src->dqb_valid & QIF_ILIMITS)
Jan Kara14bf61f2014-10-09 16:03:13 +0200209 dst->d_fieldmask |= QC_INO_SOFT | QC_INO_HARD;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400210 if (src->dqb_valid & QIF_INODES)
Jan Kara14bf61f2014-10-09 16:03:13 +0200211 dst->d_fieldmask |= QC_INO_COUNT;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400212 if (src->dqb_valid & QIF_BTIME)
Jan Kara14bf61f2014-10-09 16:03:13 +0200213 dst->d_fieldmask |= QC_SPC_TIMER;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400214 if (src->dqb_valid & QIF_ITIME)
Jan Kara14bf61f2014-10-09 16:03:13 +0200215 dst->d_fieldmask |= QC_INO_TIMER;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400216}
217
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500218static int quota_setquota(struct super_block *sb, int type, qid_t id,
219 void __user *addr)
220{
Jan Kara14bf61f2014-10-09 16:03:13 +0200221 struct qc_dqblk fdq;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500222 struct if_dqblk idq;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700223 struct kqid qid;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500224
225 if (copy_from_user(&idq, addr, sizeof(idq)))
226 return -EFAULT;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500227 if (!sb->s_qcop->set_dqblk)
228 return -ENOSYS;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700229 qid = make_kqid(current_user_ns(), type, id);
230 if (!qid_valid(qid))
231 return -EINVAL;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400232 copy_from_if_dqblk(&fdq, &idq);
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700233 return sb->s_qcop->set_dqblk(sb, qid, &fdq);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500234}
235
Jan Kara38e478c2014-10-08 15:56:21 +0200236static int quota_enable(struct super_block *sb, void __user *addr)
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500237{
238 __u32 flags;
239
240 if (copy_from_user(&flags, addr, sizeof(flags)))
241 return -EFAULT;
Jan Kara38e478c2014-10-08 15:56:21 +0200242 if (!sb->s_qcop->quota_enable)
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500243 return -ENOSYS;
Jan Kara38e478c2014-10-08 15:56:21 +0200244 return sb->s_qcop->quota_enable(sb, flags);
245}
246
247static int quota_disable(struct super_block *sb, void __user *addr)
248{
249 __u32 flags;
250
251 if (copy_from_user(&flags, addr, sizeof(flags)))
252 return -EFAULT;
253 if (!sb->s_qcop->quota_disable)
254 return -ENOSYS;
255 return sb->s_qcop->quota_disable(sb, flags);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500256}
257
258static int quota_getxstate(struct super_block *sb, void __user *addr)
259{
260 struct fs_quota_stat fqs;
261 int ret;
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500262
263 if (!sb->s_qcop->get_xstate)
264 return -ENOSYS;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500265 ret = sb->s_qcop->get_xstate(sb, &fqs);
266 if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
267 return -EFAULT;
268 return ret;
269}
270
Chandra Seetharamanaf30cb42013-08-06 17:27:07 -0500271static int quota_getxstatev(struct super_block *sb, void __user *addr)
272{
273 struct fs_quota_statv fqs;
274 int ret;
275
276 if (!sb->s_qcop->get_xstatev)
277 return -ENOSYS;
278
279 memset(&fqs, 0, sizeof(fqs));
280 if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
281 return -EFAULT;
282
283 /* If this kernel doesn't support user specified version, fail */
284 switch (fqs.qs_version) {
285 case FS_QSTATV_VERSION1:
286 break;
287 default:
288 return -EINVAL;
289 }
290 ret = sb->s_qcop->get_xstatev(sb, &fqs);
291 if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
292 return -EFAULT;
293 return ret;
294}
295
Jan Kara14bf61f2014-10-09 16:03:13 +0200296/*
297 * XFS defines BBTOB and BTOBB macros inside fs/xfs/ and we cannot move them
298 * out of there as xfsprogs rely on definitions being in that header file. So
299 * just define same functions here for quota purposes.
300 */
301#define XFS_BB_SHIFT 9
302
303static inline u64 quota_bbtob(u64 blocks)
304{
305 return blocks << XFS_BB_SHIFT;
306}
307
308static inline u64 quota_btobb(u64 bytes)
309{
310 return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
311}
312
313static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
314{
315 dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
316 dst->d_spc_softlimit = quota_bbtob(src->d_blk_softlimit);
317 dst->d_ino_hardlimit = src->d_ino_hardlimit;
318 dst->d_ino_softlimit = src->d_ino_softlimit;
319 dst->d_space = quota_bbtob(src->d_bcount);
320 dst->d_ino_count = src->d_icount;
321 dst->d_ino_timer = src->d_itimer;
322 dst->d_spc_timer = src->d_btimer;
323 dst->d_ino_warns = src->d_iwarns;
324 dst->d_spc_warns = src->d_bwarns;
325 dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
326 dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
327 dst->d_rt_space = quota_bbtob(src->d_rtbcount);
328 dst->d_rt_spc_timer = src->d_rtbtimer;
329 dst->d_rt_spc_warns = src->d_rtbwarns;
330 dst->d_fieldmask = 0;
331 if (src->d_fieldmask & FS_DQ_ISOFT)
332 dst->d_fieldmask |= QC_INO_SOFT;
333 if (src->d_fieldmask & FS_DQ_IHARD)
334 dst->d_fieldmask |= QC_INO_HARD;
335 if (src->d_fieldmask & FS_DQ_BSOFT)
336 dst->d_fieldmask |= QC_SPC_SOFT;
337 if (src->d_fieldmask & FS_DQ_BHARD)
338 dst->d_fieldmask |= QC_SPC_HARD;
339 if (src->d_fieldmask & FS_DQ_RTBSOFT)
340 dst->d_fieldmask |= QC_RT_SPC_SOFT;
341 if (src->d_fieldmask & FS_DQ_RTBHARD)
342 dst->d_fieldmask |= QC_RT_SPC_HARD;
343 if (src->d_fieldmask & FS_DQ_BTIMER)
344 dst->d_fieldmask |= QC_SPC_TIMER;
345 if (src->d_fieldmask & FS_DQ_ITIMER)
346 dst->d_fieldmask |= QC_INO_TIMER;
347 if (src->d_fieldmask & FS_DQ_RTBTIMER)
348 dst->d_fieldmask |= QC_RT_SPC_TIMER;
349 if (src->d_fieldmask & FS_DQ_BWARNS)
350 dst->d_fieldmask |= QC_SPC_WARNS;
351 if (src->d_fieldmask & FS_DQ_IWARNS)
352 dst->d_fieldmask |= QC_INO_WARNS;
353 if (src->d_fieldmask & FS_DQ_RTBWARNS)
354 dst->d_fieldmask |= QC_RT_SPC_WARNS;
355 if (src->d_fieldmask & FS_DQ_BCOUNT)
356 dst->d_fieldmask |= QC_SPACE;
357 if (src->d_fieldmask & FS_DQ_ICOUNT)
358 dst->d_fieldmask |= QC_INO_COUNT;
359 if (src->d_fieldmask & FS_DQ_RTBCOUNT)
360 dst->d_fieldmask |= QC_RT_SPACE;
361}
362
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500363static int quota_setxquota(struct super_block *sb, int type, qid_t id,
364 void __user *addr)
365{
366 struct fs_disk_quota fdq;
Jan Kara14bf61f2014-10-09 16:03:13 +0200367 struct qc_dqblk qdq;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700368 struct kqid qid;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500369
370 if (copy_from_user(&fdq, addr, sizeof(fdq)))
371 return -EFAULT;
Christoph Hellwigc472b432010-05-06 17:05:17 -0400372 if (!sb->s_qcop->set_dqblk)
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500373 return -ENOSYS;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700374 qid = make_kqid(current_user_ns(), type, id);
375 if (!qid_valid(qid))
376 return -EINVAL;
Jan Kara14bf61f2014-10-09 16:03:13 +0200377 copy_from_xfs_dqblk(&qdq, &fdq);
378 return sb->s_qcop->set_dqblk(sb, qid, &qdq);
379}
380
381static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
382 int type, qid_t id)
383{
384 memset(dst, 0, sizeof(*dst));
385 dst->d_version = FS_DQUOT_VERSION;
386 dst->d_id = id;
387 if (type == USRQUOTA)
388 dst->d_flags = FS_USER_QUOTA;
389 else if (type == PRJQUOTA)
390 dst->d_flags = FS_PROJ_QUOTA;
391 else
392 dst->d_flags = FS_GROUP_QUOTA;
393 dst->d_blk_hardlimit = quota_btobb(src->d_spc_hardlimit);
394 dst->d_blk_softlimit = quota_btobb(src->d_spc_softlimit);
395 dst->d_ino_hardlimit = src->d_ino_hardlimit;
396 dst->d_ino_softlimit = src->d_ino_softlimit;
397 dst->d_bcount = quota_btobb(src->d_space);
398 dst->d_icount = src->d_ino_count;
399 dst->d_itimer = src->d_ino_timer;
400 dst->d_btimer = src->d_spc_timer;
401 dst->d_iwarns = src->d_ino_warns;
402 dst->d_bwarns = src->d_spc_warns;
403 dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
404 dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
405 dst->d_rtbcount = quota_btobb(src->d_rt_space);
406 dst->d_rtbtimer = src->d_rt_spc_timer;
407 dst->d_rtbwarns = src->d_rt_spc_warns;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500408}
409
410static int quota_getxquota(struct super_block *sb, int type, qid_t id,
411 void __user *addr)
412{
413 struct fs_disk_quota fdq;
Jan Kara14bf61f2014-10-09 16:03:13 +0200414 struct qc_dqblk qdq;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700415 struct kqid qid;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500416 int ret;
417
Christoph Hellwigb9b2dd32010-05-06 17:04:58 -0400418 if (!sb->s_qcop->get_dqblk)
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500419 return -ENOSYS;
Eric W. Biederman74a8a102012-09-16 02:07:49 -0700420 qid = make_kqid(current_user_ns(), type, id);
421 if (!qid_valid(qid))
422 return -EINVAL;
Jan Kara14bf61f2014-10-09 16:03:13 +0200423 ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
424 if (ret)
425 return ret;
426 copy_to_xfs_dqblk(&fdq, &qdq, type, id);
427 if (copy_to_user(addr, &fdq, sizeof(fdq)))
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500428 return -EFAULT;
429 return ret;
430}
431
Eric Sandeen9da93f92014-05-05 17:25:50 +1000432static int quota_rmxquota(struct super_block *sb, void __user *addr)
433{
434 __u32 flags;
435
436 if (copy_from_user(&flags, addr, sizeof(flags)))
437 return -EFAULT;
438 if (!sb->s_qcop->rm_xquota)
439 return -ENOSYS;
440 return sb->s_qcop->rm_xquota(sb, flags);
441}
442
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443/* Copy parameters and call proper function */
Jan Kara268157b2009-01-27 15:47:22 +0100444static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
Jan Karaf00c9e42010-09-15 17:38:58 +0200445 void __user *addr, struct path *path)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700446{
Christoph Hellwigc988afb2010-02-16 03:44:50 -0500447 int ret;
448
449 if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
450 return -EINVAL;
Jan Kara2c5f6482014-09-30 10:43:09 +0200451 /*
452 * Quota not supported on this fs? Check this before s_quota_types
453 * since they needn't be set if quota is not supported at all.
454 */
Christoph Hellwigc988afb2010-02-16 03:44:50 -0500455 if (!sb->s_qcop)
456 return -ENOSYS;
Jan Kara2c5f6482014-09-30 10:43:09 +0200457 if (!(sb->s_quota_types & (1 << type)))
458 return -EINVAL;
Christoph Hellwigc988afb2010-02-16 03:44:50 -0500459
460 ret = check_quotactl_permission(sb, type, cmd, id);
461 if (ret < 0)
462 return ret;
463
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 switch (cmd) {
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500465 case Q_QUOTAON:
Jan Karaf00c9e42010-09-15 17:38:58 +0200466 return quota_quotaon(sb, type, cmd, id, path);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500467 case Q_QUOTAOFF:
Jan Karad3b86322014-10-08 16:07:12 +0200468 return quota_quotaoff(sb, type);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500469 case Q_GETFMT:
470 return quota_getfmt(sb, type, addr);
471 case Q_GETINFO:
472 return quota_getinfo(sb, type, addr);
473 case Q_SETINFO:
474 return quota_setinfo(sb, type, addr);
475 case Q_GETQUOTA:
476 return quota_getquota(sb, type, id, addr);
477 case Q_SETQUOTA:
478 return quota_setquota(sb, type, id, addr);
479 case Q_SYNC:
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500480 if (!sb->s_qcop->quota_sync)
481 return -ENOSYS;
Jan Karaceed1722012-07-03 16:45:28 +0200482 return sb->s_qcop->quota_sync(sb, type);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500483 case Q_XQUOTAON:
Jan Kara38e478c2014-10-08 15:56:21 +0200484 return quota_enable(sb, addr);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500485 case Q_XQUOTAOFF:
Jan Kara38e478c2014-10-08 15:56:21 +0200486 return quota_disable(sb, addr);
Eric Sandeen9da93f92014-05-05 17:25:50 +1000487 case Q_XQUOTARM:
488 return quota_rmxquota(sb, addr);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500489 case Q_XGETQSTAT:
490 return quota_getxstate(sb, addr);
Chandra Seetharamanaf30cb42013-08-06 17:27:07 -0500491 case Q_XGETQSTATV:
492 return quota_getxstatev(sb, addr);
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500493 case Q_XSETQLIM:
494 return quota_setxquota(sb, type, id, addr);
495 case Q_XGETQUOTA:
496 return quota_getxquota(sb, type, id, addr);
497 case Q_XQUOTASYNC:
Christoph Hellwig8c4e4ac2010-02-16 03:44:51 -0500498 if (sb->s_flags & MS_RDONLY)
499 return -EROFS;
Christoph Hellwig4b217ed2012-02-20 02:28:18 +0000500 /* XFS quotas are fully coherent now, making this call a noop */
Christoph Hellwig8c4e4ac2010-02-16 03:44:51 -0500501 return 0;
Christoph Hellwigc411e5f2010-02-16 03:44:47 -0500502 default:
Christoph Hellwigf450d4f2010-02-16 03:44:48 -0500503 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700505}
506
Lee Jones56df1272012-11-03 23:02:28 +0100507#ifdef CONFIG_BLOCK
508
Jan Karadcdbed82012-02-10 11:03:01 +0100509/* Return 1 if 'cmd' will block on frozen filesystem */
510static int quotactl_cmd_write(int cmd)
511{
512 switch (cmd) {
513 case Q_GETFMT:
514 case Q_GETINFO:
515 case Q_SYNC:
516 case Q_XGETQSTAT:
Chandra Seetharamanaf30cb42013-08-06 17:27:07 -0500517 case Q_XGETQSTATV:
Jan Karadcdbed82012-02-10 11:03:01 +0100518 case Q_XGETQUOTA:
519 case Q_XQUOTASYNC:
520 return 0;
521 }
522 return 1;
523}
524
Lee Jones56df1272012-11-03 23:02:28 +0100525#endif /* CONFIG_BLOCK */
526
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527/*
David Howells93614012006-09-30 20:45:40 +0200528 * look up a superblock on which quota ops will be performed
529 * - use the name of a block device to find the superblock thereon
530 */
Jan Karadcdbed82012-02-10 11:03:01 +0100531static struct super_block *quotactl_block(const char __user *special, int cmd)
David Howells93614012006-09-30 20:45:40 +0200532{
533#ifdef CONFIG_BLOCK
534 struct block_device *bdev;
535 struct super_block *sb;
Jeff Layton91a27b22012-10-10 15:25:28 -0400536 struct filename *tmp = getname(special);
David Howells93614012006-09-30 20:45:40 +0200537
538 if (IS_ERR(tmp))
David Howellse231c2e2008-02-07 00:15:26 -0800539 return ERR_CAST(tmp);
Jeff Layton91a27b22012-10-10 15:25:28 -0400540 bdev = lookup_bdev(tmp->name);
David Howells93614012006-09-30 20:45:40 +0200541 putname(tmp);
542 if (IS_ERR(bdev))
David Howellse231c2e2008-02-07 00:15:26 -0800543 return ERR_CAST(bdev);
Jan Karadcdbed82012-02-10 11:03:01 +0100544 if (quotactl_cmd_write(cmd))
545 sb = get_super_thawed(bdev);
546 else
547 sb = get_super(bdev);
David Howells93614012006-09-30 20:45:40 +0200548 bdput(bdev);
549 if (!sb)
550 return ERR_PTR(-ENODEV);
551
552 return sb;
553#else
554 return ERR_PTR(-ENODEV);
555#endif
556}
557
558/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700559 * This is the system call interface. This communicates with
560 * the user-level programs. Currently this only supports diskquota
561 * calls. Maybe we need to add the process quotas etc. in the future,
562 * but we probably should use rlimits for that.
563 */
Heiko Carstens3cdad422009-01-14 14:14:22 +0100564SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
565 qid_t, id, void __user *, addr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566{
567 uint cmds, type;
568 struct super_block *sb = NULL;
Jan Karaf00c9e42010-09-15 17:38:58 +0200569 struct path path, *pathp = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570 int ret;
571
572 cmds = cmd >> SUBCMDSHIFT;
573 type = cmd & SUBCMDMASK;
574
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500575 /*
576 * As a special case Q_SYNC can be called without a specific device.
577 * It will iterate all superblocks that have quota enabled and call
578 * the sync action on each of them.
579 */
580 if (!special) {
581 if (cmds == Q_SYNC)
582 return quota_sync_all(type);
583 return -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700584 }
585
Jan Karaf00c9e42010-09-15 17:38:58 +0200586 /*
587 * Path for quotaon has to be resolved before grabbing superblock
588 * because that gets s_umount sem which is also possibly needed by path
589 * resolution (think about autofs) and thus deadlocks could arise.
590 */
591 if (cmds == Q_QUOTAON) {
Trond Myklebust815d4052011-09-26 20:36:09 -0400592 ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
Jan Karaf00c9e42010-09-15 17:38:58 +0200593 if (ret)
594 pathp = ERR_PTR(ret);
595 else
596 pathp = &path;
597 }
598
Jan Karadcdbed82012-02-10 11:03:01 +0100599 sb = quotactl_block(special, cmds);
Jan Kara0aaa6182011-10-10 18:32:06 +0200600 if (IS_ERR(sb)) {
601 ret = PTR_ERR(sb);
602 goto out;
603 }
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500604
Jan Karaf00c9e42010-09-15 17:38:58 +0200605 ret = do_quotactl(sb, type, cmds, id, addr, pathp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
Christoph Hellwig6ae09572010-02-16 03:44:49 -0500607 drop_super(sb);
Jan Kara0aaa6182011-10-10 18:32:06 +0200608out:
Jan Karaf00c9e42010-09-15 17:38:58 +0200609 if (pathp && !IS_ERR(pathp))
610 path_put(pathp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700611 return ret;
612}