diff options
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 73 |
1 files changed, 54 insertions, 19 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index b48abc300c36..6de613b558a9 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -4721,6 +4721,47 @@ error0: | |||
4721 | } | 4721 | } |
4722 | 4722 | ||
4723 | /* | 4723 | /* |
4724 | * When a delalloc extent is split (e.g., due to a hole punch), the original | ||
4725 | * indlen reservation must be shared across the two new extents that are left | ||
4726 | * behind. | ||
4727 | * | ||
4728 | * Given the original reservation and the worst case indlen for the two new | ||
4729 | * extents (as calculated by xfs_bmap_worst_indlen()), split the original | ||
4730 | * reservation fairly across the two new extents. | ||
4731 | */ | ||
4732 | static void | ||
4733 | xfs_bmap_split_indlen( | ||
4734 | xfs_filblks_t ores, /* original res. */ | ||
4735 | xfs_filblks_t *indlen1, /* ext1 worst indlen */ | ||
4736 | xfs_filblks_t *indlen2) /* ext2 worst indlen */ | ||
4737 | { | ||
4738 | xfs_filblks_t len1 = *indlen1; | ||
4739 | xfs_filblks_t len2 = *indlen2; | ||
4740 | xfs_filblks_t nres = len1 + len2; /* new total res. */ | ||
4741 | |||
4742 | /* | ||
4743 | * The only blocks available are those reserved for the original extent. | ||
4744 | * Therefore, we have to skim blocks off each of the new reservations so | ||
4745 | * long as the new total reservation is greater than the original. | ||
4746 | */ | ||
4747 | while (nres > ores) { | ||
4748 | if (len1) { | ||
4749 | len1--; | ||
4750 | nres--; | ||
4751 | } | ||
4752 | if (nres == ores) | ||
4753 | break; | ||
4754 | if (len2) { | ||
4755 | len2--; | ||
4756 | nres--; | ||
4757 | } | ||
4758 | } | ||
4759 | |||
4760 | *indlen1 = len1; | ||
4761 | *indlen2 = len2; | ||
4762 | } | ||
4763 | |||
4764 | /* | ||
4724 | * Called by xfs_bmapi to update file extent records and the btree | 4765 | * Called by xfs_bmapi to update file extent records and the btree |
4725 | * after removing space (or undoing a delayed allocation). | 4766 | * after removing space (or undoing a delayed allocation). |
4726 | */ | 4767 | */ |
@@ -4985,27 +5026,21 @@ xfs_bmap_del_extent( | |||
4985 | XFS_IFORK_NEXTENTS(ip, whichfork) + 1); | 5026 | XFS_IFORK_NEXTENTS(ip, whichfork) + 1); |
4986 | } else { | 5027 | } else { |
4987 | ASSERT(whichfork == XFS_DATA_FORK); | 5028 | ASSERT(whichfork == XFS_DATA_FORK); |
4988 | temp = xfs_bmap_worst_indlen(ip, temp); | 5029 | |
5030 | /* | ||
5031 | * Distribute the original indlen reservation across the | ||
5032 | * two new extents. | ||
5033 | */ | ||
5034 | temp = xfs_bmap_worst_indlen(ip, got.br_blockcount); | ||
5035 | temp2 = xfs_bmap_worst_indlen(ip, new.br_blockcount); | ||
5036 | xfs_bmap_split_indlen(da_old, &temp, &temp2); | ||
5037 | da_new = temp + temp2; | ||
5038 | |||
5039 | /* | ||
5040 | * Set the reservation for each extent. | ||
5041 | */ | ||
4989 | xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); | 5042 | xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); |
4990 | temp2 = xfs_bmap_worst_indlen(ip, temp2); | ||
4991 | new.br_startblock = nullstartblock((int)temp2); | 5043 | new.br_startblock = nullstartblock((int)temp2); |
4992 | da_new = temp + temp2; | ||
4993 | while (da_new > da_old) { | ||
4994 | if (temp) { | ||
4995 | temp--; | ||
4996 | da_new--; | ||
4997 | xfs_bmbt_set_startblock(ep, | ||
4998 | nullstartblock((int)temp)); | ||
4999 | } | ||
5000 | if (da_new == da_old) | ||
5001 | break; | ||
5002 | if (temp2) { | ||
5003 | temp2--; | ||
5004 | da_new--; | ||
5005 | new.br_startblock = | ||
5006 | nullstartblock((int)temp2); | ||
5007 | } | ||
5008 | } | ||
5009 | } | 5044 | } |
5010 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); | 5045 | trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); |
5011 | xfs_iext_insert(ip, *idx + 1, 1, &new, state); | 5046 | xfs_iext_insert(ip, *idx + 1, 1, &new, state); |