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