xref: /linux/fs/quota/quota.c (revision d3b863248577504f6eecca2a464d6ddf86b71584)
1884d179dSJan Kara /*
2884d179dSJan Kara  * Quota code necessary even when VFS quota support is not compiled
3884d179dSJan Kara  * into the kernel.  The interesting stuff is over in dquot.c, here
4884d179dSJan Kara  * we have symbols for initial quotactl(2) handling, the sysctl(2)
5884d179dSJan Kara  * variables, etc - things needed even when quota support disabled.
6884d179dSJan Kara  */
7884d179dSJan Kara 
8884d179dSJan Kara #include <linux/fs.h>
9884d179dSJan Kara #include <linux/namei.h>
10884d179dSJan Kara #include <linux/slab.h>
11884d179dSJan Kara #include <asm/current.h>
12f3da9310SJeff Liu #include <linux/uaccess.h>
13884d179dSJan Kara #include <linux/kernel.h>
14884d179dSJan Kara #include <linux/security.h>
15884d179dSJan Kara #include <linux/syscalls.h>
16884d179dSJan Kara #include <linux/capability.h>
17884d179dSJan Kara #include <linux/quotaops.h>
18884d179dSJan Kara #include <linux/types.h>
198c4e4acdSChristoph Hellwig #include <linux/writeback.h>
20884d179dSJan Kara 
21c988afb5SChristoph Hellwig static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
22268157baSJan Kara 				     qid_t id)
23884d179dSJan Kara {
24c988afb5SChristoph Hellwig 	switch (cmd) {
25c988afb5SChristoph Hellwig 	/* these commands do not require any special privilegues */
26c988afb5SChristoph Hellwig 	case Q_GETFMT:
27c988afb5SChristoph Hellwig 	case Q_SYNC:
28c988afb5SChristoph Hellwig 	case Q_GETINFO:
29c988afb5SChristoph Hellwig 	case Q_XGETQSTAT:
30af30cb44SChandra Seetharaman 	case Q_XGETQSTATV:
31c988afb5SChristoph Hellwig 	case Q_XQUOTASYNC:
32c988afb5SChristoph Hellwig 		break;
33c988afb5SChristoph Hellwig 	/* allow to query information for dquots we "own" */
34c988afb5SChristoph Hellwig 	case Q_GETQUOTA:
35c988afb5SChristoph Hellwig 	case Q_XGETQUOTA:
3674a8a103SEric W. Biederman 		if ((type == USRQUOTA && uid_eq(current_euid(), make_kuid(current_user_ns(), id))) ||
3774a8a103SEric W. Biederman 		    (type == GRPQUOTA && in_egroup_p(make_kgid(current_user_ns(), id))))
38c988afb5SChristoph Hellwig 			break;
39c988afb5SChristoph Hellwig 		/*FALLTHROUGH*/
40c988afb5SChristoph Hellwig 	default:
41884d179dSJan Kara 		if (!capable(CAP_SYS_ADMIN))
42884d179dSJan Kara 			return -EPERM;
43884d179dSJan Kara 	}
44884d179dSJan Kara 
45c988afb5SChristoph Hellwig 	return security_quotactl(cmd, type, id, sb);
46884d179dSJan Kara }
47884d179dSJan Kara 
4801a05b33SAl Viro static void quota_sync_one(struct super_block *sb, void *arg)
4901a05b33SAl Viro {
502c5f648aSJan Kara 	int type = *(int *)arg;
512c5f648aSJan Kara 
522c5f648aSJan Kara 	if (sb->s_qcop && sb->s_qcop->quota_sync &&
532c5f648aSJan Kara 	    (sb->s_quota_types & (1 << type)))
542c5f648aSJan Kara 		sb->s_qcop->quota_sync(sb, type);
5501a05b33SAl Viro }
5601a05b33SAl Viro 
576ae09575SChristoph Hellwig static int quota_sync_all(int type)
58884d179dSJan Kara {
596ae09575SChristoph Hellwig 	int ret;
606ae09575SChristoph Hellwig 
616ae09575SChristoph Hellwig 	if (type >= MAXQUOTAS)
626ae09575SChristoph Hellwig 		return -EINVAL;
636ae09575SChristoph Hellwig 	ret = security_quotactl(Q_SYNC, type, 0, NULL);
6401a05b33SAl Viro 	if (!ret)
6501a05b33SAl Viro 		iterate_supers(quota_sync_one, &type);
666ae09575SChristoph Hellwig 	return ret;
67884d179dSJan Kara }
68884d179dSJan Kara 
69*d3b86324SJan Kara unsigned int qtype_enforce_flag(int type)
70*d3b86324SJan Kara {
71*d3b86324SJan Kara 	switch (type) {
72*d3b86324SJan Kara 	case USRQUOTA:
73*d3b86324SJan Kara 		return FS_QUOTA_UDQ_ENFD;
74*d3b86324SJan Kara 	case GRPQUOTA:
75*d3b86324SJan Kara 		return FS_QUOTA_GDQ_ENFD;
76*d3b86324SJan Kara 	case PRJQUOTA:
77*d3b86324SJan Kara 		return FS_QUOTA_PDQ_ENFD;
78*d3b86324SJan Kara 	}
79*d3b86324SJan Kara 	return 0;
80*d3b86324SJan Kara }
81*d3b86324SJan Kara 
82c411e5f6SChristoph Hellwig static int quota_quotaon(struct super_block *sb, int type, int cmd, qid_t id,
83f00c9e44SJan Kara 		         struct path *path)
84884d179dSJan Kara {
85*d3b86324SJan Kara 	if (!sb->s_qcop->quota_on && !sb->s_qcop->quota_on_meta &&
86*d3b86324SJan Kara 	    !sb->s_qcop->quota_enable)
87f00c9e44SJan Kara 		return -ENOSYS;
88f00c9e44SJan Kara 	if (sb->s_qcop->quota_on_meta)
89f00c9e44SJan Kara 		return sb->s_qcop->quota_on_meta(sb, type, id);
90*d3b86324SJan Kara 	if (sb->s_qcop->quota_enable)
91*d3b86324SJan Kara 		return sb->s_qcop->quota_enable(sb, qtype_enforce_flag(type));
92f00c9e44SJan Kara 	if (IS_ERR(path))
93f00c9e44SJan Kara 		return PTR_ERR(path);
94f00c9e44SJan Kara 	return sb->s_qcop->quota_on(sb, type, id, path);
95884d179dSJan Kara }
96884d179dSJan Kara 
97*d3b86324SJan Kara static int quota_quotaoff(struct super_block *sb, int type)
98*d3b86324SJan Kara {
99*d3b86324SJan Kara 	if (!sb->s_qcop->quota_off && !sb->s_qcop->quota_disable)
100*d3b86324SJan Kara 		return -ENOSYS;
101*d3b86324SJan Kara 	if (sb->s_qcop->quota_disable)
102*d3b86324SJan Kara 		return sb->s_qcop->quota_disable(sb, qtype_enforce_flag(type));
103*d3b86324SJan Kara 	return sb->s_qcop->quota_off(sb, type);
104*d3b86324SJan Kara }
105*d3b86324SJan Kara 
106c411e5f6SChristoph Hellwig static int quota_getfmt(struct super_block *sb, int type, void __user *addr)
107c411e5f6SChristoph Hellwig {
108884d179dSJan Kara 	__u32 fmt;
109884d179dSJan Kara 
110606cdccaSNiu Yawei 	mutex_lock(&sb_dqopt(sb)->dqonoff_mutex);
111884d179dSJan Kara 	if (!sb_has_quota_active(sb, type)) {
112606cdccaSNiu Yawei 		mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
113884d179dSJan Kara 		return -ESRCH;
114884d179dSJan Kara 	}
115884d179dSJan Kara 	fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id;
116606cdccaSNiu Yawei 	mutex_unlock(&sb_dqopt(sb)->dqonoff_mutex);
117884d179dSJan Kara 	if (copy_to_user(addr, &fmt, sizeof(fmt)))
118884d179dSJan Kara 		return -EFAULT;
119884d179dSJan Kara 	return 0;
120884d179dSJan Kara }
121c411e5f6SChristoph Hellwig 
122c411e5f6SChristoph Hellwig static int quota_getinfo(struct super_block *sb, int type, void __user *addr)
123c411e5f6SChristoph Hellwig {
124884d179dSJan Kara 	struct if_dqinfo info;
125c411e5f6SChristoph Hellwig 	int ret;
126884d179dSJan Kara 
127f450d4feSChristoph Hellwig 	if (!sb->s_qcop->get_info)
128f450d4feSChristoph Hellwig 		return -ENOSYS;
129268157baSJan Kara 	ret = sb->s_qcop->get_info(sb, type, &info);
130c411e5f6SChristoph Hellwig 	if (!ret && copy_to_user(addr, &info, sizeof(info)))
131884d179dSJan Kara 		return -EFAULT;
132c411e5f6SChristoph Hellwig 	return ret;
133884d179dSJan Kara }
134c411e5f6SChristoph Hellwig 
135c411e5f6SChristoph Hellwig static int quota_setinfo(struct super_block *sb, int type, void __user *addr)
136c411e5f6SChristoph Hellwig {
137884d179dSJan Kara 	struct if_dqinfo info;
138884d179dSJan Kara 
139884d179dSJan Kara 	if (copy_from_user(&info, addr, sizeof(info)))
140884d179dSJan Kara 		return -EFAULT;
141f450d4feSChristoph Hellwig 	if (!sb->s_qcop->set_info)
142f450d4feSChristoph Hellwig 		return -ENOSYS;
143884d179dSJan Kara 	return sb->s_qcop->set_info(sb, type, &info);
144884d179dSJan Kara }
145c411e5f6SChristoph Hellwig 
14614bf61ffSJan Kara static inline qsize_t qbtos(qsize_t blocks)
14714bf61ffSJan Kara {
14814bf61ffSJan Kara 	return blocks << QIF_DQBLKSIZE_BITS;
14914bf61ffSJan Kara }
15014bf61ffSJan Kara 
15114bf61ffSJan Kara static inline qsize_t stoqb(qsize_t space)
15214bf61ffSJan Kara {
15314bf61ffSJan Kara 	return (space + QIF_DQBLKSIZE - 1) >> QIF_DQBLKSIZE_BITS;
15414bf61ffSJan Kara }
15514bf61ffSJan Kara 
15614bf61ffSJan Kara static void copy_to_if_dqblk(struct if_dqblk *dst, struct qc_dqblk *src)
157b9b2dd36SChristoph Hellwig {
15818da65e7SDan Carpenter 	memset(dst, 0, sizeof(*dst));
15914bf61ffSJan Kara 	dst->dqb_bhardlimit = stoqb(src->d_spc_hardlimit);
16014bf61ffSJan Kara 	dst->dqb_bsoftlimit = stoqb(src->d_spc_softlimit);
16114bf61ffSJan Kara 	dst->dqb_curspace = src->d_space;
162b9b2dd36SChristoph Hellwig 	dst->dqb_ihardlimit = src->d_ino_hardlimit;
163b9b2dd36SChristoph Hellwig 	dst->dqb_isoftlimit = src->d_ino_softlimit;
16414bf61ffSJan Kara 	dst->dqb_curinodes = src->d_ino_count;
16514bf61ffSJan Kara 	dst->dqb_btime = src->d_spc_timer;
16614bf61ffSJan Kara 	dst->dqb_itime = src->d_ino_timer;
167b9b2dd36SChristoph Hellwig 	dst->dqb_valid = QIF_ALL;
168b9b2dd36SChristoph Hellwig }
169b9b2dd36SChristoph Hellwig 
170c411e5f6SChristoph Hellwig static int quota_getquota(struct super_block *sb, int type, qid_t id,
171c411e5f6SChristoph Hellwig 			  void __user *addr)
172c411e5f6SChristoph Hellwig {
17374a8a103SEric W. Biederman 	struct kqid qid;
17414bf61ffSJan Kara 	struct qc_dqblk fdq;
175884d179dSJan Kara 	struct if_dqblk idq;
176c411e5f6SChristoph Hellwig 	int ret;
177884d179dSJan Kara 
178f450d4feSChristoph Hellwig 	if (!sb->s_qcop->get_dqblk)
179f450d4feSChristoph Hellwig 		return -ENOSYS;
18074a8a103SEric W. Biederman 	qid = make_kqid(current_user_ns(), type, id);
18174a8a103SEric W. Biederman 	if (!qid_valid(qid))
18274a8a103SEric W. Biederman 		return -EINVAL;
18374a8a103SEric W. Biederman 	ret = sb->s_qcop->get_dqblk(sb, qid, &fdq);
184268157baSJan Kara 	if (ret)
185884d179dSJan Kara 		return ret;
186b9b2dd36SChristoph Hellwig 	copy_to_if_dqblk(&idq, &fdq);
187884d179dSJan Kara 	if (copy_to_user(addr, &idq, sizeof(idq)))
188884d179dSJan Kara 		return -EFAULT;
189884d179dSJan Kara 	return 0;
190884d179dSJan Kara }
191c411e5f6SChristoph Hellwig 
19214bf61ffSJan Kara static void copy_from_if_dqblk(struct qc_dqblk *dst, struct if_dqblk *src)
193c472b432SChristoph Hellwig {
19414bf61ffSJan Kara 	dst->d_spc_hardlimit = qbtos(src->dqb_bhardlimit);
19514bf61ffSJan Kara 	dst->d_spc_softlimit = qbtos(src->dqb_bsoftlimit);
19614bf61ffSJan Kara 	dst->d_space = src->dqb_curspace;
197c472b432SChristoph Hellwig 	dst->d_ino_hardlimit = src->dqb_ihardlimit;
198c472b432SChristoph Hellwig 	dst->d_ino_softlimit = src->dqb_isoftlimit;
19914bf61ffSJan Kara 	dst->d_ino_count = src->dqb_curinodes;
20014bf61ffSJan Kara 	dst->d_spc_timer = src->dqb_btime;
20114bf61ffSJan Kara 	dst->d_ino_timer = src->dqb_itime;
202c472b432SChristoph Hellwig 
203c472b432SChristoph Hellwig 	dst->d_fieldmask = 0;
204c472b432SChristoph Hellwig 	if (src->dqb_valid & QIF_BLIMITS)
20514bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPC_SOFT | QC_SPC_HARD;
206c472b432SChristoph Hellwig 	if (src->dqb_valid & QIF_SPACE)
20714bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPACE;
208c472b432SChristoph Hellwig 	if (src->dqb_valid & QIF_ILIMITS)
20914bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_SOFT | QC_INO_HARD;
210c472b432SChristoph Hellwig 	if (src->dqb_valid & QIF_INODES)
21114bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_COUNT;
212c472b432SChristoph Hellwig 	if (src->dqb_valid & QIF_BTIME)
21314bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPC_TIMER;
214c472b432SChristoph Hellwig 	if (src->dqb_valid & QIF_ITIME)
21514bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_TIMER;
216c472b432SChristoph Hellwig }
217c472b432SChristoph Hellwig 
218c411e5f6SChristoph Hellwig static int quota_setquota(struct super_block *sb, int type, qid_t id,
219c411e5f6SChristoph Hellwig 			  void __user *addr)
220c411e5f6SChristoph Hellwig {
22114bf61ffSJan Kara 	struct qc_dqblk fdq;
222884d179dSJan Kara 	struct if_dqblk idq;
22374a8a103SEric W. Biederman 	struct kqid qid;
224884d179dSJan Kara 
225884d179dSJan Kara 	if (copy_from_user(&idq, addr, sizeof(idq)))
226884d179dSJan Kara 		return -EFAULT;
227f450d4feSChristoph Hellwig 	if (!sb->s_qcop->set_dqblk)
228f450d4feSChristoph Hellwig 		return -ENOSYS;
22974a8a103SEric W. Biederman 	qid = make_kqid(current_user_ns(), type, id);
23074a8a103SEric W. Biederman 	if (!qid_valid(qid))
23174a8a103SEric W. Biederman 		return -EINVAL;
232c472b432SChristoph Hellwig 	copy_from_if_dqblk(&fdq, &idq);
23374a8a103SEric W. Biederman 	return sb->s_qcop->set_dqblk(sb, qid, &fdq);
234884d179dSJan Kara }
235884d179dSJan Kara 
23638e478c4SJan Kara static int quota_enable(struct super_block *sb, void __user *addr)
237c411e5f6SChristoph Hellwig {
238884d179dSJan Kara 	__u32 flags;
239884d179dSJan Kara 
240884d179dSJan Kara 	if (copy_from_user(&flags, addr, sizeof(flags)))
241884d179dSJan Kara 		return -EFAULT;
24238e478c4SJan Kara 	if (!sb->s_qcop->quota_enable)
243f450d4feSChristoph Hellwig 		return -ENOSYS;
24438e478c4SJan Kara 	return sb->s_qcop->quota_enable(sb, flags);
24538e478c4SJan Kara }
24638e478c4SJan Kara 
24738e478c4SJan Kara static int quota_disable(struct super_block *sb, void __user *addr)
24838e478c4SJan Kara {
24938e478c4SJan Kara 	__u32 flags;
25038e478c4SJan Kara 
25138e478c4SJan Kara 	if (copy_from_user(&flags, addr, sizeof(flags)))
25238e478c4SJan Kara 		return -EFAULT;
25338e478c4SJan Kara 	if (!sb->s_qcop->quota_disable)
25438e478c4SJan Kara 		return -ENOSYS;
25538e478c4SJan Kara 	return sb->s_qcop->quota_disable(sb, flags);
256884d179dSJan Kara }
257884d179dSJan Kara 
258c411e5f6SChristoph Hellwig static int quota_getxstate(struct super_block *sb, void __user *addr)
259c411e5f6SChristoph Hellwig {
260c411e5f6SChristoph Hellwig 	struct fs_quota_stat fqs;
261c411e5f6SChristoph Hellwig 	int ret;
262c411e5f6SChristoph Hellwig 
263f450d4feSChristoph Hellwig 	if (!sb->s_qcop->get_xstate)
264f450d4feSChristoph Hellwig 		return -ENOSYS;
265c411e5f6SChristoph Hellwig 	ret = sb->s_qcop->get_xstate(sb, &fqs);
266c411e5f6SChristoph Hellwig 	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
267884d179dSJan Kara 		return -EFAULT;
268c411e5f6SChristoph Hellwig 	return ret;
269884d179dSJan Kara }
270c411e5f6SChristoph Hellwig 
271af30cb44SChandra Seetharaman static int quota_getxstatev(struct super_block *sb, void __user *addr)
272af30cb44SChandra Seetharaman {
273af30cb44SChandra Seetharaman 	struct fs_quota_statv fqs;
274af30cb44SChandra Seetharaman 	int ret;
275af30cb44SChandra Seetharaman 
276af30cb44SChandra Seetharaman 	if (!sb->s_qcop->get_xstatev)
277af30cb44SChandra Seetharaman 		return -ENOSYS;
278af30cb44SChandra Seetharaman 
279af30cb44SChandra Seetharaman 	memset(&fqs, 0, sizeof(fqs));
280af30cb44SChandra Seetharaman 	if (copy_from_user(&fqs, addr, 1)) /* Just read qs_version */
281af30cb44SChandra Seetharaman 		return -EFAULT;
282af30cb44SChandra Seetharaman 
283af30cb44SChandra Seetharaman 	/* If this kernel doesn't support user specified version, fail */
284af30cb44SChandra Seetharaman 	switch (fqs.qs_version) {
285af30cb44SChandra Seetharaman 	case FS_QSTATV_VERSION1:
286af30cb44SChandra Seetharaman 		break;
287af30cb44SChandra Seetharaman 	default:
288af30cb44SChandra Seetharaman 		return -EINVAL;
289af30cb44SChandra Seetharaman 	}
290af30cb44SChandra Seetharaman 	ret = sb->s_qcop->get_xstatev(sb, &fqs);
291af30cb44SChandra Seetharaman 	if (!ret && copy_to_user(addr, &fqs, sizeof(fqs)))
292af30cb44SChandra Seetharaman 		return -EFAULT;
293af30cb44SChandra Seetharaman 	return ret;
294af30cb44SChandra Seetharaman }
295af30cb44SChandra Seetharaman 
29614bf61ffSJan Kara /*
29714bf61ffSJan Kara  * XFS defines BBTOB and BTOBB macros inside fs/xfs/ and we cannot move them
29814bf61ffSJan Kara  * out of there as xfsprogs rely on definitions being in that header file. So
29914bf61ffSJan Kara  * just define same functions here for quota purposes.
30014bf61ffSJan Kara  */
30114bf61ffSJan Kara #define XFS_BB_SHIFT 9
30214bf61ffSJan Kara 
30314bf61ffSJan Kara static inline u64 quota_bbtob(u64 blocks)
30414bf61ffSJan Kara {
30514bf61ffSJan Kara 	return blocks << XFS_BB_SHIFT;
30614bf61ffSJan Kara }
30714bf61ffSJan Kara 
30814bf61ffSJan Kara static inline u64 quota_btobb(u64 bytes)
30914bf61ffSJan Kara {
31014bf61ffSJan Kara 	return (bytes + (1 << XFS_BB_SHIFT) - 1) >> XFS_BB_SHIFT;
31114bf61ffSJan Kara }
31214bf61ffSJan Kara 
31314bf61ffSJan Kara static void copy_from_xfs_dqblk(struct qc_dqblk *dst, struct fs_disk_quota *src)
31414bf61ffSJan Kara {
31514bf61ffSJan Kara 	dst->d_spc_hardlimit = quota_bbtob(src->d_blk_hardlimit);
31614bf61ffSJan Kara 	dst->d_spc_softlimit = quota_bbtob(src->d_blk_softlimit);
31714bf61ffSJan Kara 	dst->d_ino_hardlimit = src->d_ino_hardlimit;
31814bf61ffSJan Kara 	dst->d_ino_softlimit = src->d_ino_softlimit;
31914bf61ffSJan Kara 	dst->d_space = quota_bbtob(src->d_bcount);
32014bf61ffSJan Kara 	dst->d_ino_count = src->d_icount;
32114bf61ffSJan Kara 	dst->d_ino_timer = src->d_itimer;
32214bf61ffSJan Kara 	dst->d_spc_timer = src->d_btimer;
32314bf61ffSJan Kara 	dst->d_ino_warns = src->d_iwarns;
32414bf61ffSJan Kara 	dst->d_spc_warns = src->d_bwarns;
32514bf61ffSJan Kara 	dst->d_rt_spc_hardlimit = quota_bbtob(src->d_rtb_hardlimit);
32614bf61ffSJan Kara 	dst->d_rt_spc_softlimit = quota_bbtob(src->d_rtb_softlimit);
32714bf61ffSJan Kara 	dst->d_rt_space = quota_bbtob(src->d_rtbcount);
32814bf61ffSJan Kara 	dst->d_rt_spc_timer = src->d_rtbtimer;
32914bf61ffSJan Kara 	dst->d_rt_spc_warns = src->d_rtbwarns;
33014bf61ffSJan Kara 	dst->d_fieldmask = 0;
33114bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_ISOFT)
33214bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_SOFT;
33314bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_IHARD)
33414bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_HARD;
33514bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_BSOFT)
33614bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPC_SOFT;
33714bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_BHARD)
33814bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPC_HARD;
33914bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_RTBSOFT)
34014bf61ffSJan Kara 		dst->d_fieldmask |= QC_RT_SPC_SOFT;
34114bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_RTBHARD)
34214bf61ffSJan Kara 		dst->d_fieldmask |= QC_RT_SPC_HARD;
34314bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_BTIMER)
34414bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPC_TIMER;
34514bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_ITIMER)
34614bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_TIMER;
34714bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_RTBTIMER)
34814bf61ffSJan Kara 		dst->d_fieldmask |= QC_RT_SPC_TIMER;
34914bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_BWARNS)
35014bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPC_WARNS;
35114bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_IWARNS)
35214bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_WARNS;
35314bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_RTBWARNS)
35414bf61ffSJan Kara 		dst->d_fieldmask |= QC_RT_SPC_WARNS;
35514bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_BCOUNT)
35614bf61ffSJan Kara 		dst->d_fieldmask |= QC_SPACE;
35714bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_ICOUNT)
35814bf61ffSJan Kara 		dst->d_fieldmask |= QC_INO_COUNT;
35914bf61ffSJan Kara 	if (src->d_fieldmask & FS_DQ_RTBCOUNT)
36014bf61ffSJan Kara 		dst->d_fieldmask |= QC_RT_SPACE;
36114bf61ffSJan Kara }
36214bf61ffSJan Kara 
363c411e5f6SChristoph Hellwig static int quota_setxquota(struct super_block *sb, int type, qid_t id,
364c411e5f6SChristoph Hellwig 			   void __user *addr)
365c411e5f6SChristoph Hellwig {
366884d179dSJan Kara 	struct fs_disk_quota fdq;
36714bf61ffSJan Kara 	struct qc_dqblk qdq;
36874a8a103SEric W. Biederman 	struct kqid qid;
369884d179dSJan Kara 
370884d179dSJan Kara 	if (copy_from_user(&fdq, addr, sizeof(fdq)))
371884d179dSJan Kara 		return -EFAULT;
372c472b432SChristoph Hellwig 	if (!sb->s_qcop->set_dqblk)
373f450d4feSChristoph Hellwig 		return -ENOSYS;
37474a8a103SEric W. Biederman 	qid = make_kqid(current_user_ns(), type, id);
37574a8a103SEric W. Biederman 	if (!qid_valid(qid))
37674a8a103SEric W. Biederman 		return -EINVAL;
37714bf61ffSJan Kara 	copy_from_xfs_dqblk(&qdq, &fdq);
37814bf61ffSJan Kara 	return sb->s_qcop->set_dqblk(sb, qid, &qdq);
37914bf61ffSJan Kara }
38014bf61ffSJan Kara 
38114bf61ffSJan Kara static void copy_to_xfs_dqblk(struct fs_disk_quota *dst, struct qc_dqblk *src,
38214bf61ffSJan Kara 			      int type, qid_t id)
38314bf61ffSJan Kara {
38414bf61ffSJan Kara 	memset(dst, 0, sizeof(*dst));
38514bf61ffSJan Kara 	dst->d_version = FS_DQUOT_VERSION;
38614bf61ffSJan Kara 	dst->d_id = id;
38714bf61ffSJan Kara 	if (type == USRQUOTA)
38814bf61ffSJan Kara 		dst->d_flags = FS_USER_QUOTA;
38914bf61ffSJan Kara 	else if (type == PRJQUOTA)
39014bf61ffSJan Kara 		dst->d_flags = FS_PROJ_QUOTA;
39114bf61ffSJan Kara 	else
39214bf61ffSJan Kara 		dst->d_flags = FS_GROUP_QUOTA;
39314bf61ffSJan Kara 	dst->d_blk_hardlimit = quota_btobb(src->d_spc_hardlimit);
39414bf61ffSJan Kara 	dst->d_blk_softlimit = quota_btobb(src->d_spc_softlimit);
39514bf61ffSJan Kara 	dst->d_ino_hardlimit = src->d_ino_hardlimit;
39614bf61ffSJan Kara 	dst->d_ino_softlimit = src->d_ino_softlimit;
39714bf61ffSJan Kara 	dst->d_bcount = quota_btobb(src->d_space);
39814bf61ffSJan Kara 	dst->d_icount = src->d_ino_count;
39914bf61ffSJan Kara 	dst->d_itimer = src->d_ino_timer;
40014bf61ffSJan Kara 	dst->d_btimer = src->d_spc_timer;
40114bf61ffSJan Kara 	dst->d_iwarns = src->d_ino_warns;
40214bf61ffSJan Kara 	dst->d_bwarns = src->d_spc_warns;
40314bf61ffSJan Kara 	dst->d_rtb_hardlimit = quota_btobb(src->d_rt_spc_hardlimit);
40414bf61ffSJan Kara 	dst->d_rtb_softlimit = quota_btobb(src->d_rt_spc_softlimit);
40514bf61ffSJan Kara 	dst->d_rtbcount = quota_btobb(src->d_rt_space);
40614bf61ffSJan Kara 	dst->d_rtbtimer = src->d_rt_spc_timer;
40714bf61ffSJan Kara 	dst->d_rtbwarns = src->d_rt_spc_warns;
408884d179dSJan Kara }
409c411e5f6SChristoph Hellwig 
410c411e5f6SChristoph Hellwig static int quota_getxquota(struct super_block *sb, int type, qid_t id,
411c411e5f6SChristoph Hellwig 			   void __user *addr)
412c411e5f6SChristoph Hellwig {
413884d179dSJan Kara 	struct fs_disk_quota fdq;
41414bf61ffSJan Kara 	struct qc_dqblk qdq;
41574a8a103SEric W. Biederman 	struct kqid qid;
416c411e5f6SChristoph Hellwig 	int ret;
417884d179dSJan Kara 
418b9b2dd36SChristoph Hellwig 	if (!sb->s_qcop->get_dqblk)
419f450d4feSChristoph Hellwig 		return -ENOSYS;
42074a8a103SEric W. Biederman 	qid = make_kqid(current_user_ns(), type, id);
42174a8a103SEric W. Biederman 	if (!qid_valid(qid))
42274a8a103SEric W. Biederman 		return -EINVAL;
42314bf61ffSJan Kara 	ret = sb->s_qcop->get_dqblk(sb, qid, &qdq);
42414bf61ffSJan Kara 	if (ret)
42514bf61ffSJan Kara 		return ret;
42614bf61ffSJan Kara 	copy_to_xfs_dqblk(&fdq, &qdq, type, id);
42714bf61ffSJan Kara 	if (copy_to_user(addr, &fdq, sizeof(fdq)))
428884d179dSJan Kara 		return -EFAULT;
429c411e5f6SChristoph Hellwig 	return ret;
430884d179dSJan Kara }
431c411e5f6SChristoph Hellwig 
4329da93f9bSEric Sandeen static int quota_rmxquota(struct super_block *sb, void __user *addr)
4339da93f9bSEric Sandeen {
4349da93f9bSEric Sandeen 	__u32 flags;
4359da93f9bSEric Sandeen 
4369da93f9bSEric Sandeen 	if (copy_from_user(&flags, addr, sizeof(flags)))
4379da93f9bSEric Sandeen 		return -EFAULT;
4389da93f9bSEric Sandeen 	if (!sb->s_qcop->rm_xquota)
4399da93f9bSEric Sandeen 		return -ENOSYS;
4409da93f9bSEric Sandeen 	return sb->s_qcop->rm_xquota(sb, flags);
4419da93f9bSEric Sandeen }
4429da93f9bSEric Sandeen 
443c411e5f6SChristoph Hellwig /* Copy parameters and call proper function */
444c411e5f6SChristoph Hellwig static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
445f00c9e44SJan Kara 		       void __user *addr, struct path *path)
446c411e5f6SChristoph Hellwig {
447c988afb5SChristoph Hellwig 	int ret;
448c988afb5SChristoph Hellwig 
449c988afb5SChristoph Hellwig 	if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
450c988afb5SChristoph Hellwig 		return -EINVAL;
4512c5f648aSJan Kara 	/*
4522c5f648aSJan Kara 	 * Quota not supported on this fs? Check this before s_quota_types
4532c5f648aSJan Kara 	 * since they needn't be set if quota is not supported at all.
4542c5f648aSJan Kara 	 */
455c988afb5SChristoph Hellwig 	if (!sb->s_qcop)
456c988afb5SChristoph Hellwig 		return -ENOSYS;
4572c5f648aSJan Kara 	if (!(sb->s_quota_types & (1 << type)))
4582c5f648aSJan Kara 		return -EINVAL;
459c988afb5SChristoph Hellwig 
460c988afb5SChristoph Hellwig 	ret = check_quotactl_permission(sb, type, cmd, id);
461c988afb5SChristoph Hellwig 	if (ret < 0)
462c988afb5SChristoph Hellwig 		return ret;
463c988afb5SChristoph Hellwig 
464c411e5f6SChristoph Hellwig 	switch (cmd) {
465c411e5f6SChristoph Hellwig 	case Q_QUOTAON:
466f00c9e44SJan Kara 		return quota_quotaon(sb, type, cmd, id, path);
467c411e5f6SChristoph Hellwig 	case Q_QUOTAOFF:
468*d3b86324SJan Kara 		return quota_quotaoff(sb, type);
469c411e5f6SChristoph Hellwig 	case Q_GETFMT:
470c411e5f6SChristoph Hellwig 		return quota_getfmt(sb, type, addr);
471c411e5f6SChristoph Hellwig 	case Q_GETINFO:
472c411e5f6SChristoph Hellwig 		return quota_getinfo(sb, type, addr);
473c411e5f6SChristoph Hellwig 	case Q_SETINFO:
474c411e5f6SChristoph Hellwig 		return quota_setinfo(sb, type, addr);
475c411e5f6SChristoph Hellwig 	case Q_GETQUOTA:
476c411e5f6SChristoph Hellwig 		return quota_getquota(sb, type, id, addr);
477c411e5f6SChristoph Hellwig 	case Q_SETQUOTA:
478c411e5f6SChristoph Hellwig 		return quota_setquota(sb, type, id, addr);
479c411e5f6SChristoph Hellwig 	case Q_SYNC:
480f450d4feSChristoph Hellwig 		if (!sb->s_qcop->quota_sync)
481f450d4feSChristoph Hellwig 			return -ENOSYS;
482ceed1723SJan Kara 		return sb->s_qcop->quota_sync(sb, type);
483c411e5f6SChristoph Hellwig 	case Q_XQUOTAON:
48438e478c4SJan Kara 		return quota_enable(sb, addr);
485c411e5f6SChristoph Hellwig 	case Q_XQUOTAOFF:
48638e478c4SJan Kara 		return quota_disable(sb, addr);
4879da93f9bSEric Sandeen 	case Q_XQUOTARM:
4889da93f9bSEric Sandeen 		return quota_rmxquota(sb, addr);
489c411e5f6SChristoph Hellwig 	case Q_XGETQSTAT:
490c411e5f6SChristoph Hellwig 		return quota_getxstate(sb, addr);
491af30cb44SChandra Seetharaman 	case Q_XGETQSTATV:
492af30cb44SChandra Seetharaman 		return quota_getxstatev(sb, addr);
493c411e5f6SChristoph Hellwig 	case Q_XSETQLIM:
494c411e5f6SChristoph Hellwig 		return quota_setxquota(sb, type, id, addr);
495c411e5f6SChristoph Hellwig 	case Q_XGETQUOTA:
496c411e5f6SChristoph Hellwig 		return quota_getxquota(sb, type, id, addr);
497884d179dSJan Kara 	case Q_XQUOTASYNC:
4988c4e4acdSChristoph Hellwig 		if (sb->s_flags & MS_RDONLY)
4998c4e4acdSChristoph Hellwig 			return -EROFS;
5004b217ed9SChristoph Hellwig 		/* XFS quotas are fully coherent now, making this call a noop */
5018c4e4acdSChristoph Hellwig 		return 0;
502884d179dSJan Kara 	default:
503f450d4feSChristoph Hellwig 		return -EINVAL;
504884d179dSJan Kara 	}
505884d179dSJan Kara }
506884d179dSJan Kara 
50756df1278SLee Jones #ifdef CONFIG_BLOCK
50856df1278SLee Jones 
509dcdbed85SJan Kara /* Return 1 if 'cmd' will block on frozen filesystem */
510dcdbed85SJan Kara static int quotactl_cmd_write(int cmd)
511dcdbed85SJan Kara {
512dcdbed85SJan Kara 	switch (cmd) {
513dcdbed85SJan Kara 	case Q_GETFMT:
514dcdbed85SJan Kara 	case Q_GETINFO:
515dcdbed85SJan Kara 	case Q_SYNC:
516dcdbed85SJan Kara 	case Q_XGETQSTAT:
517af30cb44SChandra Seetharaman 	case Q_XGETQSTATV:
518dcdbed85SJan Kara 	case Q_XGETQUOTA:
519dcdbed85SJan Kara 	case Q_XQUOTASYNC:
520dcdbed85SJan Kara 		return 0;
521dcdbed85SJan Kara 	}
522dcdbed85SJan Kara 	return 1;
523dcdbed85SJan Kara }
524dcdbed85SJan Kara 
52556df1278SLee Jones #endif /* CONFIG_BLOCK */
52656df1278SLee Jones 
527884d179dSJan Kara /*
528884d179dSJan Kara  * look up a superblock on which quota ops will be performed
529884d179dSJan Kara  * - use the name of a block device to find the superblock thereon
530884d179dSJan Kara  */
531dcdbed85SJan Kara static struct super_block *quotactl_block(const char __user *special, int cmd)
532884d179dSJan Kara {
533884d179dSJan Kara #ifdef CONFIG_BLOCK
534884d179dSJan Kara 	struct block_device *bdev;
535884d179dSJan Kara 	struct super_block *sb;
53691a27b2aSJeff Layton 	struct filename *tmp = getname(special);
537884d179dSJan Kara 
538884d179dSJan Kara 	if (IS_ERR(tmp))
539884d179dSJan Kara 		return ERR_CAST(tmp);
54091a27b2aSJeff Layton 	bdev = lookup_bdev(tmp->name);
541884d179dSJan Kara 	putname(tmp);
542884d179dSJan Kara 	if (IS_ERR(bdev))
543884d179dSJan Kara 		return ERR_CAST(bdev);
544dcdbed85SJan Kara 	if (quotactl_cmd_write(cmd))
545dcdbed85SJan Kara 		sb = get_super_thawed(bdev);
546dcdbed85SJan Kara 	else
547884d179dSJan Kara 		sb = get_super(bdev);
548884d179dSJan Kara 	bdput(bdev);
549884d179dSJan Kara 	if (!sb)
550884d179dSJan Kara 		return ERR_PTR(-ENODEV);
551884d179dSJan Kara 
552884d179dSJan Kara 	return sb;
553884d179dSJan Kara #else
554884d179dSJan Kara 	return ERR_PTR(-ENODEV);
555884d179dSJan Kara #endif
556884d179dSJan Kara }
557884d179dSJan Kara 
558884d179dSJan Kara /*
559884d179dSJan Kara  * This is the system call interface. This communicates with
560884d179dSJan Kara  * the user-level programs. Currently this only supports diskquota
561884d179dSJan Kara  * calls. Maybe we need to add the process quotas etc. in the future,
562884d179dSJan Kara  * but we probably should use rlimits for that.
563884d179dSJan Kara  */
564884d179dSJan Kara SYSCALL_DEFINE4(quotactl, unsigned int, cmd, const char __user *, special,
565884d179dSJan Kara 		qid_t, id, void __user *, addr)
566884d179dSJan Kara {
567884d179dSJan Kara 	uint cmds, type;
568884d179dSJan Kara 	struct super_block *sb = NULL;
569f00c9e44SJan Kara 	struct path path, *pathp = NULL;
570884d179dSJan Kara 	int ret;
571884d179dSJan Kara 
572884d179dSJan Kara 	cmds = cmd >> SUBCMDSHIFT;
573884d179dSJan Kara 	type = cmd & SUBCMDMASK;
574884d179dSJan Kara 
5756ae09575SChristoph Hellwig 	/*
5766ae09575SChristoph Hellwig 	 * As a special case Q_SYNC can be called without a specific device.
5776ae09575SChristoph Hellwig 	 * It will iterate all superblocks that have quota enabled and call
5786ae09575SChristoph Hellwig 	 * the sync action on each of them.
5796ae09575SChristoph Hellwig 	 */
5806ae09575SChristoph Hellwig 	if (!special) {
5816ae09575SChristoph Hellwig 		if (cmds == Q_SYNC)
5826ae09575SChristoph Hellwig 			return quota_sync_all(type);
5836ae09575SChristoph Hellwig 		return -ENODEV;
5846ae09575SChristoph Hellwig 	}
5856ae09575SChristoph Hellwig 
586f00c9e44SJan Kara 	/*
587f00c9e44SJan Kara 	 * Path for quotaon has to be resolved before grabbing superblock
588f00c9e44SJan Kara 	 * because that gets s_umount sem which is also possibly needed by path
589f00c9e44SJan Kara 	 * resolution (think about autofs) and thus deadlocks could arise.
590f00c9e44SJan Kara 	 */
591f00c9e44SJan Kara 	if (cmds == Q_QUOTAON) {
592815d405cSTrond Myklebust 		ret = user_path_at(AT_FDCWD, addr, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path);
593f00c9e44SJan Kara 		if (ret)
594f00c9e44SJan Kara 			pathp = ERR_PTR(ret);
595f00c9e44SJan Kara 		else
596f00c9e44SJan Kara 			pathp = &path;
597f00c9e44SJan Kara 	}
598f00c9e44SJan Kara 
599dcdbed85SJan Kara 	sb = quotactl_block(special, cmds);
6000aaa6188SJan Kara 	if (IS_ERR(sb)) {
6010aaa6188SJan Kara 		ret = PTR_ERR(sb);
6020aaa6188SJan Kara 		goto out;
6030aaa6188SJan Kara 	}
604884d179dSJan Kara 
605f00c9e44SJan Kara 	ret = do_quotactl(sb, type, cmds, id, addr, pathp);
606884d179dSJan Kara 
6076ae09575SChristoph Hellwig 	drop_super(sb);
6080aaa6188SJan Kara out:
609f00c9e44SJan Kara 	if (pathp && !IS_ERR(pathp))
610f00c9e44SJan Kara 		path_put(pathp);
611884d179dSJan Kara 	return ret;
612884d179dSJan Kara }
613