xref: /OK3568_Linux_fs/kernel/fs/xfs/xfs_quotaops.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2008, Christoph Hellwig
4*4882a593Smuzhiyun  * All Rights Reserved.
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun #include "xfs.h"
7*4882a593Smuzhiyun #include "xfs_shared.h"
8*4882a593Smuzhiyun #include "xfs_format.h"
9*4882a593Smuzhiyun #include "xfs_log_format.h"
10*4882a593Smuzhiyun #include "xfs_trans_resv.h"
11*4882a593Smuzhiyun #include "xfs_mount.h"
12*4882a593Smuzhiyun #include "xfs_inode.h"
13*4882a593Smuzhiyun #include "xfs_quota.h"
14*4882a593Smuzhiyun #include "xfs_trans.h"
15*4882a593Smuzhiyun #include "xfs_icache.h"
16*4882a593Smuzhiyun #include "xfs_qm.h"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun static void
xfs_qm_fill_state(struct qc_type_state * tstate,struct xfs_mount * mp,struct xfs_inode * ip,xfs_ino_t ino,struct xfs_def_quota * defq)20*4882a593Smuzhiyun xfs_qm_fill_state(
21*4882a593Smuzhiyun 	struct qc_type_state	*tstate,
22*4882a593Smuzhiyun 	struct xfs_mount	*mp,
23*4882a593Smuzhiyun 	struct xfs_inode	*ip,
24*4882a593Smuzhiyun 	xfs_ino_t		ino,
25*4882a593Smuzhiyun 	struct xfs_def_quota	*defq)
26*4882a593Smuzhiyun {
27*4882a593Smuzhiyun 	bool			tempqip = false;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 	tstate->ino = ino;
30*4882a593Smuzhiyun 	if (!ip && ino == NULLFSINO)
31*4882a593Smuzhiyun 		return;
32*4882a593Smuzhiyun 	if (!ip) {
33*4882a593Smuzhiyun 		if (xfs_iget(mp, NULL, ino, 0, 0, &ip))
34*4882a593Smuzhiyun 			return;
35*4882a593Smuzhiyun 		tempqip = true;
36*4882a593Smuzhiyun 	}
37*4882a593Smuzhiyun 	tstate->flags |= QCI_SYSFILE;
38*4882a593Smuzhiyun 	tstate->blocks = ip->i_d.di_nblocks;
39*4882a593Smuzhiyun 	tstate->nextents = ip->i_df.if_nextents;
40*4882a593Smuzhiyun 	tstate->spc_timelimit = (u32)defq->blk.time;
41*4882a593Smuzhiyun 	tstate->ino_timelimit = (u32)defq->ino.time;
42*4882a593Smuzhiyun 	tstate->rt_spc_timelimit = (u32)defq->rtb.time;
43*4882a593Smuzhiyun 	tstate->spc_warnlimit = defq->blk.warn;
44*4882a593Smuzhiyun 	tstate->ino_warnlimit = defq->ino.warn;
45*4882a593Smuzhiyun 	tstate->rt_spc_warnlimit = defq->rtb.warn;
46*4882a593Smuzhiyun 	if (tempqip)
47*4882a593Smuzhiyun 		xfs_irele(ip);
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /*
51*4882a593Smuzhiyun  * Return quota status information, such as enforcements, quota file inode
52*4882a593Smuzhiyun  * numbers etc.
53*4882a593Smuzhiyun  */
54*4882a593Smuzhiyun static int
xfs_fs_get_quota_state(struct super_block * sb,struct qc_state * state)55*4882a593Smuzhiyun xfs_fs_get_quota_state(
56*4882a593Smuzhiyun 	struct super_block	*sb,
57*4882a593Smuzhiyun 	struct qc_state		*state)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	struct xfs_mount *mp = XFS_M(sb);
60*4882a593Smuzhiyun 	struct xfs_quotainfo *q = mp->m_quotainfo;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	memset(state, 0, sizeof(*state));
63*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
64*4882a593Smuzhiyun 		return 0;
65*4882a593Smuzhiyun 	state->s_incoredqs = q->qi_dquots;
66*4882a593Smuzhiyun 	if (XFS_IS_UQUOTA_RUNNING(mp))
67*4882a593Smuzhiyun 		state->s_state[USRQUOTA].flags |= QCI_ACCT_ENABLED;
68*4882a593Smuzhiyun 	if (XFS_IS_UQUOTA_ENFORCED(mp))
69*4882a593Smuzhiyun 		state->s_state[USRQUOTA].flags |= QCI_LIMITS_ENFORCED;
70*4882a593Smuzhiyun 	if (XFS_IS_GQUOTA_RUNNING(mp))
71*4882a593Smuzhiyun 		state->s_state[GRPQUOTA].flags |= QCI_ACCT_ENABLED;
72*4882a593Smuzhiyun 	if (XFS_IS_GQUOTA_ENFORCED(mp))
73*4882a593Smuzhiyun 		state->s_state[GRPQUOTA].flags |= QCI_LIMITS_ENFORCED;
74*4882a593Smuzhiyun 	if (XFS_IS_PQUOTA_RUNNING(mp))
75*4882a593Smuzhiyun 		state->s_state[PRJQUOTA].flags |= QCI_ACCT_ENABLED;
76*4882a593Smuzhiyun 	if (XFS_IS_PQUOTA_ENFORCED(mp))
77*4882a593Smuzhiyun 		state->s_state[PRJQUOTA].flags |= QCI_LIMITS_ENFORCED;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	xfs_qm_fill_state(&state->s_state[USRQUOTA], mp, q->qi_uquotaip,
80*4882a593Smuzhiyun 			  mp->m_sb.sb_uquotino, &q->qi_usr_default);
81*4882a593Smuzhiyun 	xfs_qm_fill_state(&state->s_state[GRPQUOTA], mp, q->qi_gquotaip,
82*4882a593Smuzhiyun 			  mp->m_sb.sb_gquotino, &q->qi_grp_default);
83*4882a593Smuzhiyun 	xfs_qm_fill_state(&state->s_state[PRJQUOTA], mp, q->qi_pquotaip,
84*4882a593Smuzhiyun 			  mp->m_sb.sb_pquotino, &q->qi_prj_default);
85*4882a593Smuzhiyun 	return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun STATIC xfs_dqtype_t
xfs_quota_type(int type)89*4882a593Smuzhiyun xfs_quota_type(int type)
90*4882a593Smuzhiyun {
91*4882a593Smuzhiyun 	switch (type) {
92*4882a593Smuzhiyun 	case USRQUOTA:
93*4882a593Smuzhiyun 		return XFS_DQTYPE_USER;
94*4882a593Smuzhiyun 	case GRPQUOTA:
95*4882a593Smuzhiyun 		return XFS_DQTYPE_GROUP;
96*4882a593Smuzhiyun 	default:
97*4882a593Smuzhiyun 		return XFS_DQTYPE_PROJ;
98*4882a593Smuzhiyun 	}
99*4882a593Smuzhiyun }
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun #define XFS_QC_SETINFO_MASK (QC_TIMER_MASK | QC_WARNS_MASK)
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun /*
104*4882a593Smuzhiyun  * Adjust quota timers & warnings
105*4882a593Smuzhiyun  */
106*4882a593Smuzhiyun static int
xfs_fs_set_info(struct super_block * sb,int type,struct qc_info * info)107*4882a593Smuzhiyun xfs_fs_set_info(
108*4882a593Smuzhiyun 	struct super_block	*sb,
109*4882a593Smuzhiyun 	int			type,
110*4882a593Smuzhiyun 	struct qc_info		*info)
111*4882a593Smuzhiyun {
112*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
113*4882a593Smuzhiyun 	struct qc_dqblk		newlim;
114*4882a593Smuzhiyun 
115*4882a593Smuzhiyun 	if (sb_rdonly(sb))
116*4882a593Smuzhiyun 		return -EROFS;
117*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
118*4882a593Smuzhiyun 		return -ENOSYS;
119*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_ON(mp))
120*4882a593Smuzhiyun 		return -ESRCH;
121*4882a593Smuzhiyun 	if (info->i_fieldmask & ~XFS_QC_SETINFO_MASK)
122*4882a593Smuzhiyun 		return -EINVAL;
123*4882a593Smuzhiyun 	if ((info->i_fieldmask & XFS_QC_SETINFO_MASK) == 0)
124*4882a593Smuzhiyun 		return 0;
125*4882a593Smuzhiyun 
126*4882a593Smuzhiyun 	newlim.d_fieldmask = info->i_fieldmask;
127*4882a593Smuzhiyun 	newlim.d_spc_timer = info->i_spc_timelimit;
128*4882a593Smuzhiyun 	newlim.d_ino_timer = info->i_ino_timelimit;
129*4882a593Smuzhiyun 	newlim.d_rt_spc_timer = info->i_rt_spc_timelimit;
130*4882a593Smuzhiyun 	newlim.d_ino_warns = info->i_ino_warnlimit;
131*4882a593Smuzhiyun 	newlim.d_spc_warns = info->i_spc_warnlimit;
132*4882a593Smuzhiyun 	newlim.d_rt_spc_warns = info->i_rt_spc_warnlimit;
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	return xfs_qm_scall_setqlim(mp, 0, xfs_quota_type(type), &newlim);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun static unsigned int
xfs_quota_flags(unsigned int uflags)138*4882a593Smuzhiyun xfs_quota_flags(unsigned int uflags)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	unsigned int flags = 0;
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 	if (uflags & FS_QUOTA_UDQ_ACCT)
143*4882a593Smuzhiyun 		flags |= XFS_UQUOTA_ACCT;
144*4882a593Smuzhiyun 	if (uflags & FS_QUOTA_PDQ_ACCT)
145*4882a593Smuzhiyun 		flags |= XFS_PQUOTA_ACCT;
146*4882a593Smuzhiyun 	if (uflags & FS_QUOTA_GDQ_ACCT)
147*4882a593Smuzhiyun 		flags |= XFS_GQUOTA_ACCT;
148*4882a593Smuzhiyun 	if (uflags & FS_QUOTA_UDQ_ENFD)
149*4882a593Smuzhiyun 		flags |= XFS_UQUOTA_ENFD;
150*4882a593Smuzhiyun 	if (uflags & FS_QUOTA_GDQ_ENFD)
151*4882a593Smuzhiyun 		flags |= XFS_GQUOTA_ENFD;
152*4882a593Smuzhiyun 	if (uflags & FS_QUOTA_PDQ_ENFD)
153*4882a593Smuzhiyun 		flags |= XFS_PQUOTA_ENFD;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	return flags;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun STATIC int
xfs_quota_enable(struct super_block * sb,unsigned int uflags)159*4882a593Smuzhiyun xfs_quota_enable(
160*4882a593Smuzhiyun 	struct super_block	*sb,
161*4882a593Smuzhiyun 	unsigned int		uflags)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	if (sb_rdonly(sb))
166*4882a593Smuzhiyun 		return -EROFS;
167*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
168*4882a593Smuzhiyun 		return -ENOSYS;
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun 	return xfs_qm_scall_quotaon(mp, xfs_quota_flags(uflags));
171*4882a593Smuzhiyun }
172*4882a593Smuzhiyun 
173*4882a593Smuzhiyun STATIC int
xfs_quota_disable(struct super_block * sb,unsigned int uflags)174*4882a593Smuzhiyun xfs_quota_disable(
175*4882a593Smuzhiyun 	struct super_block	*sb,
176*4882a593Smuzhiyun 	unsigned int		uflags)
177*4882a593Smuzhiyun {
178*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	if (sb_rdonly(sb))
181*4882a593Smuzhiyun 		return -EROFS;
182*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
183*4882a593Smuzhiyun 		return -ENOSYS;
184*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_ON(mp))
185*4882a593Smuzhiyun 		return -EINVAL;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	return xfs_qm_scall_quotaoff(mp, xfs_quota_flags(uflags));
188*4882a593Smuzhiyun }
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun STATIC int
xfs_fs_rm_xquota(struct super_block * sb,unsigned int uflags)191*4882a593Smuzhiyun xfs_fs_rm_xquota(
192*4882a593Smuzhiyun 	struct super_block	*sb,
193*4882a593Smuzhiyun 	unsigned int		uflags)
194*4882a593Smuzhiyun {
195*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
196*4882a593Smuzhiyun 	unsigned int		flags = 0;
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	if (sb_rdonly(sb))
199*4882a593Smuzhiyun 		return -EROFS;
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	if (XFS_IS_QUOTA_ON(mp))
202*4882a593Smuzhiyun 		return -EINVAL;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	if (uflags & ~(FS_USER_QUOTA | FS_GROUP_QUOTA | FS_PROJ_QUOTA))
205*4882a593Smuzhiyun 		return -EINVAL;
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun 	if (uflags & FS_USER_QUOTA)
208*4882a593Smuzhiyun 		flags |= XFS_QMOPT_UQUOTA;
209*4882a593Smuzhiyun 	if (uflags & FS_GROUP_QUOTA)
210*4882a593Smuzhiyun 		flags |= XFS_QMOPT_GQUOTA;
211*4882a593Smuzhiyun 	if (uflags & FS_PROJ_QUOTA)
212*4882a593Smuzhiyun 		flags |= XFS_QMOPT_PQUOTA;
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun 	return xfs_qm_scall_trunc_qfiles(mp, flags);
215*4882a593Smuzhiyun }
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun STATIC int
xfs_fs_get_dqblk(struct super_block * sb,struct kqid qid,struct qc_dqblk * qdq)218*4882a593Smuzhiyun xfs_fs_get_dqblk(
219*4882a593Smuzhiyun 	struct super_block	*sb,
220*4882a593Smuzhiyun 	struct kqid		qid,
221*4882a593Smuzhiyun 	struct qc_dqblk		*qdq)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
224*4882a593Smuzhiyun 	xfs_dqid_t		id;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
227*4882a593Smuzhiyun 		return -ENOSYS;
228*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_ON(mp))
229*4882a593Smuzhiyun 		return -ESRCH;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 	id = from_kqid(&init_user_ns, qid);
232*4882a593Smuzhiyun 	return xfs_qm_scall_getquota(mp, id, xfs_quota_type(qid.type), qdq);
233*4882a593Smuzhiyun }
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun /* Return quota info for active quota >= this qid */
236*4882a593Smuzhiyun STATIC int
xfs_fs_get_nextdqblk(struct super_block * sb,struct kqid * qid,struct qc_dqblk * qdq)237*4882a593Smuzhiyun xfs_fs_get_nextdqblk(
238*4882a593Smuzhiyun 	struct super_block	*sb,
239*4882a593Smuzhiyun 	struct kqid		*qid,
240*4882a593Smuzhiyun 	struct qc_dqblk		*qdq)
241*4882a593Smuzhiyun {
242*4882a593Smuzhiyun 	int			ret;
243*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
244*4882a593Smuzhiyun 	xfs_dqid_t		id;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
247*4882a593Smuzhiyun 		return -ENOSYS;
248*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_ON(mp))
249*4882a593Smuzhiyun 		return -ESRCH;
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun 	id = from_kqid(&init_user_ns, *qid);
252*4882a593Smuzhiyun 	ret = xfs_qm_scall_getquota_next(mp, &id, xfs_quota_type(qid->type),
253*4882a593Smuzhiyun 			qdq);
254*4882a593Smuzhiyun 	if (ret)
255*4882a593Smuzhiyun 		return ret;
256*4882a593Smuzhiyun 
257*4882a593Smuzhiyun 	/* ID may be different, so convert back what we got */
258*4882a593Smuzhiyun 	*qid = make_kqid(current_user_ns(), qid->type, id);
259*4882a593Smuzhiyun 	return 0;
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun STATIC int
xfs_fs_set_dqblk(struct super_block * sb,struct kqid qid,struct qc_dqblk * qdq)263*4882a593Smuzhiyun xfs_fs_set_dqblk(
264*4882a593Smuzhiyun 	struct super_block	*sb,
265*4882a593Smuzhiyun 	struct kqid		qid,
266*4882a593Smuzhiyun 	struct qc_dqblk		*qdq)
267*4882a593Smuzhiyun {
268*4882a593Smuzhiyun 	struct xfs_mount	*mp = XFS_M(sb);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	if (sb_rdonly(sb))
271*4882a593Smuzhiyun 		return -EROFS;
272*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_RUNNING(mp))
273*4882a593Smuzhiyun 		return -ENOSYS;
274*4882a593Smuzhiyun 	if (!XFS_IS_QUOTA_ON(mp))
275*4882a593Smuzhiyun 		return -ESRCH;
276*4882a593Smuzhiyun 
277*4882a593Smuzhiyun 	return xfs_qm_scall_setqlim(mp, from_kqid(&init_user_ns, qid),
278*4882a593Smuzhiyun 				     xfs_quota_type(qid.type), qdq);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun const struct quotactl_ops xfs_quotactl_operations = {
282*4882a593Smuzhiyun 	.get_state		= xfs_fs_get_quota_state,
283*4882a593Smuzhiyun 	.set_info		= xfs_fs_set_info,
284*4882a593Smuzhiyun 	.quota_enable		= xfs_quota_enable,
285*4882a593Smuzhiyun 	.quota_disable		= xfs_quota_disable,
286*4882a593Smuzhiyun 	.rm_xquota		= xfs_fs_rm_xquota,
287*4882a593Smuzhiyun 	.get_dqblk		= xfs_fs_get_dqblk,
288*4882a593Smuzhiyun 	.get_nextdqblk		= xfs_fs_get_nextdqblk,
289*4882a593Smuzhiyun 	.set_dqblk		= xfs_fs_set_dqblk,
290*4882a593Smuzhiyun };
291