|
|
|
|
@@ -207,54 +207,102 @@ xfs_reclaim_work_queue(
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xfs_perag_set_reclaim_tag(
|
|
|
|
|
/*
|
|
|
|
|
* Background scanning to trim preallocated space. This is queued based on the
|
|
|
|
|
* 'speculative_prealloc_lifetime' tunable (5m by default).
|
|
|
|
|
*/
|
|
|
|
|
static inline void
|
|
|
|
|
xfs_blockgc_queue(
|
|
|
|
|
struct xfs_perag *pag)
|
|
|
|
|
{
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
if (radix_tree_tagged(&pag->pag_ici_root, XFS_ICI_BLOCKGC_TAG))
|
|
|
|
|
queue_delayed_work(pag->pag_mount->m_gc_workqueue,
|
|
|
|
|
&pag->pag_blockgc_work,
|
|
|
|
|
msecs_to_jiffies(xfs_blockgc_secs * 1000));
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Set a tag on both the AG incore inode tree and the AG radix tree. */
|
|
|
|
|
static void
|
|
|
|
|
xfs_perag_set_inode_tag(
|
|
|
|
|
struct xfs_perag *pag,
|
|
|
|
|
xfs_agino_t agino,
|
|
|
|
|
unsigned int tag)
|
|
|
|
|
{
|
|
|
|
|
struct xfs_mount *mp = pag->pag_mount;
|
|
|
|
|
bool was_tagged;
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held(&pag->pag_ici_lock);
|
|
|
|
|
|
|
|
|
|
was_tagged = radix_tree_tagged(&pag->pag_ici_root, tag);
|
|
|
|
|
radix_tree_tag_set(&pag->pag_ici_root, agino, tag);
|
|
|
|
|
|
|
|
|
|
if (tag == XFS_ICI_RECLAIM_TAG)
|
|
|
|
|
pag->pag_ici_reclaimable++;
|
|
|
|
|
|
|
|
|
|
if (was_tagged)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* propagate the tag up into the perag radix tree */
|
|
|
|
|
spin_lock(&mp->m_perag_lock);
|
|
|
|
|
radix_tree_tag_set(&mp->m_perag_tree, pag->pag_agno, tag);
|
|
|
|
|
spin_unlock(&mp->m_perag_lock);
|
|
|
|
|
|
|
|
|
|
/* start background work */
|
|
|
|
|
switch (tag) {
|
|
|
|
|
case XFS_ICI_RECLAIM_TAG:
|
|
|
|
|
xfs_reclaim_work_queue(mp);
|
|
|
|
|
break;
|
|
|
|
|
case XFS_ICI_BLOCKGC_TAG:
|
|
|
|
|
xfs_blockgc_queue(pag);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
trace_xfs_perag_set_inode_tag(mp, pag->pag_agno, tag, _RET_IP_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Clear a tag on both the AG incore inode tree and the AG radix tree. */
|
|
|
|
|
static void
|
|
|
|
|
xfs_perag_clear_inode_tag(
|
|
|
|
|
struct xfs_perag *pag,
|
|
|
|
|
xfs_agino_t agino,
|
|
|
|
|
unsigned int tag)
|
|
|
|
|
{
|
|
|
|
|
struct xfs_mount *mp = pag->pag_mount;
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held(&pag->pag_ici_lock);
|
|
|
|
|
if (pag->pag_ici_reclaimable++)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Reclaim can signal (with a null agino) that it cleared its own tag
|
|
|
|
|
* by removing the inode from the radix tree.
|
|
|
|
|
*/
|
|
|
|
|
if (agino != NULLAGINO)
|
|
|
|
|
radix_tree_tag_clear(&pag->pag_ici_root, agino, tag);
|
|
|
|
|
else
|
|
|
|
|
ASSERT(tag == XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
|
|
|
|
|
if (tag == XFS_ICI_RECLAIM_TAG)
|
|
|
|
|
pag->pag_ici_reclaimable--;
|
|
|
|
|
|
|
|
|
|
if (radix_tree_tagged(&pag->pag_ici_root, tag))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* propagate the reclaim tag up into the perag radix tree */
|
|
|
|
|
/* clear the tag from the perag radix tree */
|
|
|
|
|
spin_lock(&mp->m_perag_lock);
|
|
|
|
|
radix_tree_tag_set(&mp->m_perag_tree, pag->pag_agno,
|
|
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
radix_tree_tag_clear(&mp->m_perag_tree, pag->pag_agno, tag);
|
|
|
|
|
spin_unlock(&mp->m_perag_lock);
|
|
|
|
|
|
|
|
|
|
/* schedule periodic background inode reclaim */
|
|
|
|
|
xfs_reclaim_work_queue(mp);
|
|
|
|
|
|
|
|
|
|
trace_xfs_perag_set_reclaim(mp, pag->pag_agno, -1, _RET_IP_);
|
|
|
|
|
trace_xfs_perag_clear_inode_tag(mp, pag->pag_agno, tag, _RET_IP_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xfs_perag_clear_reclaim_tag(
|
|
|
|
|
struct xfs_perag *pag)
|
|
|
|
|
{
|
|
|
|
|
struct xfs_mount *mp = pag->pag_mount;
|
|
|
|
|
|
|
|
|
|
lockdep_assert_held(&pag->pag_ici_lock);
|
|
|
|
|
if (--pag->pag_ici_reclaimable)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* clear the reclaim tag from the perag radix tree */
|
|
|
|
|
spin_lock(&mp->m_perag_lock);
|
|
|
|
|
radix_tree_tag_clear(&mp->m_perag_tree, pag->pag_agno,
|
|
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
spin_unlock(&mp->m_perag_lock);
|
|
|
|
|
trace_xfs_perag_clear_reclaim(mp, pag->pag_agno, -1, _RET_IP_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We set the inode flag atomically with the radix tree tag.
|
|
|
|
|
* Once we get tag lookups on the radix tree, this inode flag
|
|
|
|
|
* can go away.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
xfs_inode_set_reclaim_tag(
|
|
|
|
|
xfs_inode_mark_reclaimable(
|
|
|
|
|
struct xfs_inode *ip)
|
|
|
|
|
{
|
|
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
|
|
|
@@ -264,9 +312,8 @@ xfs_inode_set_reclaim_tag(
|
|
|
|
|
spin_lock(&pag->pag_ici_lock);
|
|
|
|
|
spin_lock(&ip->i_flags_lock);
|
|
|
|
|
|
|
|
|
|
radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino),
|
|
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
xfs_perag_set_reclaim_tag(pag);
|
|
|
|
|
xfs_perag_set_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
|
|
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
__xfs_iflags_set(ip, XFS_IRECLAIMABLE);
|
|
|
|
|
|
|
|
|
|
spin_unlock(&ip->i_flags_lock);
|
|
|
|
|
@@ -274,17 +321,6 @@ xfs_inode_set_reclaim_tag(
|
|
|
|
|
xfs_perag_put(pag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
STATIC void
|
|
|
|
|
xfs_inode_clear_reclaim_tag(
|
|
|
|
|
struct xfs_perag *pag,
|
|
|
|
|
xfs_ino_t ino)
|
|
|
|
|
{
|
|
|
|
|
radix_tree_tag_clear(&pag->pag_ici_root,
|
|
|
|
|
XFS_INO_TO_AGINO(pag->pag_mount, ino),
|
|
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
xfs_perag_clear_reclaim_tag(pag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void
|
|
|
|
|
xfs_inew_wait(
|
|
|
|
|
struct xfs_inode *ip)
|
|
|
|
|
@@ -483,7 +519,9 @@ xfs_iget_cache_hit(
|
|
|
|
|
*/
|
|
|
|
|
ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS;
|
|
|
|
|
ip->i_flags |= XFS_INEW;
|
|
|
|
|
xfs_inode_clear_reclaim_tag(pag, ip->i_ino);
|
|
|
|
|
xfs_perag_clear_inode_tag(pag,
|
|
|
|
|
XFS_INO_TO_AGINO(pag->pag_mount, ino),
|
|
|
|
|
XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
inode->i_state = I_NEW;
|
|
|
|
|
ip->i_sick = 0;
|
|
|
|
|
ip->i_checked = 0;
|
|
|
|
|
@@ -957,7 +995,7 @@ reclaim:
|
|
|
|
|
if (!radix_tree_delete(&pag->pag_ici_root,
|
|
|
|
|
XFS_INO_TO_AGINO(ip->i_mount, ino)))
|
|
|
|
|
ASSERT(0);
|
|
|
|
|
xfs_perag_clear_reclaim_tag(pag);
|
|
|
|
|
xfs_perag_clear_inode_tag(pag, NULLAGINO, XFS_ICI_RECLAIM_TAG);
|
|
|
|
|
spin_unlock(&pag->pag_ici_lock);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
@@ -1173,22 +1211,6 @@ xfs_inode_free_eofblocks(
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Background scanning to trim preallocated space. This is queued based on the
|
|
|
|
|
* 'speculative_prealloc_lifetime' tunable (5m by default).
|
|
|
|
|
*/
|
|
|
|
|
static inline void
|
|
|
|
|
xfs_blockgc_queue(
|
|
|
|
|
struct xfs_perag *pag)
|
|
|
|
|
{
|
|
|
|
|
rcu_read_lock();
|
|
|
|
|
if (radix_tree_tagged(&pag->pag_ici_root, XFS_ICI_BLOCKGC_TAG))
|
|
|
|
|
queue_delayed_work(pag->pag_mount->m_gc_workqueue,
|
|
|
|
|
&pag->pag_blockgc_work,
|
|
|
|
|
msecs_to_jiffies(xfs_blockgc_secs * 1000));
|
|
|
|
|
rcu_read_unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
xfs_blockgc_set_iflag(
|
|
|
|
|
struct xfs_inode *ip,
|
|
|
|
|
@@ -1196,7 +1218,6 @@ xfs_blockgc_set_iflag(
|
|
|
|
|
{
|
|
|
|
|
struct xfs_mount *mp = ip->i_mount;
|
|
|
|
|
struct xfs_perag *pag;
|
|
|
|
|
int tagged;
|
|
|
|
|
|
|
|
|
|
ASSERT((iflag & ~(XFS_IEOFBLOCKS | XFS_ICOWBLOCKS)) == 0);
|
|
|
|
|
|
|
|
|
|
@@ -1213,24 +1234,8 @@ xfs_blockgc_set_iflag(
|
|
|
|
|
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
|
|
|
|
|
spin_lock(&pag->pag_ici_lock);
|
|
|
|
|
|
|
|
|
|
tagged = radix_tree_tagged(&pag->pag_ici_root, XFS_ICI_BLOCKGC_TAG);
|
|
|
|
|
radix_tree_tag_set(&pag->pag_ici_root,
|
|
|
|
|
XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
|
|
|
|
|
XFS_ICI_BLOCKGC_TAG);
|
|
|
|
|
if (!tagged) {
|
|
|
|
|
/* propagate the blockgc 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_BLOCKGC_TAG);
|
|
|
|
|
spin_unlock(&ip->i_mount->m_perag_lock);
|
|
|
|
|
|
|
|
|
|
/* kick off background trimming */
|
|
|
|
|
xfs_blockgc_queue(pag);
|
|
|
|
|
|
|
|
|
|
trace_xfs_perag_set_blockgc(ip->i_mount, pag->pag_agno, -1,
|
|
|
|
|
_RET_IP_);
|
|
|
|
|
}
|
|
|
|
|
xfs_perag_set_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
|
|
|
|
|
XFS_ICI_BLOCKGC_TAG);
|
|
|
|
|
|
|
|
|
|
spin_unlock(&pag->pag_ici_lock);
|
|
|
|
|
xfs_perag_put(pag);
|
|
|
|
|
@@ -1266,19 +1271,8 @@ xfs_blockgc_clear_iflag(
|
|
|
|
|
pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino));
|
|
|
|
|
spin_lock(&pag->pag_ici_lock);
|
|
|
|
|
|
|
|
|
|
radix_tree_tag_clear(&pag->pag_ici_root,
|
|
|
|
|
XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),
|
|
|
|
|
XFS_ICI_BLOCKGC_TAG);
|
|
|
|
|
if (!radix_tree_tagged(&pag->pag_ici_root, XFS_ICI_BLOCKGC_TAG)) {
|
|
|
|
|
/* clear the blockgc 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_BLOCKGC_TAG);
|
|
|
|
|
spin_unlock(&ip->i_mount->m_perag_lock);
|
|
|
|
|
trace_xfs_perag_clear_blockgc(ip->i_mount, pag->pag_agno, -1,
|
|
|
|
|
_RET_IP_);
|
|
|
|
|
}
|
|
|
|
|
xfs_perag_clear_inode_tag(pag, XFS_INO_TO_AGINO(mp, ip->i_ino),
|
|
|
|
|
XFS_ICI_BLOCKGC_TAG);
|
|
|
|
|
|
|
|
|
|
spin_unlock(&pag->pag_ici_lock);
|
|
|
|
|
xfs_perag_put(pag);
|
|
|
|
|
|