|
@@ -144,6 +144,41 @@ restart:
|
|
|
return last_error;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Select the next per-ag structure to iterate during the walk. The reclaim
|
|
|
+ * walk is optimised only to walk AGs with reclaimable inodes in them.
|
|
|
+ */
|
|
|
+static struct xfs_perag *
|
|
|
+xfs_inode_ag_iter_next_pag(
|
|
|
+ struct xfs_mount *mp,
|
|
|
+ xfs_agnumber_t *first,
|
|
|
+ int tag)
|
|
|
+{
|
|
|
+ struct xfs_perag *pag = NULL;
|
|
|
+
|
|
|
+ if (tag == XFS_ICI_RECLAIM_TAG) {
|
|
|
+ int found;
|
|
|
+ int ref;
|
|
|
+
|
|
|
+ spin_lock(&mp->m_perag_lock);
|
|
|
+ found = radix_tree_gang_lookup_tag(&mp->m_perag_tree,
|
|
|
+ (void **)&pag, *first, 1, tag);
|
|
|
+ if (found <= 0) {
|
|
|
+ spin_unlock(&mp->m_perag_lock);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ *first = pag->pag_agno + 1;
|
|
|
+ /* open coded pag reference increment */
|
|
|
+ ref = atomic_inc_return(&pag->pag_ref);
|
|
|
+ spin_unlock(&mp->m_perag_lock);
|
|
|
+ trace_xfs_perag_get_reclaim(mp, pag->pag_agno, ref, _RET_IP_);
|
|
|
+ } else {
|
|
|
+ pag = xfs_perag_get(mp, *first);
|
|
|
+ (*first)++;
|
|
|
+ }
|
|
|
+ return pag;
|
|
|
+}
|
|
|
+
|
|
|
int
|
|
|
xfs_inode_ag_iterator(
|
|
|
struct xfs_mount *mp,
|
|
@@ -154,16 +189,15 @@ xfs_inode_ag_iterator(
|
|
|
int exclusive,
|
|
|
int *nr_to_scan)
|
|
|
{
|
|
|
+ struct xfs_perag *pag;
|
|
|
int error = 0;
|
|
|
int last_error = 0;
|
|
|
xfs_agnumber_t ag;
|
|
|
int nr;
|
|
|
|
|
|
nr = nr_to_scan ? *nr_to_scan : INT_MAX;
|
|
|
- for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
|
|
|
- struct xfs_perag *pag;
|
|
|
-
|
|
|
- pag = xfs_perag_get(mp, ag);
|
|
|
+ ag = 0;
|
|
|
+ while ((pag = xfs_inode_ag_iter_next_pag(mp, &ag, tag))) {
|
|
|
error = xfs_inode_ag_walk(mp, pag, execute, flags, tag,
|
|
|
exclusive, &nr);
|
|
|
xfs_perag_put(pag);
|
|
@@ -640,6 +674,17 @@ __xfs_inode_set_reclaim_tag(
|
|
|
radix_tree_tag_set(&pag->pag_ici_root,
|
|
|
XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
+
|
|
|
+ if (!pag->pag_ici_reclaimable) {
|
|
|
+ /* propagate the reclaim tag up into the perag radix tree */
|
|
|
+ spin_lock(&ip->i_mount->m_perag_lock);
|
|
|
+ radix_tree_tag_set(&ip->i_mount->m_perag_tree,
|
|
|
+ XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
|
|
|
+ XFS_ICI_RECLAIM_TAG);
|
|
|
+ spin_unlock(&ip->i_mount->m_perag_lock);
|
|
|
+ trace_xfs_perag_set_reclaim(ip->i_mount, pag->pag_agno,
|
|
|
+ -1, _RET_IP_);
|
|
|
+ }
|
|
|
pag->pag_ici_reclaimable++;
|
|
|
}
|
|
|
|
|
@@ -674,6 +719,16 @@ __xfs_inode_clear_reclaim_tag(
|
|
|
radix_tree_tag_clear(&pag->pag_ici_root,
|
|
|
XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);
|
|
|
pag->pag_ici_reclaimable--;
|
|
|
+ if (!pag->pag_ici_reclaimable) {
|
|
|
+ /* clear the reclaim tag from the perag radix tree */
|
|
|
+ spin_lock(&ip->i_mount->m_perag_lock);
|
|
|
+ radix_tree_tag_clear(&ip->i_mount->m_perag_tree,
|
|
|
+ XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino),
|
|
|
+ XFS_ICI_RECLAIM_TAG);
|
|
|
+ spin_unlock(&ip->i_mount->m_perag_lock);
|
|
|
+ trace_xfs_perag_clear_reclaim(ip->i_mount, pag->pag_agno,
|
|
|
+ -1, _RET_IP_);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -838,7 +893,7 @@ xfs_reclaim_inode_shrink(
|
|
|
struct xfs_mount *mp;
|
|
|
struct xfs_perag *pag;
|
|
|
xfs_agnumber_t ag;
|
|
|
- int reclaimable = 0;
|
|
|
+ int reclaimable;
|
|
|
|
|
|
mp = container_of(shrink, struct xfs_mount, m_inode_shrink);
|
|
|
if (nr_to_scan) {
|
|
@@ -852,8 +907,10 @@ xfs_reclaim_inode_shrink(
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
- for (ag = 0; ag < mp->m_sb.sb_agcount; ag++) {
|
|
|
- pag = xfs_perag_get(mp, ag);
|
|
|
+ reclaimable = 0;
|
|
|
+ ag = 0;
|
|
|
+ while ((pag = xfs_inode_ag_iter_next_pag(mp, &ag,
|
|
|
+ XFS_ICI_RECLAIM_TAG))) {
|
|
|
reclaimable += pag->pag_ici_reclaimable;
|
|
|
xfs_perag_put(pag);
|
|
|
}
|