Linux Audio

Check our new training course

Loading...
v6.9.4
  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}
v6.13.7
  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	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 defaults
317	 * 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 users
324	 * can be over quota for this file system. If it is zero a default is
325	 * used.  Ditto for the default soft and hard limit values (already
326	 * done, above), and for warnings.
327	 *
328	 * For other IDs, userspace can bump out the grace period if over
329	 * 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 enforcement
380		 * is on or off. We don't really want to bother with iterating
381		 * 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 void
397xfs_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 enforcement
422	 * 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
432/* Return the quota information for the dquot matching id. */
433int
434xfs_qm_scall_getquota(
435	struct xfs_mount	*mp,
436	xfs_dqid_t		id,
437	xfs_dqtype_t		type,
438	struct qc_dqblk		*dst)
439{
440	struct xfs_dquot	*dqp;
441	int			error;
442
443	/*
444	 * Expedite pending inodegc work at the start of a quota reporting
445	 * scan but don't block waiting for it to complete.
446	 */
447	if (id == 0)
448		xfs_inodegc_push(mp);
449
450	/*
451	 * Try to get the dquot. We don't want it allocated on disk, so don't
452	 * set doalloc. If it doesn't exist, we'll get ENOENT back.
453	 */
454	error = xfs_qm_dqget(mp, id, type, false, &dqp);
455	if (error)
456		return error;
457
458	/*
459	 * If everything's NULL, this dquot doesn't quite exist as far as
460	 * our utility programs are concerned.
461	 */
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	xfs_qm_dqput(dqp);
471	return error;
472}
473
474/*
475 * Return the quota information for the first initialized dquot whose id
476 * is at least as high as id.
477 */
478int
479xfs_qm_scall_getquota_next(
480	struct xfs_mount	*mp,
481	xfs_dqid_t		*id,
482	xfs_dqtype_t		type,
483	struct qc_dqblk		*dst)
484{
485	struct xfs_dquot	*dqp;
486	int			error;
487
488	/* Flush inodegc work at the start of a quota reporting scan. */
489	if (*id == 0)
490		xfs_inodegc_push(mp);
491
492	error = xfs_qm_dqget_next(mp, *id, type, &dqp);
493	if (error)
494		return error;
495
496	/* Fill in the ID we actually read from disk */
497	*id = dqp->q_id;
498
499	xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
500
501	xfs_qm_dqput(dqp);
502	return error;
503}