aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2017-02-14 01:48:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-08 03:30:31 -0400
commitc251c6c2dec99562a0075c08d31257cff1bc1158 (patch)
tree6df2f272dd6f046974ea6453514a497e5f0a9d82
parent2d7c1c7ffafd6dffa3400cce60174fe904982101 (diff)
xfs: split indlen reservations fairly when under reserved
commit 75d65361cf3c0dae2af970c305e19c727b28a510 upstream. 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 7457937549bb..70e732ce3dea 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -4899,34 +4899,59 @@ xfs_bmap_split_indlen(
4899 xfs_filblks_t len2 = *indlen2; 4899 xfs_filblks_t len2 = *indlen2;
4900 xfs_filblks_t nres = len1 + len2; /* new total res. */ 4900 xfs_filblks_t nres = len1 + len2; /* new total res. */
4901 xfs_filblks_t stolen = 0; 4901 xfs_filblks_t stolen = 0;
4902 xfs_filblks_t resfactor;
4902 4903
4903 /* 4904 /*
4904 * Steal as many blocks as we can to try and satisfy the worst case 4905 * Steal as many blocks as we can to try and satisfy the worst case
4905 * indlen for both new extents. 4906 * indlen for both new extents.
4906 */ 4907 */
4907 while (nres > ores && avail) { 4908 if (ores < nres && avail)
4908 nres--; 4909 stolen = XFS_FILBLKS_MIN(nres - ores, avail);
4909 avail--; 4910 ores += stolen;
4910 stolen++; 4911
4911 } 4912 /* nothing else to do if we've satisfied the new reservation */
4913 if (ores >= nres)
4914 return stolen;
4915
4916 /*
4917 * We can't meet the total required reservation for the two extents.
4918 * Calculate the percent of the overall shortage between both extents
4919 * and apply this percentage to each of the requested indlen values.
4920 * This distributes the shortage fairly and reduces the chances that one
4921 * of the two extents is left with nothing when extents are repeatedly
4922 * split.
4923 */
4924 resfactor = (ores * 100);
4925 do_div(resfactor, nres);
4926 len1 *= resfactor;
4927 do_div(len1, 100);
4928 len2 *= resfactor;
4929 do_div(len2, 100);
4930 ASSERT(len1 + len2 <= ores);
4931 ASSERT(len1 < *indlen1 && len2 < *indlen2);
4912 4932
4913 /* 4933 /*
4914 * The only blocks available are those reserved for the original 4934 * Hand out the remainder to each extent. If one of the two reservations
4915 * extent and what we can steal from the extent being removed. 4935 * is zero, we want to make sure that one gets a block first. The loop
4916 * If this still isn't enough to satisfy the combined 4936 * below starts with len1, so hand len2 a block right off the bat if it
4917 * requirements for the two new extents, skim blocks off of each 4937 * is zero.
4918 * of the new reservations until they match what is available.
4919 */ 4938 */
4920 while (nres > ores) { 4939 ores -= (len1 + len2);
4921 if (len1) { 4940 ASSERT((*indlen1 - len1) + (*indlen2 - len2) >= ores);
4922 len1--; 4941 if (ores && !len2 && *indlen2) {
4923 nres--; 4942 len2++;
4943 ores--;
4944 }
4945 while (ores) {
4946 if (len1 < *indlen1) {
4947 len1++;
4948 ores--;
4924 } 4949 }
4925 if (nres == ores) 4950 if (!ores)
4926 break; 4951 break;
4927 if (len2) { 4952 if (len2 < *indlen2) {
4928 len2--; 4953 len2++;
4929 nres--; 4954 ores--;
4930 } 4955 }
4931 } 4956 }
4932 4957