@@ -2848,3 +2848,91 @@ xfs_ialloc_setup_geometry(
else
igeo->ialloc_align = 0;
}
+
+/*
+ * Compute the first and last inodes numbers of the inode chunk that was
+ * preallocated for the root directory.
+ */
+void
+xfs_ialloc_find_prealloc(
+ struct xfs_mount *mp,
+ xfs_agino_t *first_agino,
+ xfs_agino_t *last_agino)
+{
+ struct xfs_ino_geometry *igeo = M_IGEO(mp);
+ xfs_agblock_t first_bno;
+
+ /*
+ * Pre-calculate the geometry of ag 0. We know what it looks like
+ * because we know what mkfs does: 2 allocation btree roots (by block
+ * and by size), the inode allocation btree root, the free inode
+ * allocation btree root (if enabled) and some number of blocks to
+ * prefill the agfl.
+ *
+ * Because the current shape of the btrees may differ from the current
+ * shape, we open code the mkfs freelist block count here. mkfs creates
+ * single level trees, so the calculation is pertty straight forward for
+ * the trees that use the AGFL.
+ */
+
+ /* free space by block btree root comes after the ag headers */
+ first_bno = howmany(4 * mp->m_sb.sb_sectsize, mp->m_sb.sb_blocksize);
+
+ /* free space by length btree root */
+ first_bno += 1;
+
+ /* inode btree root */
+ first_bno += 1;
+
+ /* agfl */
+ first_bno += (2 * min(2U, mp->m_ag_maxlevels)) + 1;
+
+ if (xfs_sb_version_hasfinobt(&mp->m_sb))
+ first_bno++;
+
+ if (xfs_sb_version_hasrmapbt(&mp->m_sb)) {
+ first_bno += min(2U, mp->m_rmap_maxlevels); /* agfl blocks */
+ first_bno++;
+ }
+
+ if (xfs_sb_version_hasreflink(&mp->m_sb))
+ first_bno++;
+
+ /*
+ * If the log is allocated in the first allocation group we need to
+ * add the number of blocks used by the log to the above calculation.
+ *
+ * This can happens with filesystems that only have a single
+ * allocation group, or very odd geometries created by old mkfs
+ * versions on very small filesystems.
+ */
+ if (mp->m_sb.sb_logstart &&
+ XFS_FSB_TO_AGNO(mp, mp->m_sb.sb_logstart) == 0) {
+
+ /*
+ * XXX(hch): verify that sb_logstart makes sense?
+ */
+ first_bno += mp->m_sb.sb_logblocks;
+ }
+
+ /*
+ * ditto the location of the first inode chunks in the fs ('/')
+ */
+ if (xfs_sb_version_hasdalign(&mp->m_sb) && igeo->ialloc_align > 0) {
+ *first_agino = XFS_AGB_TO_AGINO(mp,
+ roundup(first_bno, mp->m_sb.sb_unit));
+ } else if (xfs_sb_version_hasalign(&mp->m_sb) &&
+ mp->m_sb.sb_inoalignmt > 1) {
+ *first_agino = XFS_AGB_TO_AGINO(mp,
+ roundup(first_bno, mp->m_sb.sb_inoalignmt));
+ } else {
+ *first_agino = XFS_AGB_TO_AGINO(mp, first_bno);
+ }
+
+ ASSERT(igeo->ialloc_blks > 0);
+
+ if (igeo->ialloc_blks > 1)
+ *last_agino = *first_agino + XFS_INODES_PER_CHUNK;
+ else
+ *last_agino = XFS_AGB_TO_AGINO(mp, first_bno + 1);
+}
@@ -152,5 +152,7 @@ int xfs_inobt_insert_rec(struct xfs_btree_cur *cur, uint16_t holemask,
int xfs_ialloc_cluster_alignment(struct xfs_mount *mp);
void xfs_ialloc_setup_geometry(struct xfs_mount *mp);
+void xfs_ialloc_find_prealloc(struct xfs_mount *mp, xfs_agino_t *first_agino,
+ xfs_agino_t *last_agino);
#endif /* __XFS_IALLOC_H__ */