File Index
Files and directories
Sign in
FILE

xfs_qm_syscalls.c

File preview with syntax highlighting.

linux-6.19.14/fs/xfs/xfs_qm_syscalls.c C
  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_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
100int
101xfs_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 takes
132 * effect immediately.
133 * (Switching on quota accounting must be done at mount time.)
134 */
135int
136xfs_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 superblock
157	 * qflags here instead of m_qflags because rootfs can have
158	 * 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->qflags
179	 * 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 true
223 * if the new limits made sense and were applied, false otherwise.
224 */
225static inline bool
226xfs_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 void
252xfs_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 */
271int
272xfs_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 a
294	 * transaction to allocate it if it doesn't exist. Once we have the
295	 * dquot, unlock it so we can start the next transaction safely. We hold
296	 * a reference to the dquot, so it's safe to do this unlock/lock without
297	 * 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
307	error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_setqlim, 0, 0, 0, &tp);
308	if (error)
309		goto out_rele;
310
311	mutex_lock(&dqp->q_qlock);
312	xfs_trans_dqjoin(tp, dqp);
313
314	/*
315	 * Update quota limits, warnings, and timers, and the defaults
316	 * if we're touching id == 0.
317	 *
318	 * Make sure that hardlimits are >= soft limits before changing.
319	 *
320	 * Update warnings counter(s) if requested.
321	 *
322	 * Timelimits for the super user set the relative time the other users
323	 * can be over quota for this file system. If it is zero a default is
324	 * used.  Ditto for the default soft and hard limit values (already
325	 * done, above), and for warnings.
326	 *
327	 * For other IDs, userspace can bump out the grace period if over
328	 * the soft limit.
329	 */
330
331	/* Blocks on the data device. */
332	hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
333		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
334			dqp->q_blk.hardlimit;
335	soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
336		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
337			dqp->q_blk.softlimit;
338	res = &dqp->q_blk;
339	qlim = id == 0 ? &defq->blk : NULL;
340
341	if (xfs_setqlim_limits(mp, res, qlim, hard, soft, "blk"))
342		xfs_dquot_set_prealloc_limits(dqp);
343	if (newlim->d_fieldmask & QC_SPC_TIMER)
344		xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
345
346	/* Blocks on the realtime device. */
347	hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
348		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
349			dqp->q_rtb.hardlimit;
350	soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
351		(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
352			dqp->q_rtb.softlimit;
353	res = &dqp->q_rtb;
354	qlim = id == 0 ? &defq->rtb : NULL;
355
356	xfs_setqlim_limits(mp, res, qlim, hard, soft, "rtb");
357	if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
358		xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer);
359
360	/* Inodes */
361	hard = (newlim->d_fieldmask & QC_INO_HARD) ?
362		(xfs_qcnt_t) newlim->d_ino_hardlimit :
363			dqp->q_ino.hardlimit;
364	soft = (newlim->d_fieldmask & QC_INO_SOFT) ?
365		(xfs_qcnt_t) newlim->d_ino_softlimit :
366			dqp->q_ino.softlimit;
367	res = &dqp->q_ino;
368	qlim = id == 0 ? &defq->ino : NULL;
369
370	xfs_setqlim_limits(mp, res, qlim, hard, soft, "ino");
371	if (newlim->d_fieldmask & QC_INO_TIMER)
372		xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer);
373
374	if (id != 0) {
375		/*
376		 * If the user is now over quota, start the timelimit.
377		 * The user will not be 'warned'.
378		 * Note that we keep the timers ticking, whether enforcement
379		 * is on or off. We don't really want to bother with iterating
380		 * over all ondisk dquots and turning the timers on/off.
381		 */
382		xfs_qm_adjust_dqtimers(dqp);
383	}
384	dqp->q_flags |= XFS_DQFLAG_DIRTY;
385	xfs_trans_log_dquot(tp, dqp);
386
387	error = xfs_trans_commit(tp);
388
389out_rele:
390	xfs_qm_dqrele(dqp);
391	return error;
392}
393
394/* Fill out the quota context. */
395static void
396xfs_qm_scall_getquota_fill_qc(
397	struct xfs_mount	*mp,
398	xfs_dqtype_t		type,
399	const struct xfs_dquot	*dqp,
400	struct qc_dqblk		*dst)
401{
402	memset(dst, 0, sizeof(*dst));
403	dst->d_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_blk.hardlimit);
404	dst->d_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_blk.softlimit);
405	dst->d_ino_hardlimit = dqp->q_ino.hardlimit;
406	dst->d_ino_softlimit = dqp->q_ino.softlimit;
407	dst->d_space = XFS_FSB_TO_B(mp, dqp->q_blk.reserved);
408	dst->d_ino_count = dqp->q_ino.reserved;
409	dst->d_spc_timer = dqp->q_blk.timer;
410	dst->d_ino_timer = dqp->q_ino.timer;
411	dst->d_ino_warns = 0;
412	dst->d_spc_warns = 0;
413	dst->d_rt_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.hardlimit);
414	dst->d_rt_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.softlimit);
415	dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_rtb.reserved);
416	dst->d_rt_spc_timer = dqp->q_rtb.timer;
417	dst->d_rt_spc_warns = 0;
418
419	/*
420	 * Internally, we don't reset all the timers when quota enforcement
421	 * gets turned off. No need to confuse the user level code,
422	 * so return zeroes in that case.
423	 */
424	if (!xfs_dquot_is_enforced(dqp)) {
425		dst->d_spc_timer = 0;
426		dst->d_ino_timer = 0;
427		dst->d_rt_spc_timer = 0;
428	}
429}
430
431/* Return the quota information for the dquot matching id. */
432int
433xfs_qm_scall_getquota(
434	struct xfs_mount	*mp,
435	xfs_dqid_t		id,
436	xfs_dqtype_t		type,
437	struct qc_dqblk		*dst)
438{
439	struct xfs_dquot	*dqp;
440	int			error;
441
442	/*
443	 * Expedite pending inodegc work at the start of a quota reporting
444	 * scan but don't block waiting for it to complete.
445	 */
446	if (id == 0)
447		xfs_inodegc_push(mp);
448
449	/*
450	 * Try to get the dquot. We don't want it allocated on disk, so don't
451	 * set doalloc. If it doesn't exist, we'll get ENOENT back.
452	 */
453	error = xfs_qm_dqget(mp, id, type, false, &dqp);
454	if (error)
455		return error;
456
457	/*
458	 * If everything's NULL, this dquot doesn't quite exist as far as
459	 * our utility programs are concerned.
460	 */
461	mutex_lock(&dqp->q_qlock);
462	if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
463		error = -ENOENT;
464		goto out_put;
465	}
466
467	xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
468
469out_put:
470	mutex_unlock(&dqp->q_qlock);
471	xfs_qm_dqrele(dqp);
472	return error;
473}
474
475/*
476 * Return the quota information for the first initialized dquot whose id
477 * is at least as high as id.
478 */
479int
480xfs_qm_scall_getquota_next(
481	struct xfs_mount	*mp,
482	xfs_dqid_t		*id,
483	xfs_dqtype_t		type,
484	struct qc_dqblk		*dst)
485{
486	struct xfs_dquot	*dqp;
487	int			error;
488
489	/* Flush inodegc work at the start of a quota reporting scan. */
490	if (*id == 0)
491		xfs_inodegc_push(mp);
492
493	error = xfs_qm_dqget_next(mp, *id, type, &dqp);
494	if (error)
495		return error;
496
497	/* Fill in the ID we actually read from disk */
498	*id = dqp->q_id;
499
500	xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
501	mutex_unlock(&dqp->q_qlock);
502
503	xfs_qm_dqrele(dqp);
504	return error;
505}
~/ Read-only file preview.