brintos

brintos / linux-shallow public Read only

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