aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2014-04-24 02:00:52 -0400
committerDave Chinner <david@fromorbit.com>2014-04-24 02:00:52 -0400
commit9d43b180af67cccd4bd1342f7f54f8131515b0a1 (patch)
treef4bb0ee658249dc78c5465a850e53add0384b236
parentaafc3c24652924ea951d215d04a3f42e832e9d7d (diff)
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: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-rw-r--r--fs/xfs/xfs_inode.c28
-rw-r--r--fs/xfs/xfs_trans_resv.c53
-rw-r--r--fs/xfs/xfs_trans_space.h7
3 files changed, 82 insertions, 6 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index 5e7a38fa6ee6..a9079c142041 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1837,9 +1837,33 @@ xfs_inactive_ifree(
1837 int error; 1837 int error;
1838 1838
1839 tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE); 1839 tp = xfs_trans_alloc(mp, XFS_TRANS_INACTIVE);
1840 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree, 0, 0); 1840
1841 /*
1842 * The ifree transaction might need to allocate blocks for record
1843 * insertion to the finobt. We don't want to fail here at ENOSPC, so
1844 * allow ifree to dip into the reserved block pool if necessary.
1845 *
1846 * Freeing large sets of inodes generally means freeing inode chunks,
1847 * directory and file data blocks, so this should be relatively safe.
1848 * Only under severe circumstances should it be possible to free enough
1849 * inodes to exhaust the reserve block pool via finobt expansion while
1850 * at the same time not creating free space in the filesystem.
1851 *
1852 * Send a warning if the reservation does happen to fail, as the inode
1853 * now remains allocated and sits on the unlinked list until the fs is
1854 * repaired.
1855 */
1856 tp->t_flags |= XFS_TRANS_RESERVE;
1857 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ifree,
1858 XFS_IFREE_SPACE_RES(mp), 0);
1841 if (error) { 1859 if (error) {
1842 ASSERT(XFS_FORCED_SHUTDOWN(mp)); 1860 if (error == ENOSPC) {
1861 xfs_warn_ratelimited(mp,
1862 "Failed to remove inode(s) from unlinked list. "
1863 "Please free space, unmount and run xfs_repair.");
1864 } else {
1865 ASSERT(XFS_FORCED_SHUTDOWN(mp));
1866 }
1843 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES); 1867 xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES);
1844 return error; 1868 return error;
1845 } 1869 }
diff --git a/fs/xfs/xfs_trans_resv.c b/fs/xfs/xfs_trans_resv.c
index ae368165244d..52b6c3e3203e 100644
--- a/fs/xfs/xfs_trans_resv.c
+++ b/fs/xfs/xfs_trans_resv.c
@@ -106,6 +106,47 @@ xfs_calc_inode_res(
106} 106}
107 107
108/* 108/*
109 * The free inode btree is a conditional feature and the log reservation
110 * requirements differ slightly from that of the traditional inode allocation
111 * btree. The finobt tracks records for inode chunks with at least one free
112 * inode. A record can be removed from the tree for an inode allocation
113 * or free and thus the finobt reservation is unconditional across:
114 *
115 * - inode allocation
116 * - inode free
117 * - inode chunk allocation
118 *
119 * The 'modify' param indicates to include the record modification scenario. The
120 * 'alloc' param indicates to include the reservation for free space btree
121 * modifications on behalf of finobt modifications. This is required only for
122 * transactions that do not already account for free space btree modifications.
123 *
124 * the free inode btree: max depth * block size
125 * the allocation btrees: 2 trees * (max depth - 1) * block size
126 * the free inode btree entry: block size
127 */
128STATIC uint
129xfs_calc_finobt_res(
130 struct xfs_mount *mp,
131 int alloc,
132 int modify)
133{
134 uint res;
135
136 if (!xfs_sb_version_hasfinobt(&mp->m_sb))
137 return 0;
138
139 res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1));
140 if (alloc)
141 res += xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
142 XFS_FSB_TO_B(mp, 1));
143 if (modify)
144 res += (uint)XFS_FSB_TO_B(mp, 1);
145
146 return res;
147}
148
149/*
109 * Various log reservation values. 150 * Various log reservation values.
110 * 151 *
111 * These are based on the size of the file system block because that is what 152 * These are based on the size of the file system block because that is what
@@ -302,6 +343,7 @@ xfs_calc_remove_reservation(
302 * the superblock for the nlink flag: sector size 343 * the superblock for the nlink flag: sector size
303 * the directory btree: (max depth + v2) * dir block size 344 * the directory btree: (max depth + v2) * dir block size
304 * the directory inode's bmap btree: (max depth + v2) * block size 345 * the directory inode's bmap btree: (max depth + v2) * block size
346 * the finobt (record modification and allocation btrees)
305 */ 347 */
306STATIC uint 348STATIC uint
307xfs_calc_create_resv_modify( 349xfs_calc_create_resv_modify(
@@ -310,7 +352,8 @@ xfs_calc_create_resv_modify(
310 return xfs_calc_inode_res(mp, 2) + 352 return xfs_calc_inode_res(mp, 2) +
311 xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + 353 xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) +
312 (uint)XFS_FSB_TO_B(mp, 1) + 354 (uint)XFS_FSB_TO_B(mp, 1) +
313 xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)); 355 xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) +
356 xfs_calc_finobt_res(mp, 1, 1);
314} 357}
315 358
316/* 359/*
@@ -348,6 +391,7 @@ __xfs_calc_create_reservation(
348 * the superblock for the nlink flag: sector size 391 * the superblock for the nlink flag: sector size
349 * the inode btree: max depth * blocksize 392 * the inode btree: max depth * blocksize
350 * the allocation btrees: 2 trees * (max depth - 1) * block size 393 * the allocation btrees: 2 trees * (max depth - 1) * block size
394 * the finobt (record insertion)
351 */ 395 */
352STATIC uint 396STATIC uint
353xfs_calc_icreate_resv_alloc( 397xfs_calc_icreate_resv_alloc(
@@ -357,7 +401,8 @@ xfs_calc_icreate_resv_alloc(
357 mp->m_sb.sb_sectsize + 401 mp->m_sb.sb_sectsize +
358 xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + 402 xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) +
359 xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), 403 xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
360 XFS_FSB_TO_B(mp, 1)); 404 XFS_FSB_TO_B(mp, 1)) +
405 xfs_calc_finobt_res(mp, 0, 0);
361} 406}
362 407
363STATIC uint 408STATIC uint
@@ -425,6 +470,7 @@ xfs_calc_symlink_reservation(
425 * the on disk inode before ours in the agi hash list: inode cluster size 470 * the on disk inode before ours in the agi hash list: inode cluster size
426 * the inode btree: max depth * blocksize 471 * the inode btree: max depth * blocksize
427 * the allocation btrees: 2 trees * (max depth - 1) * block size 472 * the allocation btrees: 2 trees * (max depth - 1) * block size
473 * the finobt (record insertion, removal or modification)
428 */ 474 */
429STATIC uint 475STATIC uint
430xfs_calc_ifree_reservation( 476xfs_calc_ifree_reservation(
@@ -439,7 +485,8 @@ xfs_calc_ifree_reservation(
439 xfs_calc_buf_res(2 + mp->m_ialloc_blks + 485 xfs_calc_buf_res(2 + mp->m_ialloc_blks +
440 mp->m_in_maxlevels, 0) + 486 mp->m_in_maxlevels, 0) +
441 xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1), 487 xfs_calc_buf_res(XFS_ALLOCFREE_LOG_COUNT(mp, 1),
442 XFS_FSB_TO_B(mp, 1)); 488 XFS_FSB_TO_B(mp, 1)) +
489 xfs_calc_finobt_res(mp, 0, 1);
443} 490}
444 491
445/* 492/*
diff --git a/fs/xfs/xfs_trans_space.h b/fs/xfs/xfs_trans_space.h
index af5dbe06cb65..df4c1f81884c 100644
--- a/fs/xfs/xfs_trans_space.h
+++ b/fs/xfs/xfs_trans_space.h
@@ -47,7 +47,9 @@
47#define XFS_DIRREMOVE_SPACE_RES(mp) \ 47#define XFS_DIRREMOVE_SPACE_RES(mp) \
48 XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) 48 XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK)
49#define XFS_IALLOC_SPACE_RES(mp) \ 49#define XFS_IALLOC_SPACE_RES(mp) \
50 ((mp)->m_ialloc_blks + (mp)->m_in_maxlevels - 1) 50 ((mp)->m_ialloc_blks + \
51 (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \
52 ((mp)->m_in_maxlevels - 1)))
51 53
52/* 54/*
53 * Space reservation values for various transactions. 55 * Space reservation values for various transactions.
@@ -82,5 +84,8 @@
82 (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) 84 (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl))
83#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ 85#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \
84 (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) 86 (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b))
87#define XFS_IFREE_SPACE_RES(mp) \
88 (xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0)
89
85 90
86#endif /* __XFS_TRANS_SPACE_H__ */ 91#endif /* __XFS_TRANS_SPACE_H__ */