summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-05-31 11:31:58 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-05-31 15:37:56 -0700
commitd8e5c6ac2b49d5cc1446f8e3262a6f1e77adb429 (patch)
treebac97480c9167f651bd79831bac6227372202444
parente1b2d7de4868fad51cf31597f2cb1a72baddde01 (diff)
xfs: separate the dqrele_all inode grab logic from xfs_inode_walk_ag_grab
Disentangle the dqrele_all inode grab code from the "generic" inode walk grabbing code, and and use the opportunity to document why the dqrele grab function does what it does. Since dqrele_all is the only user of XFS_ICI_NO_TAG, rename it to something more specific for what we're doing. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
-rw-r--r--fs/xfs/xfs_icache.c64
-rw-r--r--fs/xfs/xfs_icache.h4
2 files changed, 62 insertions, 6 deletions
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 34b8b5fbd60d..5501318b5db0 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -26,6 +26,8 @@
#include <linux/iversion.h>
+static bool xfs_dqrele_inode_grab(struct xfs_inode *ip);
+
/*
* Allocate and initialise an xfs_inode.
*/
@@ -765,6 +767,22 @@ out_unlock_noent:
return false;
}
+static inline bool
+xfs_grabbed_for_walk(
+ int tag,
+ struct xfs_inode *ip,
+ int iter_flags)
+{
+ switch (tag) {
+ case XFS_ICI_BLOCKGC_TAG:
+ return xfs_inode_walk_ag_grab(ip, iter_flags);
+ case XFS_ICI_DQRELE_NONTAG:
+ return xfs_dqrele_inode_grab(ip);
+ default:
+ return false;
+ }
+}
+
/*
* For a given per-AG structure @pag, grab, @execute, and rele all incore
* inodes with the given radix tree @tag.
@@ -796,7 +814,7 @@ restart:
rcu_read_lock();
- if (tag == XFS_ICI_NO_TAG)
+ if (tag == XFS_ICI_DQRELE_NONTAG)
nr_found = radix_tree_gang_lookup(&pag->pag_ici_root,
(void **)batch, first_index,
XFS_LOOKUP_BATCH);
@@ -818,7 +836,7 @@ restart:
for (i = 0; i < nr_found; i++) {
struct xfs_inode *ip = batch[i];
- if (done || !xfs_inode_walk_ag_grab(ip, iter_flags))
+ if (done || !xfs_grabbed_for_walk(tag, ip, iter_flags))
batch[i] = NULL;
/*
@@ -881,7 +899,7 @@ xfs_inode_walk_get_perag(
xfs_agnumber_t agno,
int tag)
{
- if (tag == XFS_ICI_NO_TAG)
+ if (tag == XFS_ICI_DQRELE_NONTAG)
return xfs_perag_get(mp, agno);
return xfs_perag_get_tag(mp, agno, tag);
}
@@ -917,6 +935,44 @@ xfs_inode_walk(
return last_error;
}
+/* Decide if we want to grab this inode to drop its dquots. */
+static bool
+xfs_dqrele_inode_grab(
+ struct xfs_inode *ip)
+{
+ bool ret = false;
+
+ ASSERT(rcu_read_lock_held());
+
+ /* Check for stale RCU freed inode */
+ spin_lock(&ip->i_flags_lock);
+ if (!ip->i_ino)
+ goto out_unlock;
+
+ /*
+ * Skip inodes that are anywhere in the reclaim machinery because we
+ * drop dquots before tagging an inode for reclamation.
+ */
+ if (ip->i_flags & (XFS_IRECLAIM | XFS_IRECLAIMABLE))
+ goto out_unlock;
+
+ /*
+ * The inode looks alive; try to grab a VFS reference so that it won't
+ * get destroyed. If we got the reference, return true to say that
+ * we grabbed the inode.
+ *
+ * If we can't get the reference, then we know the inode had its VFS
+ * state torn down and hasn't yet entered the reclaim machinery. Since
+ * we also know that dquots are detached from an inode before it enters
+ * reclaim, we can skip the inode.
+ */
+ ret = igrab(VFS_I(ip)) != NULL;
+
+out_unlock:
+ spin_unlock(&ip->i_flags_lock);
+ return ret;
+}
+
/* Drop this inode's dquots. */
static int
xfs_dqrele_inode(
@@ -964,7 +1020,7 @@ xfs_dqrele_all_inodes(
eofb.eof_flags |= XFS_EOFB_DROP_PDQUOT;
return xfs_inode_walk(mp, XFS_INODE_WALK_INEW_WAIT, xfs_dqrele_inode,
- &eofb, XFS_ICI_NO_TAG);
+ &eofb, XFS_ICI_DQRELE_NONTAG);
}
/*
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h
index 77029e92ba4c..fcfcdad7f977 100644
--- a/fs/xfs/xfs_icache.h
+++ b/fs/xfs/xfs_icache.h
@@ -29,8 +29,8 @@ struct xfs_eofblocks {
/*
* tags for inode radix tree
*/
-#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup
- in xfs_inode_walk */
+#define XFS_ICI_DQRELE_NONTAG (-1) /* quotaoff dqdetach inode walk uses
+ untagged lookups */
#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */
/* Inode has speculative preallocations (posteof or cow) to clean. */
#define XFS_ICI_BLOCKGC_TAG 1