cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

xfs_qm_syscalls.c (12940B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
      4 * All Rights Reserved.
      5 */
      6
      7
      8#include "xfs.h"
      9#include "xfs_fs.h"
     10#include "xfs_shared.h"
     11#include "xfs_format.h"
     12#include "xfs_log_format.h"
     13#include "xfs_trans_resv.h"
     14#include "xfs_sb.h"
     15#include "xfs_mount.h"
     16#include "xfs_inode.h"
     17#include "xfs_trans.h"
     18#include "xfs_quota.h"
     19#include "xfs_qm.h"
     20#include "xfs_icache.h"
     21
     22int
     23xfs_qm_scall_quotaoff(
     24	xfs_mount_t		*mp,
     25	uint			flags)
     26{
     27	/*
     28	 * No file system can have quotas enabled on disk but not in core.
     29	 * Note that quota utilities (like quotaoff) _expect_
     30	 * errno == -EEXIST here.
     31	 */
     32	if ((mp->m_qflags & flags) == 0)
     33		return -EEXIST;
     34
     35	/*
     36	 * We do not support actually turning off quota accounting any more.
     37	 * Just log a warning and ignore the accounting related flags.
     38	 */
     39	if (flags & XFS_ALL_QUOTA_ACCT)
     40		xfs_info(mp, "disabling of quota accounting not supported.");
     41
     42	mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
     43	mp->m_qflags &= ~(flags & XFS_ALL_QUOTA_ENFD);
     44	spin_lock(&mp->m_sb_lock);
     45	mp->m_sb.sb_qflags = mp->m_qflags;
     46	spin_unlock(&mp->m_sb_lock);
     47	mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);
     48
     49	/* XXX what to do if error ? Revert back to old vals incore ? */
     50	return xfs_sync_sb(mp, false);
     51}
     52
     53STATIC int
     54xfs_qm_scall_trunc_qfile(
     55	struct xfs_mount	*mp,
     56	xfs_ino_t		ino)
     57{
     58	struct xfs_inode	*ip;
     59	struct xfs_trans	*tp;
     60	int			error;
     61
     62	if (ino == NULLFSINO)
     63		return 0;
     64
     65	error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
     66	if (error)
     67		return error;
     68
     69	xfs_ilock(ip, XFS_IOLOCK_EXCL);
     70
     71	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
     72	if (error) {
     73		xfs_iunlock(ip, XFS_IOLOCK_EXCL);
     74		goto out_put;
     75	}
     76
     77	xfs_ilock(ip, XFS_ILOCK_EXCL);
     78	xfs_trans_ijoin(tp, ip, 0);
     79
     80	ip->i_disk_size = 0;
     81	xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
     82
     83	error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
     84	if (error) {
     85		xfs_trans_cancel(tp);
     86		goto out_unlock;
     87	}
     88
     89	ASSERT(ip->i_df.if_nextents == 0);
     90
     91	xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
     92	error = xfs_trans_commit(tp);
     93
     94out_unlock:
     95	xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
     96out_put:
     97	xfs_irele(ip);
     98	return error;
     99}
    100
    101int
    102xfs_qm_scall_trunc_qfiles(
    103	xfs_mount_t	*mp,
    104	uint		flags)
    105{
    106	int		error = -EINVAL;
    107
    108	if (!xfs_has_quota(mp) || flags == 0 ||
    109	    (flags & ~XFS_QMOPT_QUOTALL)) {
    110		xfs_debug(mp, "%s: flags=%x m_qflags=%x",
    111			__func__, flags, mp->m_qflags);
    112		return -EINVAL;
    113	}
    114
    115	if (flags & XFS_QMOPT_UQUOTA) {
    116		error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
    117		if (error)
    118			return error;
    119	}
    120	if (flags & XFS_QMOPT_GQUOTA) {
    121		error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
    122		if (error)
    123			return error;
    124	}
    125	if (flags & XFS_QMOPT_PQUOTA)
    126		error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);
    127
    128	return error;
    129}
    130
    131/*
    132 * Switch on (a given) quota enforcement for a filesystem.  This takes
    133 * effect immediately.
    134 * (Switching on quota accounting must be done at mount time.)
    135 */
    136int
    137xfs_qm_scall_quotaon(
    138	xfs_mount_t	*mp,
    139	uint		flags)
    140{
    141	int		error;
    142	uint		qf;
    143
    144	/*
    145	 * Switching on quota accounting must be done at mount time,
    146	 * only consider quota enforcement stuff here.
    147	 */
    148	flags &= XFS_ALL_QUOTA_ENFD;
    149
    150	if (flags == 0) {
    151		xfs_debug(mp, "%s: zero flags, m_qflags=%x",
    152			__func__, mp->m_qflags);
    153		return -EINVAL;
    154	}
    155
    156	/*
    157	 * Can't enforce without accounting. We check the superblock
    158	 * qflags here instead of m_qflags because rootfs can have
    159	 * quota acct on ondisk without m_qflags' knowing.
    160	 */
    161	if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
    162	     (flags & XFS_UQUOTA_ENFD)) ||
    163	    ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
    164	     (flags & XFS_GQUOTA_ENFD)) ||
    165	    ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
    166	     (flags & XFS_PQUOTA_ENFD))) {
    167		xfs_debug(mp,
    168			"%s: Can't enforce without acct, flags=%x sbflags=%x",
    169			__func__, flags, mp->m_sb.sb_qflags);
    170		return -EINVAL;
    171	}
    172	/*
    173	 * If everything's up to-date incore, then don't waste time.
    174	 */
    175	if ((mp->m_qflags & flags) == flags)
    176		return -EEXIST;
    177
    178	/*
    179	 * Change sb_qflags on disk but not incore mp->qflags
    180	 * if this is the root filesystem.
    181	 */
    182	spin_lock(&mp->m_sb_lock);
    183	qf = mp->m_sb.sb_qflags;
    184	mp->m_sb.sb_qflags = qf | flags;
    185	spin_unlock(&mp->m_sb_lock);
    186
    187	/*
    188	 * There's nothing to change if it's the same.
    189	 */
    190	if ((qf & flags) == flags)
    191		return -EEXIST;
    192
    193	error = xfs_sync_sb(mp, false);
    194	if (error)
    195		return error;
    196	/*
    197	 * If we aren't trying to switch on quota enforcement, we are done.
    198	 */
    199	if  (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
    200	     (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
    201	     ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
    202	     (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
    203	     ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
    204	     (mp->m_qflags & XFS_GQUOTA_ACCT)))
    205		return 0;
    206
    207	if (!XFS_IS_QUOTA_ON(mp))
    208		return -ESRCH;
    209
    210	/*
    211	 * Switch on quota enforcement in core.
    212	 */
    213	mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
    214	mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
    215	mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);
    216
    217	return 0;
    218}
    219
    220#define XFS_QC_MASK (QC_LIMIT_MASK | QC_TIMER_MASK)
    221
    222/*
    223 * Adjust limits of this quota, and the defaults if passed in.  Returns true
    224 * if the new limits made sense and were applied, false otherwise.
    225 */
    226static inline bool
    227xfs_setqlim_limits(
    228	struct xfs_mount	*mp,
    229	struct xfs_dquot_res	*res,
    230	struct xfs_quota_limits	*qlim,
    231	xfs_qcnt_t		hard,
    232	xfs_qcnt_t		soft,
    233	const char		*tag)
    234{
    235	/* The hard limit can't be less than the soft limit. */
    236	if (hard != 0 && hard < soft) {
    237		xfs_debug(mp, "%shard %lld < %ssoft %lld", tag, hard, tag,
    238				soft);
    239		return false;
    240	}
    241
    242	res->hardlimit = hard;
    243	res->softlimit = soft;
    244	if (qlim) {
    245		qlim->hard = hard;
    246		qlim->soft = soft;
    247	}
    248
    249	return true;
    250}
    251
    252static inline void
    253xfs_setqlim_timer(
    254	struct xfs_mount	*mp,
    255	struct xfs_dquot_res	*res,
    256	struct xfs_quota_limits	*qlim,
    257	s64			timer)
    258{
    259	if (qlim) {
    260		/* Set the length of the default grace period. */
    261		res->timer = xfs_dquot_set_grace_period(timer);
    262		qlim->time = res->timer;
    263	} else {
    264		/* Set the grace period expiration on a quota. */
    265		res->timer = xfs_dquot_set_timeout(mp, timer);
    266	}
    267}
    268
    269/*
    270 * Adjust quota limits, and start/stop timers accordingly.
    271 */
    272int
    273xfs_qm_scall_setqlim(
    274	struct xfs_mount	*mp,
    275	xfs_dqid_t		id,
    276	xfs_dqtype_t		type,
    277	struct qc_dqblk		*newlim)
    278{
    279	struct xfs_quotainfo	*q = mp->m_quotainfo;
    280	struct xfs_dquot	*dqp;
    281	struct xfs_trans	*tp;
    282	struct xfs_def_quota	*defq;
    283	struct xfs_dquot_res	*res;
    284	struct xfs_quota_limits	*qlim;
    285	int			error;
    286	xfs_qcnt_t		hard, soft;
    287
    288	if (newlim->d_fieldmask & ~XFS_QC_MASK)
    289		return -EINVAL;
    290	if ((newlim->d_fieldmask & XFS_QC_MASK) == 0)
    291		return 0;
    292
    293	/*
    294	 * Get the dquot (locked) before we start, as we need to do a
    295	 * transaction to allocate it if it doesn't exist. Once we have the
    296	 * dquot, unlock it so we can start the next transaction safely. We hold
    297	 * a reference to the dquot, so it's safe to do this unlock/lock without
    298	 * it being reclaimed in the mean time.
    299	 */
    300	error = xfs_qm_dqget(mp, id, type, true, &dqp);
    301	if (error) {
    302		ASSERT(error != -ENOENT);
    303		return error;
    304	}
    305
    306	defq = xfs_get_defquota(q, xfs_dquot_type(dqp));
    307	xfs_dqunlock(dqp);
    308
    309	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_setqlim, 0, 0, 0, &tp);
    310	if (error)
    311		goto out_rele;
    312
    313	xfs_dqlock(dqp);
    314	xfs_trans_dqjoin(tp, dqp);
    315
    316	/*
    317	 * Update quota limits, warnings, and timers, and the defaults
    318	 * if we're touching id == 0.
    319	 *
    320	 * Make sure that hardlimits are >= soft limits before changing.
    321	 *
    322	 * Update warnings counter(s) if requested.
    323	 *
    324	 * Timelimits for the super user set the relative time the other users
    325	 * can be over quota for this file system. If it is zero a default is
    326	 * used.  Ditto for the default soft and hard limit values (already
    327	 * done, above), and for warnings.
    328	 *
    329	 * For other IDs, userspace can bump out the grace period if over
    330	 * the soft limit.
    331	 */
    332
    333	/* Blocks on the data device. */
    334	hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
    335		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
    336			dqp->q_blk.hardlimit;
    337	soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
    338		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
    339			dqp->q_blk.softlimit;
    340	res = &dqp->q_blk;
    341	qlim = id == 0 ? &defq->blk : NULL;
    342
    343	if (xfs_setqlim_limits(mp, res, qlim, hard, soft, "blk"))
    344		xfs_dquot_set_prealloc_limits(dqp);
    345	if (newlim->d_fieldmask & QC_SPC_TIMER)
    346		xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
    347
    348	/* Blocks on the realtime device. */
    349	hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
    350		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
    351			dqp->q_rtb.hardlimit;
    352	soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
    353		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
    354			dqp->q_rtb.softlimit;
    355	res = &dqp->q_rtb;
    356	qlim = id == 0 ? &defq->rtb : NULL;
    357
    358	xfs_setqlim_limits(mp, res, qlim, hard, soft, "rtb");
    359	if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
    360		xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer);
    361
    362	/* Inodes */
    363	hard = (newlim->d_fieldmask & QC_INO_HARD) ?
    364		(xfs_qcnt_t) newlim->d_ino_hardlimit :
    365			dqp->q_ino.hardlimit;
    366	soft = (newlim->d_fieldmask & QC_INO_SOFT) ?
    367		(xfs_qcnt_t) newlim->d_ino_softlimit :
    368			dqp->q_ino.softlimit;
    369	res = &dqp->q_ino;
    370	qlim = id == 0 ? &defq->ino : NULL;
    371
    372	xfs_setqlim_limits(mp, res, qlim, hard, soft, "ino");
    373	if (newlim->d_fieldmask & QC_INO_TIMER)
    374		xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer);
    375
    376	if (id != 0) {
    377		/*
    378		 * If the user is now over quota, start the timelimit.
    379		 * The user will not be 'warned'.
    380		 * Note that we keep the timers ticking, whether enforcement
    381		 * is on or off. We don't really want to bother with iterating
    382		 * over all ondisk dquots and turning the timers on/off.
    383		 */
    384		xfs_qm_adjust_dqtimers(dqp);
    385	}
    386	dqp->q_flags |= XFS_DQFLAG_DIRTY;
    387	xfs_trans_log_dquot(tp, dqp);
    388
    389	error = xfs_trans_commit(tp);
    390
    391out_rele:
    392	xfs_qm_dqrele(dqp);
    393	return error;
    394}
    395
    396/* Fill out the quota context. */
    397static void
    398xfs_qm_scall_getquota_fill_qc(
    399	struct xfs_mount	*mp,
    400	xfs_dqtype_t		type,
    401	const struct xfs_dquot	*dqp,
    402	struct qc_dqblk		*dst)
    403{
    404	memset(dst, 0, sizeof(*dst));
    405	dst->d_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_blk.hardlimit);
    406	dst->d_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_blk.softlimit);
    407	dst->d_ino_hardlimit = dqp->q_ino.hardlimit;
    408	dst->d_ino_softlimit = dqp->q_ino.softlimit;
    409	dst->d_space = XFS_FSB_TO_B(mp, dqp->q_blk.reserved);
    410	dst->d_ino_count = dqp->q_ino.reserved;
    411	dst->d_spc_timer = dqp->q_blk.timer;
    412	dst->d_ino_timer = dqp->q_ino.timer;
    413	dst->d_ino_warns = 0;
    414	dst->d_spc_warns = 0;
    415	dst->d_rt_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.hardlimit);
    416	dst->d_rt_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.softlimit);
    417	dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_rtb.reserved);
    418	dst->d_rt_spc_timer = dqp->q_rtb.timer;
    419	dst->d_rt_spc_warns = 0;
    420
    421	/*
    422	 * Internally, we don't reset all the timers when quota enforcement
    423	 * gets turned off. No need to confuse the user level code,
    424	 * so return zeroes in that case.
    425	 */
    426	if (!xfs_dquot_is_enforced(dqp)) {
    427		dst->d_spc_timer = 0;
    428		dst->d_ino_timer = 0;
    429		dst->d_rt_spc_timer = 0;
    430	}
    431
    432#ifdef DEBUG
    433	if (xfs_dquot_is_enforced(dqp) && dqp->q_id != 0) {
    434		if ((dst->d_space > dst->d_spc_softlimit) &&
    435		    (dst->d_spc_softlimit > 0)) {
    436			ASSERT(dst->d_spc_timer != 0);
    437		}
    438		if ((dst->d_ino_count > dqp->q_ino.softlimit) &&
    439		    (dqp->q_ino.softlimit > 0)) {
    440			ASSERT(dst->d_ino_timer != 0);
    441		}
    442	}
    443#endif
    444}
    445
    446/* Return the quota information for the dquot matching id. */
    447int
    448xfs_qm_scall_getquota(
    449	struct xfs_mount	*mp,
    450	xfs_dqid_t		id,
    451	xfs_dqtype_t		type,
    452	struct qc_dqblk		*dst)
    453{
    454	struct xfs_dquot	*dqp;
    455	int			error;
    456
    457	/*
    458	 * Expedite pending inodegc work at the start of a quota reporting
    459	 * scan but don't block waiting for it to complete.
    460	 */
    461	if (id == 0)
    462		xfs_inodegc_push(mp);
    463
    464	/*
    465	 * Try to get the dquot. We don't want it allocated on disk, so don't
    466	 * set doalloc. If it doesn't exist, we'll get ENOENT back.
    467	 */
    468	error = xfs_qm_dqget(mp, id, type, false, &dqp);
    469	if (error)
    470		return error;
    471
    472	/*
    473	 * If everything's NULL, this dquot doesn't quite exist as far as
    474	 * our utility programs are concerned.
    475	 */
    476	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
    477		error = -ENOENT;
    478		goto out_put;
    479	}
    480
    481	xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
    482
    483out_put:
    484	xfs_qm_dqput(dqp);
    485	return error;
    486}
    487
    488/*
    489 * Return the quota information for the first initialized dquot whose id
    490 * is at least as high as id.
    491 */
    492int
    493xfs_qm_scall_getquota_next(
    494	struct xfs_mount	*mp,
    495	xfs_dqid_t		*id,
    496	xfs_dqtype_t		type,
    497	struct qc_dqblk		*dst)
    498{
    499	struct xfs_dquot	*dqp;
    500	int			error;
    501
    502	/* Flush inodegc work at the start of a quota reporting scan. */
    503	if (*id == 0)
    504		xfs_inodegc_push(mp);
    505
    506	error = xfs_qm_dqget_next(mp, *id, type, &dqp);
    507	if (error)
    508		return error;
    509
    510	/* Fill in the ID we actually read from disk */
    511	*id = dqp->q_id;
    512
    513	xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
    514
    515	xfs_qm_dqput(dqp);
    516	return error;
    517}