|
@@ -62,6 +62,70 @@ xfs_prealloc_blocks(
|
|
|
return XFS_IBT_BLOCK(mp) + 1;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * In order to avoid ENOSPC-related deadlock caused by out-of-order locking of
|
|
|
+ * AGF buffer (PV 947395), we place constraints on the relationship among
|
|
|
+ * actual allocations for data blocks, freelist blocks, and potential file data
|
|
|
+ * bmap btree blocks. However, these restrictions may result in no actual space
|
|
|
+ * allocated for a delayed extent, for example, a data block in a certain AG is
|
|
|
+ * allocated but there is no additional block for the additional bmap btree
|
|
|
+ * block due to a split of the bmap btree of the file. The result of this may
|
|
|
+ * lead to an infinite loop when the file gets flushed to disk and all delayed
|
|
|
+ * extents need to be actually allocated. To get around this, we explicitly set
|
|
|
+ * aside a few blocks which will not be reserved in delayed allocation.
|
|
|
+ *
|
|
|
+ * When rmap is disabled, we need to reserve 4 fsbs _per AG_ for the freelist
|
|
|
+ * and 4 more to handle a potential split of the file's bmap btree.
|
|
|
+ *
|
|
|
+ * When rmap is enabled, we must also be able to handle two rmap btree inserts
|
|
|
+ * to record both the file data extent and a new bmbt block. The bmbt block
|
|
|
+ * might not be in the same AG as the file data extent. In the worst case
|
|
|
+ * the bmap btree splits multiple levels and all the new blocks come from
|
|
|
+ * different AGs, so set aside enough to handle rmap btree splits in all AGs.
|
|
|
+ */
|
|
|
+unsigned int
|
|
|
+xfs_alloc_set_aside(
|
|
|
+ struct xfs_mount *mp)
|
|
|
+{
|
|
|
+ unsigned int blocks;
|
|
|
+
|
|
|
+ blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE);
|
|
|
+ if (xfs_sb_version_hasrmapbt(&mp->m_sb))
|
|
|
+ blocks += mp->m_sb.sb_agcount * mp->m_rmap_maxlevels;
|
|
|
+ return blocks;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * When deciding how much space to allocate out of an AG, we limit the
|
|
|
+ * allocation maximum size to the size the AG. However, we cannot use all the
|
|
|
+ * blocks in the AG - some are permanently used by metadata. These
|
|
|
+ * blocks are generally:
|
|
|
+ * - the AG superblock, AGF, AGI and AGFL
|
|
|
+ * - the AGF (bno and cnt) and AGI btree root blocks, and optionally
|
|
|
+ * the AGI free inode and rmap btree root blocks.
|
|
|
+ * - blocks on the AGFL according to xfs_alloc_set_aside() limits
|
|
|
+ * - the rmapbt root block
|
|
|
+ *
|
|
|
+ * The AG headers are sector sized, so the amount of space they take up is
|
|
|
+ * dependent on filesystem geometry. The others are all single blocks.
|
|
|
+ */
|
|
|
+unsigned int
|
|
|
+xfs_alloc_ag_max_usable(
|
|
|
+ struct xfs_mount *mp)
|
|
|
+{
|
|
|
+ unsigned int blocks;
|
|
|
+
|
|
|
+ blocks = XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)); /* ag headers */
|
|
|
+ blocks += XFS_ALLOC_AGFL_RESERVE;
|
|
|
+ blocks += 3; /* AGF, AGI btree root blocks */
|
|
|
+ if (xfs_sb_version_hasfinobt(&mp->m_sb))
|
|
|
+ blocks++; /* finobt root block */
|
|
|
+ if (xfs_sb_version_hasrmapbt(&mp->m_sb))
|
|
|
+ blocks++; /* rmap root block */
|
|
|
+
|
|
|
+ return mp->m_sb.sb_agblocks - blocks;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Lookup the record equal to [bno, len] in the btree given by cur.
|
|
|
*/
|
|
@@ -1904,6 +1968,11 @@ xfs_alloc_min_freelist(
|
|
|
/* space needed by-size freespace btree */
|
|
|
min_free += min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_CNTi] + 1,
|
|
|
mp->m_ag_maxlevels);
|
|
|
+ /* space needed reverse mapping used space btree */
|
|
|
+ if (xfs_sb_version_hasrmapbt(&mp->m_sb))
|
|
|
+ min_free += min_t(unsigned int,
|
|
|
+ pag->pagf_levels[XFS_BTNUM_RMAPi] + 1,
|
|
|
+ mp->m_rmap_maxlevels);
|
|
|
|
|
|
return min_free;
|
|
|
}
|