summaryrefslogtreecommitdiff
path: root/fs/xfs
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2020-10-25 17:14:50 -0700
committerDarrick J. Wong <darrick.wong@oracle.com>2020-10-26 18:32:19 -0700
commit6ff8d9ff6c3b720df1250b4749f950da04e4d864 (patch)
tree807da598d36ec84a0d73dfe0d092516b7488cc64 /fs/xfs
parentbea8e4884867e32cc2e0b6a5662228d3ae82feee (diff)
xfs: track unlinked inactive inode quota counters
Set up quota counters to track the number of inodes and blocks that will be freed from inactivating unlinked inodes. We'll use this in the deferred inactivation patch to hide the effects of deferred processing. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_dquot.c53
-rw-r--r--fs/xfs/xfs_dquot.h6
-rw-r--r--fs/xfs/xfs_inode.c11
-rw-r--r--fs/xfs/xfs_qm.c13
-rw-r--r--fs/xfs/xfs_qm_syscalls.c6
-rw-r--r--fs/xfs/xfs_quota.h3
-rw-r--r--fs/xfs/xfs_trace.h13
7 files changed, 99 insertions, 6 deletions
diff --git a/fs/xfs/xfs_dquot.c b/fs/xfs/xfs_dquot.c
index f98f07571524..9c96428e854c 100644
--- a/fs/xfs/xfs_dquot.c
+++ b/fs/xfs/xfs_dquot.c
@@ -151,10 +151,12 @@ xfs_qm_adjust_res_timer(
struct xfs_dquot_res *res,
struct xfs_quota_limits *qlim)
{
+ xfs_qcnt_t eff_count = res->count - res->inactive;
+
ASSERT(res->hardlimit == 0 || res->softlimit <= res->hardlimit);
- if ((res->softlimit && res->count > res->softlimit) ||
- (res->hardlimit && res->count > res->hardlimit)) {
+ if ((res->softlimit && eff_count > res->softlimit) ||
+ (res->hardlimit && eff_count > res->hardlimit)) {
if (res->timer == 0)
res->timer = xfs_dquot_set_timeout(mp,
ktime_get_real_seconds() + qlim->time);
@@ -1412,3 +1414,50 @@ xfs_qm_dqiterate(
return error;
}
+
+/* Update dquot pending-inactivation counters. */
+STATIC void
+xfs_dquot_iadjust(
+ struct xfs_dquot *dqp,
+ int direction,
+ int64_t inodes,
+ int64_t dblocks,
+ int64_t rblocks)
+{
+ xfs_dqlock(dqp);
+ dqp->q_ina_total += direction;
+ dqp->q_ino.inactive += inodes;
+ dqp->q_blk.inactive += dblocks;
+ dqp->q_rtb.inactive += rblocks;
+ if (dqp->q_id)
+ xfs_qm_adjust_dqtimers(dqp);
+ xfs_dqunlock(dqp);
+}
+
+/* Update pending-inactivation counters for all dquots attach to inode. */
+void
+xfs_qm_iadjust(
+ struct xfs_inode *ip,
+ int direction,
+ int64_t inodes,
+ int64_t dblocks,
+ int64_t rblocks)
+{
+ struct xfs_mount *mp = ip->i_mount;
+
+ if (!XFS_IS_QUOTA_RUNNING(mp) || !XFS_IS_QUOTA_ON(mp) ||
+ xfs_is_quota_inode(&mp->m_sb, ip->i_ino))
+ return;
+
+ if (XFS_IS_UQUOTA_ON(mp) && ip->i_udquot)
+ xfs_dquot_iadjust(ip->i_udquot, direction, inodes, dblocks,
+ rblocks);
+
+ if (XFS_IS_GQUOTA_ON(mp) && ip->i_gdquot)
+ xfs_dquot_iadjust(ip->i_gdquot, direction, inodes, dblocks,
+ rblocks);
+
+ if (XFS_IS_PQUOTA_ON(mp) && ip->i_pdquot)
+ xfs_dquot_iadjust(ip->i_pdquot, direction, inodes, dblocks,
+ rblocks);
+}
diff --git a/fs/xfs/xfs_dquot.h b/fs/xfs/xfs_dquot.h
index f642884a6834..309cffaa467b 100644
--- a/fs/xfs/xfs_dquot.h
+++ b/fs/xfs/xfs_dquot.h
@@ -34,6 +34,9 @@ struct xfs_dquot_res {
/* Total resources allocated. */
xfs_qcnt_t count;
+ /* Resources that would be freed by forcing inode inactivation. */
+ xfs_qcnt_t inactive;
+
/* Absolute and preferred limits. */
xfs_qcnt_t hardlimit;
xfs_qcnt_t softlimit;
@@ -74,6 +77,9 @@ struct xfs_dquot {
struct xfs_dq_logitem q_logitem;
+ /* inactive inodes attached to this dquot */
+ uint64_t q_ina_total;
+
xfs_qcnt_t q_prealloc_lo_wmark;
xfs_qcnt_t q_prealloc_hi_wmark;
int64_t q_low_space[XFS_QLOWSP_MAX];
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index c0ae539f3cad..ac9871b94e8f 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -36,6 +36,8 @@
#include "xfs_bmap_btree.h"
#include "xfs_reflink.h"
#include "xfs_health.h"
+#include "xfs_dquot_item.h"
+#include "xfs_dquot.h"
kmem_zone_t *xfs_inode_zone;
@@ -1850,7 +1852,7 @@ xfs_inode_iadjust(
ASSERT(direction != 0);
if (VFS_I(ip)->i_nlink != 0)
- return;
+ goto out;
inodes = 1;
iblocks = max_t(int64_t, 0, ip->i_d.di_nblocks + ip->i_delayed_blks);
@@ -1870,6 +1872,13 @@ xfs_inode_iadjust(
percpu_counter_add(&mp->m_dinactive, dblocks);
if (rblocks)
percpu_counter_add(&mp->m_rinactive, rblocks);
+
+out:
+ /*
+ * Always tell the quota system that we're inactivating this inode so
+ * that it will retain incore quota reservations and the like.
+ */
+ xfs_qm_iadjust(ip, direction, inodes, dblocks, rblocks);
}
/*
diff --git a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
index f7fe625be3d8..c961fb8fb300 100644
--- a/fs/xfs/xfs_qm.c
+++ b/fs/xfs/xfs_qm.c
@@ -428,6 +428,19 @@ xfs_qm_dquot_isolate(
goto out_miss_busy;
/*
+ * An inode is on the inactive list waiting to release its resources,
+ * so remove this dquot from the freelist and try again. We detached
+ * the dquot from the NEEDS_INACTIVE inode so that quotaoff won't
+ * deadlock on inactive inodes holding dquots.
+ */
+ if (dqp->q_ina_total > 0) {
+ xfs_dqunlock(dqp);
+ trace_xfs_dqreclaim_inactive(dqp);
+ list_lru_isolate(lru, &dqp->q_lru);
+ return LRU_REMOVED;
+ }
+
+ /*
* This dquot has acquired a reference in the meantime remove it from
* the freelist and try again.
*/
diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
index dad4d3fc3df3..3d78466ccb19 100644
--- a/fs/xfs/xfs_qm_syscalls.c
+++ b/fs/xfs/xfs_qm_syscalls.c
@@ -649,15 +649,15 @@ xfs_qm_scall_getquota_fill_qc(
dst->d_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_blk.softlimit);
dst->d_ino_hardlimit = dqp->q_ino.hardlimit;
dst->d_ino_softlimit = dqp->q_ino.softlimit;
- dst->d_space = XFS_FSB_TO_B(mp, dqp->q_blk.reserved);
- dst->d_ino_count = dqp->q_ino.reserved;
+ dst->d_space = XFS_FSB_TO_B(mp, dqp->q_blk.reserved - dqp->q_blk.inactive);
+ dst->d_ino_count = dqp->q_ino.reserved - dqp->q_ino.inactive;
dst->d_spc_timer = dqp->q_blk.timer;
dst->d_ino_timer = dqp->q_ino.timer;
dst->d_ino_warns = dqp->q_ino.warnings;
dst->d_spc_warns = dqp->q_blk.warnings;
dst->d_rt_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.hardlimit);
dst->d_rt_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.softlimit);
- dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_rtb.reserved);
+ dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_rtb.reserved - dqp->q_rtb.inactive);
dst->d_rt_spc_timer = dqp->q_rtb.timer;
dst->d_rt_spc_warns = dqp->q_rtb.warnings;
diff --git a/fs/xfs/xfs_quota.h b/fs/xfs/xfs_quota.h
index fa6477347ffc..7163f00fbc94 100644
--- a/fs/xfs/xfs_quota.h
+++ b/fs/xfs/xfs_quota.h
@@ -117,6 +117,8 @@ extern void xfs_qm_mount_quotas(struct xfs_mount *);
extern void xfs_qm_unmount(struct xfs_mount *);
extern void xfs_qm_unmount_quotas(struct xfs_mount *);
+void xfs_qm_iadjust(struct xfs_inode *ip, int direction, int64_t inodes,
+ int64_t dblocks, int64_t rblocks);
#else
static inline int
xfs_qm_vop_dqalloc(struct xfs_inode *ip, kuid_t kuid, kgid_t kgid,
@@ -158,6 +160,7 @@ static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp,
#define xfs_qm_mount_quotas(mp)
#define xfs_qm_unmount(mp)
#define xfs_qm_unmount_quotas(mp)
+#define xfs_qm_iadjust(ip, dir, inodes, dblocks, rblocks)
#endif /* CONFIG_XFS_QUOTA */
#if IS_ENABLED(CONFIG_XFS_QUOTA) && IS_ENABLED(CONFIG_XFS_ONLINE_SCRUB)
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index e2b439c5b3d9..7e799cad72da 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -881,6 +881,10 @@ DECLARE_EVENT_CLASS(xfs_dquot_class,
__field(unsigned long long, rtb_softlimit)
__field(unsigned long long, ino_hardlimit)
__field(unsigned long long, ino_softlimit)
+
+ __field(unsigned long long, ina_bcount)
+ __field(unsigned long long, ina_rtbcount)
+ __field(unsigned long long, ina_icount)
),
TP_fast_assign(
__entry->dev = dqp->q_mount->m_super->s_dev;
@@ -903,9 +907,14 @@ DECLARE_EVENT_CLASS(xfs_dquot_class,
__entry->rtb_softlimit = dqp->q_rtb.softlimit;
__entry->ino_hardlimit = dqp->q_ino.hardlimit;
__entry->ino_softlimit = dqp->q_ino.softlimit;
+
+ __entry->ina_bcount = dqp->q_blk.inactive;
+ __entry->ina_rtbcount = dqp->q_rtb.inactive;
+ __entry->ina_icount = dqp->q_ino.inactive;
),
TP_printk("dev %d:%d id 0x%x type %s flags %s nrefs %u "
"res_bc 0x%llx res_rtbc 0x%llx res_ic 0x%llx "
+ "ina_bc 0x%llx ina_rtbc 0x%llx ina_ic 0x%llx "
"bcnt 0x%llx bhardlimit 0x%llx bsoftlimit 0x%llx "
"rtbcnt 0x%llx rtbhardlimit 0x%llx rtbsoftlimit 0x%llx "
"icnt 0x%llx ihardlimit 0x%llx isoftlimit 0x%llx]",
@@ -917,6 +926,9 @@ DECLARE_EVENT_CLASS(xfs_dquot_class,
__entry->res_bcount,
__entry->res_rtbcount,
__entry->res_icount,
+ __entry->ina_bcount,
+ __entry->ina_rtbcount,
+ __entry->ina_icount,
__entry->bcount,
__entry->blk_hardlimit,
__entry->blk_softlimit,
@@ -933,6 +945,7 @@ DEFINE_EVENT(xfs_dquot_class, name, \
TP_PROTO(struct xfs_dquot *dqp), \
TP_ARGS(dqp))
DEFINE_DQUOT_EVENT(xfs_dqadjust);
+DEFINE_DQUOT_EVENT(xfs_dqreclaim_inactive);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_want);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_dirty);
DEFINE_DQUOT_EVENT(xfs_dqreclaim_busy);