@@ -2848,3 +2848,84 @@ xfs_ialloc_setup_geometry(
else
igeo->ialloc_align = 0;
}
+
+/*
+ * Compute the location of the root directory inode that is laid out by mkfs.
+ * The @sunit parameter will be copied from the superblock if it is negative.
+ */
+xfs_ino_t
+xfs_ialloc_calc_rootino(
+ struct xfs_mount *mp,
+ int sunit)
+{
+ struct xfs_ino_geometry *igeo = M_IGEO(mp);
+ xfs_agino_t first_agino;
+ xfs_agblock_t first_bno;
+
+ if (sunit < 0)
+ sunit = mp->m_sb.sb_unit;
+
+ /*
+ * 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 pretty 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_t(xfs_agblock_t, 2, 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++;
+ /* agfl blocks */
+ first_bno += min_t(xfs_agblock_t, 2, mp->m_rmap_maxlevels);
+ }
+
+ 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)
+ 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, sunit));
+ } 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);
+ }
+
+ return XFS_AGINO_TO_INO(mp, 0, first_agino);
+}
@@ -152,5 +152,6 @@ 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);
+xfs_ino_t xfs_ialloc_calc_rootino(struct xfs_mount *mp, int sunit);
#endif /* __XFS_IALLOC_H__ */