int xfs_inode_ag_iterator_tag( struct xfs_mount *mp, int (*execute)(struct xfs_inode *ip, int flags, void *args), int flags, void *args, int tag) { struct xfs_perag *pag; int error = 0; int last_error = 0; xfs_agnumber_t ag; ag = 0; while ((pag = xfs_perag_get_tag(mp, ag, tag))) { ag = pag->pag_agno + 1; error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag); xfs_perag_put(pag); if (error) { last_error = error; if (error == -EFSCORRUPTED) break; } } return last_error; }
int xfs_reclaim_inodes_count( struct xfs_mount *mp) { struct xfs_perag *pag; xfs_agnumber_t ag = 0; int reclaimable = 0; while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { ag = pag->pag_agno + 1; reclaimable += pag->pag_ici_reclaimable; xfs_perag_put(pag); } return reclaimable; }
/* * Inode cache shrinker. * * When called we make sure that there is a background (fast) inode reclaim in * progress, while we will throttle the speed of reclaim via doiing synchronous * reclaim of inodes. That means if we come across dirty inodes, we wait for * them to be cleaned, which we hope will not be very long due to the * background walker having already kicked the IO off on those dirty inodes. */ static int xfs_reclaim_inode_shrink( struct shrinker *shrink, struct shrink_control *sc) { struct xfs_mount *mp; struct xfs_perag *pag; xfs_agnumber_t ag; int reclaimable; int nr_to_scan = sc->nr_to_scan; gfp_t gfp_mask = sc->gfp_mask; mp = container_of(shrink, struct xfs_mount, m_inode_shrink); if (nr_to_scan) { /* kick background reclaimer and push the AIL */ xfs_syncd_queue_reclaim(mp); xfs_ail_push_all(mp->m_ail); if (!(gfp_mask & __GFP_FS)) return -1; xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); /* terminate if we don't exhaust the scan */ if (nr_to_scan > 0) return -1; } reclaimable = 0; ag = 0; while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { ag = pag->pag_agno + 1; reclaimable += pag->pag_ici_reclaimable; xfs_perag_put(pag); } return reclaimable; }
int xfs_reclaim_inodes_ag( struct xfs_mount *mp, int flags, int *nr_to_scan) { struct xfs_perag *pag; int error = 0; int last_error = 0; xfs_agnumber_t ag; int trylock = flags & SYNC_TRYLOCK; int skipped; restart: ag = 0; skipped = 0; while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { unsigned long first_index = 0; int done = 0; int nr_found = 0; ag = pag->pag_agno + 1; if (trylock) { if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) { skipped++; xfs_perag_put(pag); continue; } first_index = pag->pag_ici_reclaim_cursor; } else mutex_lock(&pag->pag_ici_reclaim_lock); do { struct xfs_inode *batch[XFS_LOOKUP_BATCH]; int i; rcu_read_lock(); nr_found = radix_tree_gang_lookup_tag( &pag->pag_ici_root, (void **)batch, first_index, XFS_LOOKUP_BATCH, XFS_ICI_RECLAIM_TAG); if (!nr_found) { done = 1; rcu_read_unlock(); break; } for (i = 0; i < nr_found; i++) { struct xfs_inode *ip = batch[i]; if (done || xfs_reclaim_inode_grab(ip, flags)) batch[i] = NULL; if (XFS_INO_TO_AGNO(mp, ip->i_ino) != pag->pag_agno) continue; first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) done = 1; } rcu_read_unlock(); for (i = 0; i < nr_found; i++) { if (!batch[i]) continue; error = xfs_reclaim_inode(batch[i], pag, flags); if (error && last_error != EFSCORRUPTED) last_error = error; } *nr_to_scan -= XFS_LOOKUP_BATCH; cond_resched(); } while (nr_found && !done && *nr_to_scan > 0); if (trylock && !done) pag->pag_ici_reclaim_cursor = first_index; else pag->pag_ici_reclaim_cursor = 0; mutex_unlock(&pag->pag_ici_reclaim_lock); xfs_perag_put(pag); } if (skipped && (flags & SYNC_WAIT) && *nr_to_scan > 0) { trylock = 0; goto restart; } return XFS_ERROR(last_error); }
/* * Walk the AGs and reclaim the inodes in them. Even if the filesystem is * corrupted, we still want to try to reclaim all the inodes. If we don't, * then a shut down during filesystem unmount reclaim walk leak all the * unreclaimed inodes. */ int xfs_reclaim_inodes_ag( struct xfs_mount *mp, int flags, int *nr_to_scan) { struct xfs_perag *pag; int error = 0; int last_error = 0; xfs_agnumber_t ag; int trylock = flags & SYNC_TRYLOCK; int skipped; restart: ag = 0; skipped = 0; while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { unsigned long first_index = 0; int done = 0; int nr_found = 0; ag = pag->pag_agno + 1; if (trylock) { if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) { skipped++; xfs_perag_put(pag); continue; } first_index = pag->pag_ici_reclaim_cursor; } else mutex_lock(&pag->pag_ici_reclaim_lock); do { struct xfs_inode *batch[XFS_LOOKUP_BATCH]; int i; rcu_read_lock(); nr_found = radix_tree_gang_lookup_tag( &pag->pag_ici_root, (void **)batch, first_index, XFS_LOOKUP_BATCH, XFS_ICI_RECLAIM_TAG); if (!nr_found) { done = 1; rcu_read_unlock(); break; } /* * Grab the inodes before we drop the lock. if we found * nothing, nr == 0 and the loop will be skipped. */ for (i = 0; i < nr_found; i++) { struct xfs_inode *ip = batch[i]; if (done || xfs_reclaim_inode_grab(ip, flags)) batch[i] = NULL; /* * Update the index for the next lookup. Catch * overflows into the next AG range which can * occur if we have inodes in the last block of * the AG and we are currently pointing to the * last inode. * * Because we may see inodes that are from the * wrong AG due to RCU freeing and * reallocation, only update the index if it * lies in this AG. It was a race that lead us * to see this inode, so another lookup from * the same index will not find it again. */ if (XFS_INO_TO_AGNO(mp, ip->i_ino) != pag->pag_agno) continue; first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) done = 1; } /* unlock now we've grabbed the inodes. */ rcu_read_unlock(); for (i = 0; i < nr_found; i++) { if (!batch[i]) continue; error = xfs_reclaim_inode(batch[i], pag, flags); if (error && last_error != EFSCORRUPTED) last_error = error; } *nr_to_scan -= XFS_LOOKUP_BATCH; } while (nr_found && !done && *nr_to_scan > 0); if (trylock && !done) pag->pag_ici_reclaim_cursor = first_index; else pag->pag_ici_reclaim_cursor = 0; mutex_unlock(&pag->pag_ici_reclaim_lock); xfs_perag_put(pag); } /* * if we skipped any AG, and we still have scan count remaining, do * another pass this time using blocking reclaim semantics (i.e * waiting on the reclaim locks and ignoring the reclaim cursors). This * ensure that when we get more reclaimers than AGs we block rather * than spin trying to execute reclaim. */ if (trylock && skipped && *nr_to_scan > 0) { trylock = 0; goto restart; } return XFS_ERROR(last_error); }