aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/libxfs/xfs_bmap.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/libxfs/xfs_bmap.c')
-rw-r--r--fs/xfs/libxfs/xfs_bmap.c418
1 files changed, 246 insertions, 172 deletions
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c
index c27344cf38e1..c6eb21940783 100644
--- a/fs/xfs/libxfs/xfs_bmap.c
+++ b/fs/xfs/libxfs/xfs_bmap.c
@@ -3974,9 +3974,6 @@ xfs_bmap_remap_alloc(
3974 * allocating, so skip that check by pretending to be freeing. 3974 * allocating, so skip that check by pretending to be freeing.
3975 */ 3975 */
3976 error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); 3976 error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING);
3977 if (error)
3978 goto error0;
3979error0:
3980 xfs_perag_put(args.pag); 3977 xfs_perag_put(args.pag);
3981 if (error) 3978 if (error)
3982 trace_xfs_bmap_remap_alloc_error(ap->ip, error, _RET_IP_); 3979 trace_xfs_bmap_remap_alloc_error(ap->ip, error, _RET_IP_);
@@ -3999,6 +3996,39 @@ xfs_bmap_alloc(
3999 return xfs_bmap_btalloc(ap); 3996 return xfs_bmap_btalloc(ap);
4000} 3997}
4001 3998
3999/* Trim extent to fit a logical block range. */
4000void
4001xfs_trim_extent(
4002 struct xfs_bmbt_irec *irec,
4003 xfs_fileoff_t bno,
4004 xfs_filblks_t len)
4005{
4006 xfs_fileoff_t distance;
4007 xfs_fileoff_t end = bno + len;
4008
4009 if (irec->br_startoff + irec->br_blockcount <= bno ||
4010 irec->br_startoff >= end) {
4011 irec->br_blockcount = 0;
4012 return;
4013 }
4014
4015 if (irec->br_startoff < bno) {
4016 distance = bno - irec->br_startoff;
4017 if (isnullstartblock(irec->br_startblock))
4018 irec->br_startblock = DELAYSTARTBLOCK;
4019 if (irec->br_startblock != DELAYSTARTBLOCK &&
4020 irec->br_startblock != HOLESTARTBLOCK)
4021 irec->br_startblock += distance;
4022 irec->br_startoff += distance;
4023 irec->br_blockcount -= distance;
4024 }
4025
4026 if (end < irec->br_startoff + irec->br_blockcount) {
4027 distance = irec->br_startoff + irec->br_blockcount - end;
4028 irec->br_blockcount -= distance;
4029 }
4030}
4031
4002/* 4032/*
4003 * Trim the returned map to the required bounds 4033 * Trim the returned map to the required bounds
4004 */ 4034 */
@@ -4829,6 +4859,219 @@ xfs_bmap_split_indlen(
4829 return stolen; 4859 return stolen;
4830} 4860}
4831 4861
4862int
4863xfs_bmap_del_extent_delay(
4864 struct xfs_inode *ip,
4865 int whichfork,
4866 xfs_extnum_t *idx,
4867 struct xfs_bmbt_irec *got,
4868 struct xfs_bmbt_irec *del)
4869{
4870 struct xfs_mount *mp = ip->i_mount;
4871 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork);
4872 struct xfs_bmbt_irec new;
4873 int64_t da_old, da_new, da_diff = 0;
4874 xfs_fileoff_t del_endoff, got_endoff;
4875 xfs_filblks_t got_indlen, new_indlen, stolen;
4876 int error = 0, state = 0;
4877 bool isrt;
4878
4879 XFS_STATS_INC(mp, xs_del_exlist);
4880
4881 isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip);
4882 del_endoff = del->br_startoff + del->br_blockcount;
4883 got_endoff = got->br_startoff + got->br_blockcount;
4884 da_old = startblockval(got->br_startblock);
4885 da_new = 0;
4886
4887 ASSERT(*idx >= 0);
4888 ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
4889 ASSERT(del->br_blockcount > 0);
4890 ASSERT(got->br_startoff <= del->br_startoff);
4891 ASSERT(got_endoff >= del_endoff);
4892
4893 if (isrt) {
4894 int64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount);
4895
4896 do_div(rtexts, mp->m_sb.sb_rextsize);
4897 xfs_mod_frextents(mp, rtexts);
4898 }
4899
4900 /*
4901 * Update the inode delalloc counter now and wait to update the
4902 * sb counters as we might have to borrow some blocks for the
4903 * indirect block accounting.
4904 */
4905 xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del->br_blockcount), 0,
4906 isrt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS);
4907 ip->i_delayed_blks -= del->br_blockcount;
4908
4909 if (whichfork == XFS_COW_FORK)
4910 state |= BMAP_COWFORK;
4911
4912 if (got->br_startoff == del->br_startoff)
4913 state |= BMAP_LEFT_CONTIG;
4914 if (got_endoff == del_endoff)
4915 state |= BMAP_RIGHT_CONTIG;
4916
4917 switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) {
4918 case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
4919 /*
4920 * Matches the whole extent. Delete the entry.
4921 */
4922 xfs_iext_remove(ip, *idx, 1, state);
4923 --*idx;
4924 break;
4925 case BMAP_LEFT_CONTIG:
4926 /*
4927 * Deleting the first part of the extent.
4928 */
4929 trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
4930 got->br_startoff = del_endoff;
4931 got->br_blockcount -= del->br_blockcount;
4932 da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip,
4933 got->br_blockcount), da_old);
4934 got->br_startblock = nullstartblock((int)da_new);
4935 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
4936 trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
4937 break;
4938 case BMAP_RIGHT_CONTIG:
4939 /*
4940 * Deleting the last part of the extent.
4941 */
4942 trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
4943 got->br_blockcount = got->br_blockcount - del->br_blockcount;
4944 da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip,
4945 got->br_blockcount), da_old);
4946 got->br_startblock = nullstartblock((int)da_new);
4947 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
4948 trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
4949 break;
4950 case 0:
4951 /*
4952 * Deleting the middle of the extent.
4953 *
4954 * Distribute the original indlen reservation across the two new
4955 * extents. Steal blocks from the deleted extent if necessary.
4956 * Stealing blocks simply fudges the fdblocks accounting below.
4957 * Warn if either of the new indlen reservations is zero as this
4958 * can lead to delalloc problems.
4959 */
4960 trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
4961
4962 got->br_blockcount = del->br_startoff - got->br_startoff;
4963 got_indlen = xfs_bmap_worst_indlen(ip, got->br_blockcount);
4964
4965 new.br_blockcount = got_endoff - del_endoff;
4966 new_indlen = xfs_bmap_worst_indlen(ip, new.br_blockcount);
4967
4968 WARN_ON_ONCE(!got_indlen || !new_indlen);
4969 stolen = xfs_bmap_split_indlen(da_old, &got_indlen, &new_indlen,
4970 del->br_blockcount);
4971
4972 got->br_startblock = nullstartblock((int)got_indlen);
4973 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
4974 trace_xfs_bmap_post_update(ip, *idx, 0, _THIS_IP_);
4975
4976 new.br_startoff = del_endoff;
4977 new.br_state = got->br_state;
4978 new.br_startblock = nullstartblock((int)new_indlen);
4979
4980 ++*idx;
4981 xfs_iext_insert(ip, *idx, 1, &new, state);
4982
4983 da_new = got_indlen + new_indlen - stolen;
4984 del->br_blockcount -= stolen;
4985 break;
4986 }
4987
4988 ASSERT(da_old >= da_new);
4989 da_diff = da_old - da_new;
4990 if (!isrt)
4991 da_diff += del->br_blockcount;
4992 if (da_diff)
4993 xfs_mod_fdblocks(mp, da_diff, false);
4994 return error;
4995}
4996
4997void
4998xfs_bmap_del_extent_cow(
4999 struct xfs_inode *ip,
5000 xfs_extnum_t *idx,
5001 struct xfs_bmbt_irec *got,
5002 struct xfs_bmbt_irec *del)
5003{
5004 struct xfs_mount *mp = ip->i_mount;
5005 struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK);
5006 struct xfs_bmbt_irec new;
5007 xfs_fileoff_t del_endoff, got_endoff;
5008 int state = BMAP_COWFORK;
5009
5010 XFS_STATS_INC(mp, xs_del_exlist);
5011
5012 del_endoff = del->br_startoff + del->br_blockcount;
5013 got_endoff = got->br_startoff + got->br_blockcount;
5014
5015 ASSERT(*idx >= 0);
5016 ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec));
5017 ASSERT(del->br_blockcount > 0);
5018 ASSERT(got->br_startoff <= del->br_startoff);
5019 ASSERT(got_endoff >= del_endoff);
5020 ASSERT(!isnullstartblock(got->br_startblock));
5021
5022 if (got->br_startoff == del->br_startoff)
5023 state |= BMAP_LEFT_CONTIG;
5024 if (got_endoff == del_endoff)
5025 state |= BMAP_RIGHT_CONTIG;
5026
5027 switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) {
5028 case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG:
5029 /*
5030 * Matches the whole extent. Delete the entry.
5031 */
5032 xfs_iext_remove(ip, *idx, 1, state);
5033 --*idx;
5034 break;
5035 case BMAP_LEFT_CONTIG:
5036 /*
5037 * Deleting the first part of the extent.
5038 */
5039 trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
5040 got->br_startoff = del_endoff;
5041 got->br_blockcount -= del->br_blockcount;
5042 got->br_startblock = del->br_startblock + del->br_blockcount;
5043 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
5044 trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
5045 break;
5046 case BMAP_RIGHT_CONTIG:
5047 /*
5048 * Deleting the last part of the extent.
5049 */
5050 trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
5051 got->br_blockcount -= del->br_blockcount;
5052 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
5053 trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
5054 break;
5055 case 0:
5056 /*
5057 * Deleting the middle of the extent.
5058 */
5059 trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_);
5060 got->br_blockcount = del->br_startoff - got->br_startoff;
5061 xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got);
5062 trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_);
5063
5064 new.br_startoff = del_endoff;
5065 new.br_blockcount = got_endoff - del_endoff;
5066 new.br_state = got->br_state;
5067 new.br_startblock = del->br_startblock + del->br_blockcount;
5068
5069 ++*idx;
5070 xfs_iext_insert(ip, *idx, 1, &new, state);
5071 break;
5072 }
5073}
5074
4832/* 5075/*
4833 * Called by xfs_bmapi to update file extent records and the btree 5076 * Called by xfs_bmapi to update file extent records and the btree
4834 * after removing space (or undoing a delayed allocation). 5077 * after removing space (or undoing a delayed allocation).
@@ -5171,175 +5414,6 @@ done:
5171 return error; 5414 return error;
5172} 5415}
5173 5416
5174/* Remove an extent from the CoW fork. Similar to xfs_bmap_del_extent. */
5175int
5176xfs_bunmapi_cow(
5177 struct xfs_inode *ip,
5178 struct xfs_bmbt_irec *del)
5179{
5180 xfs_filblks_t da_new;
5181 xfs_filblks_t da_old;
5182 xfs_fsblock_t del_endblock = 0;
5183 xfs_fileoff_t del_endoff;
5184 int delay;
5185 struct xfs_bmbt_rec_host *ep;
5186 int error;
5187 struct xfs_bmbt_irec got;
5188 xfs_fileoff_t got_endoff;
5189 struct xfs_ifork *ifp;
5190 struct xfs_mount *mp;
5191 xfs_filblks_t nblks;
5192 struct xfs_bmbt_irec new;
5193 /* REFERENCED */
5194 uint qfield;
5195 xfs_filblks_t temp;
5196 xfs_filblks_t temp2;
5197 int state = BMAP_COWFORK;
5198 int eof;
5199 xfs_extnum_t eidx;
5200
5201 mp = ip->i_mount;
5202 XFS_STATS_INC(mp, xs_del_exlist);
5203
5204 ep = xfs_bmap_search_extents(ip, del->br_startoff, XFS_COW_FORK, &eof,
5205 &eidx, &got, &new);
5206
5207 ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); ifp = ifp;
5208 ASSERT((eidx >= 0) && (eidx < ifp->if_bytes /
5209 (uint)sizeof(xfs_bmbt_rec_t)));
5210 ASSERT(del->br_blockcount > 0);
5211 ASSERT(got.br_startoff <= del->br_startoff);
5212 del_endoff = del->br_startoff + del->br_blockcount;
5213 got_endoff = got.br_startoff + got.br_blockcount;
5214 ASSERT(got_endoff >= del_endoff);
5215 delay = isnullstartblock(got.br_startblock);
5216 ASSERT(isnullstartblock(del->br_startblock) == delay);
5217 qfield = 0;
5218 error = 0;
5219 /*
5220 * If deleting a real allocation, must free up the disk space.
5221 */
5222 if (!delay) {
5223 nblks = del->br_blockcount;
5224 qfield = XFS_TRANS_DQ_BCOUNT;
5225 /*
5226 * Set up del_endblock and cur for later.
5227 */
5228 del_endblock = del->br_startblock + del->br_blockcount;
5229 da_old = da_new = 0;
5230 } else {
5231 da_old = startblockval(got.br_startblock);
5232 da_new = 0;
5233 nblks = 0;
5234 }
5235 qfield = qfield;
5236 nblks = nblks;
5237
5238 /*
5239 * Set flag value to use in switch statement.
5240 * Left-contig is 2, right-contig is 1.
5241 */
5242 switch (((got.br_startoff == del->br_startoff) << 1) |
5243 (got_endoff == del_endoff)) {
5244 case 3:
5245 /*
5246 * Matches the whole extent. Delete the entry.
5247 */
5248 xfs_iext_remove(ip, eidx, 1, BMAP_COWFORK);
5249 --eidx;
5250 break;
5251
5252 case 2:
5253 /*
5254 * Deleting the first part of the extent.
5255 */
5256 trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_);
5257 xfs_bmbt_set_startoff(ep, del_endoff);
5258 temp = got.br_blockcount - del->br_blockcount;
5259 xfs_bmbt_set_blockcount(ep, temp);
5260 if (delay) {
5261 temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
5262 da_old);
5263 xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
5264 trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
5265 da_new = temp;
5266 break;
5267 }
5268 xfs_bmbt_set_startblock(ep, del_endblock);
5269 trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
5270 break;
5271
5272 case 1:
5273 /*
5274 * Deleting the last part of the extent.
5275 */
5276 temp = got.br_blockcount - del->br_blockcount;
5277 trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_);
5278 xfs_bmbt_set_blockcount(ep, temp);
5279 if (delay) {
5280 temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp),
5281 da_old);
5282 xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
5283 trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
5284 da_new = temp;
5285 break;
5286 }
5287 trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
5288 break;
5289
5290 case 0:
5291 /*
5292 * Deleting the middle of the extent.
5293 */
5294 temp = del->br_startoff - got.br_startoff;
5295 trace_xfs_bmap_pre_update(ip, eidx, state, _THIS_IP_);
5296 xfs_bmbt_set_blockcount(ep, temp);
5297 new.br_startoff = del_endoff;
5298 temp2 = got_endoff - del_endoff;
5299 new.br_blockcount = temp2;
5300 new.br_state = got.br_state;
5301 if (!delay) {
5302 new.br_startblock = del_endblock;
5303 } else {
5304 temp = xfs_bmap_worst_indlen(ip, temp);
5305 xfs_bmbt_set_startblock(ep, nullstartblock((int)temp));
5306 temp2 = xfs_bmap_worst_indlen(ip, temp2);
5307 new.br_startblock = nullstartblock((int)temp2);
5308 da_new = temp + temp2;
5309 while (da_new > da_old) {
5310 if (temp) {
5311 temp--;
5312 da_new--;
5313 xfs_bmbt_set_startblock(ep,
5314 nullstartblock((int)temp));
5315 }
5316 if (da_new == da_old)
5317 break;
5318 if (temp2) {
5319 temp2--;
5320 da_new--;
5321 new.br_startblock =
5322 nullstartblock((int)temp2);
5323 }
5324 }
5325 }
5326 trace_xfs_bmap_post_update(ip, eidx, state, _THIS_IP_);
5327 xfs_iext_insert(ip, eidx + 1, 1, &new, state);
5328 ++eidx;
5329 break;
5330 }
5331
5332 /*
5333 * Account for change in delayed indirect blocks.
5334 * Nothing to do for disk quota accounting here.
5335 */
5336 ASSERT(da_old >= da_new);
5337 if (da_old > da_new)
5338 xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false);
5339
5340 return error;
5341}
5342
5343/* 5417/*
5344 * Unmap (remove) blocks from a file. 5418 * Unmap (remove) blocks from a file.
5345 * If nexts is nonzero then the number of extents to remove is limited to 5419 * If nexts is nonzero then the number of extents to remove is limited to