Commit 9d43b180 authored by Brian Foster's avatar Brian Foster Committed by Dave Chinner

xfs: update inode allocation/free transaction reservations for finobt

Create the xfs_calc_finobt_res() helper to calculate the finobt log
reservation for inode allocation and free. Update
XFS_IALLOC_SPACE_RES() to reserve blocks for the additional finobt
insertion on inode allocation. Create XFS_IFREE_SPACE_RES() to
reserve blocks for the potential finobt record insertion on inode
free (i.e., if an inode chunk was previously fully allocated).
Signed-off-by: default avatarBrian Foster <bfoster@redhat.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent aafc3c24
...@@ -1837,9 +1837,33 @@ xfs_inactive_ifree( ...@@ -1837,9 +1837,33 @@ xfs_inactive_ifree(
int error; int error;
tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0);
/*
* The ifree transaction might need to allocate blocks for record
* insertion to the finobt. We don't want to fail here at ENOSPC, so
* allow ifree to dip into the reserved block pool if necessary.
*
* Freeing large sets of inodes generally means freeing inode chunks,
* directory and file data blocks, so this should be relatively safe.
* Only under severe circumstances should it be possible to free enough
* inodes to exhaust the reserve block pool via finobt expansion while
* at the same time not creating free space in the filesystem.
*
* Send a warning if the reservation does happen to fail, as the inode
* now remains allocated and sits on the unlinked list until the fs is
* repaired.
*/
tp->t_flags |= XFS_TRANS_RESERVE;
error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
XFS_IFREE_SPACE_RES(mp), 0);
if (error) { if (error) {
if (error == ENOSPC) {
xfs_warn_ratelimited(mp,
"Failed to remove inode(s) from unlinked list. "
"Please free space, unmount and run xfs_repair.");
} else {
ASSERT(XFS_FORCED_SHUTDOWN(mp)); ASSERT(XFS_FORCED_SHUTDOWN(mp));
}
xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
return error; return error;
} }
......
...@@ -105,6 +105,47 @@ xfs_calc_inode_res( ...@@ -105,6 +105,47 @@ xfs_calc_inode_res(
2 * XFS_BMBT_BLOCK_LEN(mp)); 2 * XFS_BMBT_BLOCK_LEN(mp));
} }
/*
* The free inode btree is a conditional feature and the log reservation
* requirements differ slightly from that of the traditional inode allocation
* btree. The finobt tracks records for inode chunks with at least one free
* inode. A record can be removed from the tree for an inode allocation
* or free and thus the finobt reservation is unconditional across:
*
* - inode allocation
* - inode free
* - inode chunk allocation
*
* The 'modify' param indicates to include the record modification scenario. The
* 'alloc' param indicates to include the reservation for free space btree
* modifications on behalf of finobt modifications. This is required only for
* transactions that do not already account for free space btree modifications.
*
* the free inode btree: max depth * block size
* the allocation btrees: 2 trees * (max depth - 1) * block size
* the free inode btree entry: block size
*/
STATIC uint
xfs_calc_finobt_res(
struct xfs_mount *mp,
int alloc,
int modify)
{
uint res;
if (!xfs_sb_version_hasfinobt(&mp->m_sb))
return 0;
res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
if (alloc)
res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1));
if (modify)
res += (uint)XFS_FSB_TO_B(mp, 1);
return res;
}
/* /*
* Various log reservation values. * Various log reservation values.
* *
...@@ -302,6 +343,7 @@ xfs_calc_remove_reservation( ...@@ -302,6 +343,7 @@ xfs_calc_remove_reservation(
* the superblock for the nlink flag: sector size * the superblock for the nlink flag: sector size
* the directory btree: (max depth + v2) * dir block size * the directory btree: (max depth + v2) * dir block size
* the directory inode's bmap btree: (max depth + v2) * block size * the directory inode's bmap btree: (max depth + v2) * block size
* the finobt (record modification and allocation btrees)
*/ */
STATIC uint STATIC uint
xfs_calc_create_resv_modify( xfs_calc_create_resv_modify(
...@@ -310,7 +352,8 @@ xfs_calc_create_resv_modify( ...@@ -310,7 +352,8 @@ xfs_calc_create_resv_modify(
return xfs_calc_inode_res(mp, 2) + return xfs_calc_inode_res(mp, 2) +
xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
(uint)XFS_FSB_TO_B(mp, 1) + (uint)XFS_FSB_TO_B(mp, 1) +
xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 1, 1);
} }
/* /*
...@@ -348,6 +391,7 @@ __xfs_calc_create_reservation( ...@@ -348,6 +391,7 @@ __xfs_calc_create_reservation(
* the superblock for the nlink flag: sector size * the superblock for the nlink flag: sector size
* the inode btree: max depth * blocksize * the inode btree: max depth * blocksize
* the allocation btrees: 2 trees * (max depth - 1) * block size * the allocation btrees: 2 trees * (max depth - 1) * block size
* the finobt (record insertion)
*/ */
STATIC uint STATIC uint
xfs_calc_icreate_resv_alloc( xfs_calc_icreate_resv_alloc(
...@@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc( ...@@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc(
mp->m_sb.sb_sectsize + mp->m_sb.sb_sectsize +
xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1)); XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 0, 0);
} }
STATIC uint STATIC uint
...@@ -425,6 +470,7 @@ xfs_calc_symlink_reservation( ...@@ -425,6 +470,7 @@ xfs_calc_symlink_reservation(
* the on disk inode before ours in the agi hash list: inode cluster size * the on disk inode before ours in the agi hash list: inode cluster size
* the inode btree: max depth * blocksize * the inode btree: max depth * blocksize
* the allocation btrees: 2 trees * (max depth - 1) * block size * the allocation btrees: 2 trees * (max depth - 1) * block size
* the finobt (record insertion, removal or modification)
*/ */
STATIC uint STATIC uint
xfs_calc_ifree_reservation( xfs_calc_ifree_reservation(
...@@ -439,7 +485,8 @@ xfs_calc_ifree_reservation( ...@@ -439,7 +485,8 @@ xfs_calc_ifree_reservation(
xfs_calc_buf_res(2 + mp->m_ialloc_blks + xfs_calc_buf_res(2 + mp->m_ialloc_blks +
mp->m_in_maxlevels, 0) + mp->m_in_maxlevels, 0) +
xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
XFS_FSB_TO_B(mp, 1)); XFS_FSB_TO_B(mp, 1)) +
xfs_calc_finobt_res(mp, 0, 1);
} }
/* /*
......
...@@ -47,7 +47,9 @@ ...@@ -47,7 +47,9 @@
#define XFS_DIRREMOVE_SPACE_RES(mp) \ #define XFS_DIRREMOVE_SPACE_RES(mp) \
XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
#define XFS_IALLOC_SPACE_RES(mp) \ #define XFS_IALLOC_SPACE_RES(mp) \
((mp)->m_ialloc_blks + (mp)->m_in_maxlevels - 1) ((mp)->m_ialloc_blks + \
(xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
((mp)->m_in_maxlevels - 1)))
/* /*
* Space reservation values for various transactions. * Space reservation values for various transactions.
...@@ -82,5 +84,8 @@ ...@@ -82,5 +84,8 @@
(XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ #define XFS_SYMLINK_SPACE_RES(mp,nl,b) \
(XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
#define XFS_IFREE_SPACE_RES(mp) \
(xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
#endif /* __XFS_TRANS_SPACE_H__ */ #endif /* __XFS_TRANS_SPACE_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment