STATIC int xfs_inode_ag_walk( struct xfs_mount *mp, struct xfs_perag *pag, int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), int flags) { uint32_t first_index; int last_error = 0; int skipped; int done; int nr_found; restart: done = 0; skipped = 0; first_index = 0; nr_found = 0; do { struct xfs_inode *batch[XFS_LOOKUP_BATCH]; int error = 0; int i; rcu_read_lock(); nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void **)batch, first_index, XFS_LOOKUP_BATCH); if (!nr_found) { rcu_read_unlock(); break; } for (i = 0; i < nr_found; i++) { struct xfs_inode *ip = batch[i]; if (done || xfs_inode_ag_walk_grab(ip)) 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 = execute(batch[i], pag, flags); IRELE(batch[i]); if (error == EAGAIN) { skipped++; continue; } if (error && last_error != EFSCORRUPTED) last_error = error; } if (error == EFSCORRUPTED) break; cond_resched(); } while (nr_found && !done); if (skipped) { delay(1); goto restart; } return last_error; }
STATIC int xfs_inode_ag_walk( struct xfs_mount *mp, struct xfs_perag *pag, int (*execute)(struct xfs_inode *ip, struct xfs_perag *pag, int flags), int flags) { uint32_t first_index; int last_error = 0; int skipped; int done; int nr_found; restart: done = 0; skipped = 0; first_index = 0; nr_found = 0; do { struct xfs_inode *batch[XFS_LOOKUP_BATCH]; int error = 0; int i; rcu_read_lock(); nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void **)batch, first_index, XFS_LOOKUP_BATCH); if (!nr_found) { 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_inode_ag_walk_grab(ip)) 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 = execute(batch[i], pag, flags); IRELE(batch[i]); if (error == EAGAIN) { skipped++; continue; } if (error && last_error != EFSCORRUPTED) last_error = error; } /* bail out if the filesystem is corrupted. */ if (error == EFSCORRUPTED) break; } while (nr_found && !done); if (skipped) { delay(1); goto restart; } return last_error; }