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