summaryrefslogtreecommitdiffstats
path: root/fs/xfs/libxfs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2017-02-14 01:48:30 -0500
committerDarrick J. Wong <darrick.wong@oracle.com>2017-02-16 20:20:12 -0500
commit75d65361cf3c0dae2af970c305e19c727b28a510 (patch)
tree9966e057017ba46f31d7ff653934290b1eb62e13 /fs/xfs/libxfs
parent0e339ef8556d9e567aa7925f8892c263d79430d9 (diff)
xfs: split indlen reservations fairly when under reserved
Certain workoads that punch holes into speculative preallocation can cause delalloc indirect reservation splits when the delalloc extent is split in two. If further splits occur, an already short-handed extent can be split into two in a manner that leaves zero indirect blocks for one of the two new extents. This occurs because the shortage is large enough that the xfs_bmap_split_indlen() algorithm completely drains the requested indlen of one of the extents before it honors the existing reservation. This ultimately results in a warning from xfs_bmap_del_extent(). This has been observed during file copies of large, sparse files using 'cp --sparse=always.' To avoid this problem, update xfs_bmap_split_indlen() to explicitly apply the reservation shortage fairly between both extents. This smooths out the overall indlen shortage and defers the situation where we end up with a delalloc extent with zero indlen reservation to extreme circumstances. Reported-by: Patrick Dung <mpatdung@gmail.com> Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs/libxfs')
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c61
1 files changed, 43 insertions, 18 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index 73c95466c225..2ae55db8c977 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -4795,34 +4795,59 @@ xfs_bmap_split_indlen(
4795 xfs_filblks_t len2 = *indlen2; 4795 xfs_filblks_t len2 = *indlen2;
4796 xfs_filblks_t nres = len1 + len2; /* new total res. */ 4796 xfs_filblks_t nres = len1 + len2; /* new total res. */
4797 xfs_filblks_t stolen = 0; 4797 xfs_filblks_t stolen = 0;
4798 xfs_filblks_t resfactor;
4798 4799
4799 /* 4800 /*
4800 * Steal as many blocks as we can to try and satisfy the worst case 4801 * Steal as many blocks as we can to try and satisfy the worst case
4801 * indlen for both new extents. 4802 * indlen for both new extents.
4802 */ 4803 */
4803 while (nres > ores && avail) { 4804 if (ores < nres && avail)
4804 nres--; 4805 stolen = XFS_FILBLKS_MIN(nres - ores, avail);
4805 avail--; 4806 ores += stolen;
4806 stolen++; 4807
4807 } 4808 /* nothing else to do if we've satisfied the new reservation */
4809 if (ores >= nres)
4810 return stolen;
4811
4812 /*
4813 * We can't meet the total required reservation for the two extents.
4814 * Calculate the percent of the overall shortage between both extents
4815 * and apply this percentage to each of the requested indlen values.
4816 * This distributes the shortage fairly and reduces the chances that one
4817 * of the two extents is left with nothing when extents are repeatedly
4818 * split.
4819 */
4820 resfactor = (ores * 100);
4821 do_div(resfactor, nres);
4822 len1 *= resfactor;
4823 do_div(len1, 100);
4824 len2 *= resfactor;
4825 do_div(len2, 100);
4826 ASSERT(len1 + len2 <= ores);
4827 ASSERT(len1 < *indlen1 && len2 < *indlen2);
4808 4828
4809 /* 4829 /*
4810 * The only blocks available are those reserved for the original 4830 * Hand out the remainder to each extent. If one of the two reservations
4811 * extent and what we can steal from the extent being removed. 4831 * is zero, we want to make sure that one gets a block first. The loop
4812 * If this still isn't enough to satisfy the combined 4832 * below starts with len1, so hand len2 a block right off the bat if it
4813 * requirements for the two new extents, skim blocks off of each 4833 * is zero.
4814 * of the new reservations until they match what is available.
4815 */ 4834 */
4816 while (nres > ores) { 4835 ores -= (len1 + len2);
4817 if (len1) { 4836 ASSERT((*indlen1 - len1) + (*indlen2 - len2) >= ores);
4818 len1--; 4837 if (ores && !len2 && *indlen2) {
4819 nres--; 4838 len2++;
4839 ores--;
4840 }
4841 while (ores) {
4842 if (len1 < *indlen1) {
4843 len1++;
4844 ores--;
4820 } 4845 }
4821 if (nres == ores) 4846 if (!ores)
4822 break; 4847 break;
4823 if (len2) { 4848 if (len2 < *indlen2) {
4824 len2--; 4849 len2++;
4825 nres--; 4850 ores--;
4826 } 4851 }
4827 } 4852 }
4828 4853