aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:21 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2016-10-03 12:11:21 -0400
commit3172725814f9a689d6e8b3c7979b66403abf5dae (patch)
tree6372a73150404f3390969f48433c1d978c580d4a
parentf997ee2137175f5b2bd7ced52acf1ca51f04f420 (diff)
xfs: adjust refcount of an extent of blocks in refcount btree
Provide functions to adjust the reference counts for an extent of physical blocks stored in the refcount btree. Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/libxfs/xfs_refcount.c814
-rw-r--r--fs/xfs/xfs_error.h4
2 files changed, 817 insertions, 1 deletions
diff --git a/fs/xfs/libxfs/xfs_refcount.c b/fs/xfs/libxfs/xfs_refcount.c
index de1340652933..f522fe130a16 100644
--- a/fs/xfs/libxfs/xfs_refcount.c
+++ b/fs/xfs/libxfs/xfs_refcount.c
@@ -37,6 +37,12 @@
37#include "xfs_bit.h" 37#include "xfs_bit.h"
38#include "xfs_refcount.h" 38#include "xfs_refcount.h"
39 39
40/* Allowable refcount adjustment amounts. */
41enum xfs_refc_adjust_op {
42 XFS_REFCOUNT_ADJUST_INCREASE = 1,
43 XFS_REFCOUNT_ADJUST_DECREASE = -1,
44};
45
40/* 46/*
41 * Look up the first record less than or equal to [bno, len] in the btree 47 * Look up the first record less than or equal to [bno, len] in the btree
42 * given by cur. 48 * given by cur.
@@ -175,3 +181,811 @@ out_error:
175 cur->bc_private.a.agno, error, _RET_IP_); 181 cur->bc_private.a.agno, error, _RET_IP_);
176 return error; 182 return error;
177} 183}
184
185/*
186 * Adjusting the Reference Count
187 *
188 * As stated elsewhere, the reference count btree (refcbt) stores
189 * >1 reference counts for extents of physical blocks. In this
190 * operation, we're either raising or lowering the reference count of
191 * some subrange stored in the tree:
192 *
193 * <------ adjustment range ------>
194 * ----+ +---+-----+ +--+--------+---------
195 * 2 | | 3 | 4 | |17| 55 | 10
196 * ----+ +---+-----+ +--+--------+---------
197 * X axis is physical blocks number;
198 * reference counts are the numbers inside the rectangles
199 *
200 * The first thing we need to do is to ensure that there are no
201 * refcount extents crossing either boundary of the range to be
202 * adjusted. For any extent that does cross a boundary, split it into
203 * two extents so that we can increment the refcount of one of the
204 * pieces later:
205 *
206 * <------ adjustment range ------>
207 * ----+ +---+-----+ +--+--------+----+----
208 * 2 | | 3 | 2 | |17| 55 | 10 | 10
209 * ----+ +---+-----+ +--+--------+----+----
210 *
211 * For this next step, let's assume that all the physical blocks in
212 * the adjustment range are mapped to a file and are therefore in use
213 * at least once. Therefore, we can infer that any gap in the
214 * refcount tree within the adjustment range represents a physical
215 * extent with refcount == 1:
216 *
217 * <------ adjustment range ------>
218 * ----+---+---+-----+-+--+--------+----+----
219 * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10
220 * ----+---+---+-----+-+--+--------+----+----
221 * ^
222 *
223 * For each extent that falls within the interval range, figure out
224 * which extent is to the left or the right of that extent. Now we
225 * have a left, current, and right extent. If the new reference count
226 * of the center extent enables us to merge left, center, and right
227 * into one record covering all three, do so. If the center extent is
228 * at the left end of the range, abuts the left extent, and its new
229 * reference count matches the left extent's record, then merge them.
230 * If the center extent is at the right end of the range, abuts the
231 * right extent, and the reference counts match, merge those. In the
232 * example, we can left merge (assuming an increment operation):
233 *
234 * <------ adjustment range ------>
235 * --------+---+-----+-+--+--------+----+----
236 * 2 | 3 | 2 |1|17| 55 | 10 | 10
237 * --------+---+-----+-+--+--------+----+----
238 * ^
239 *
240 * For all other extents within the range, adjust the reference count
241 * or delete it if the refcount falls below 2. If we were
242 * incrementing, the end result looks like this:
243 *
244 * <------ adjustment range ------>
245 * --------+---+-----+-+--+--------+----+----
246 * 2 | 4 | 3 |2|18| 56 | 11 | 10
247 * --------+---+-----+-+--+--------+----+----
248 *
249 * The result of a decrement operation looks as such:
250 *
251 * <------ adjustment range ------>
252 * ----+ +---+ +--+--------+----+----
253 * 2 | | 2 | |16| 54 | 9 | 10
254 * ----+ +---+ +--+--------+----+----
255 * DDDD 111111DD
256 *
257 * The blocks marked "D" are freed; the blocks marked "1" are only
258 * referenced once and therefore the record is removed from the
259 * refcount btree.
260 */
261
262/* Next block after this extent. */
263static inline xfs_agblock_t
264xfs_refc_next(
265 struct xfs_refcount_irec *rc)
266{
267 return rc->rc_startblock + rc->rc_blockcount;
268}
269
270/*
271 * Split a refcount extent that crosses agbno.
272 */
273STATIC int
274xfs_refcount_split_extent(
275 struct xfs_btree_cur *cur,
276 xfs_agblock_t agbno,
277 bool *shape_changed)
278{
279 struct xfs_refcount_irec rcext, tmp;
280 int found_rec;
281 int error;
282
283 *shape_changed = false;
284 error = xfs_refcount_lookup_le(cur, agbno, &found_rec);
285 if (error)
286 goto out_error;
287 if (!found_rec)
288 return 0;
289
290 error = xfs_refcount_get_rec(cur, &rcext, &found_rec);
291 if (error)
292 goto out_error;
293 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
294 if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno)
295 return 0;
296
297 *shape_changed = true;
298 trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_private.a.agno,
299 &rcext, agbno);
300
301 /* Establish the right extent. */
302 tmp = rcext;
303 tmp.rc_startblock = agbno;
304 tmp.rc_blockcount -= (agbno - rcext.rc_startblock);
305 error = xfs_refcount_update(cur, &tmp);
306 if (error)
307 goto out_error;
308
309 /* Insert the left extent. */
310 tmp = rcext;
311 tmp.rc_blockcount = agbno - rcext.rc_startblock;
312 error = xfs_refcount_insert(cur, &tmp, &found_rec);
313 if (error)
314 goto out_error;
315 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
316 return error;
317
318out_error:
319 trace_xfs_refcount_split_extent_error(cur->bc_mp,
320 cur->bc_private.a.agno, error, _RET_IP_);
321 return error;
322}
323
324/*
325 * Merge the left, center, and right extents.
326 */
327STATIC int
328xfs_refcount_merge_center_extents(
329 struct xfs_btree_cur *cur,
330 struct xfs_refcount_irec *left,
331 struct xfs_refcount_irec *center,
332 struct xfs_refcount_irec *right,
333 unsigned long long extlen,
334 xfs_agblock_t *agbno,
335 xfs_extlen_t *aglen)
336{
337 int error;
338 int found_rec;
339
340 trace_xfs_refcount_merge_center_extents(cur->bc_mp,
341 cur->bc_private.a.agno, left, center, right);
342
343 /*
344 * Make sure the center and right extents are not in the btree.
345 * If the center extent was synthesized, the first delete call
346 * removes the right extent and we skip the second deletion.
347 * If center and right were in the btree, then the first delete
348 * call removes the center and the second one removes the right
349 * extent.
350 */
351 error = xfs_refcount_lookup_ge(cur, center->rc_startblock,
352 &found_rec);
353 if (error)
354 goto out_error;
355 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
356
357 error = xfs_refcount_delete(cur, &found_rec);
358 if (error)
359 goto out_error;
360 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
361
362 if (center->rc_refcount > 1) {
363 error = xfs_refcount_delete(cur, &found_rec);
364 if (error)
365 goto out_error;
366 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
367 out_error);
368 }
369
370 /* Enlarge the left extent. */
371 error = xfs_refcount_lookup_le(cur, left->rc_startblock,
372 &found_rec);
373 if (error)
374 goto out_error;
375 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
376
377 left->rc_blockcount = extlen;
378 error = xfs_refcount_update(cur, left);
379 if (error)
380 goto out_error;
381
382 *aglen = 0;
383 return error;
384
385out_error:
386 trace_xfs_refcount_merge_center_extents_error(cur->bc_mp,
387 cur->bc_private.a.agno, error, _RET_IP_);
388 return error;
389}
390
391/*
392 * Merge with the left extent.
393 */
394STATIC int
395xfs_refcount_merge_left_extent(
396 struct xfs_btree_cur *cur,
397 struct xfs_refcount_irec *left,
398 struct xfs_refcount_irec *cleft,
399 xfs_agblock_t *agbno,
400 xfs_extlen_t *aglen)
401{
402 int error;
403 int found_rec;
404
405 trace_xfs_refcount_merge_left_extent(cur->bc_mp,
406 cur->bc_private.a.agno, left, cleft);
407
408 /* If the extent at agbno (cleft) wasn't synthesized, remove it. */
409 if (cleft->rc_refcount > 1) {
410 error = xfs_refcount_lookup_le(cur, cleft->rc_startblock,
411 &found_rec);
412 if (error)
413 goto out_error;
414 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
415 out_error);
416
417 error = xfs_refcount_delete(cur, &found_rec);
418 if (error)
419 goto out_error;
420 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
421 out_error);
422 }
423
424 /* Enlarge the left extent. */
425 error = xfs_refcount_lookup_le(cur, left->rc_startblock,
426 &found_rec);
427 if (error)
428 goto out_error;
429 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
430
431 left->rc_blockcount += cleft->rc_blockcount;
432 error = xfs_refcount_update(cur, left);
433 if (error)
434 goto out_error;
435
436 *agbno += cleft->rc_blockcount;
437 *aglen -= cleft->rc_blockcount;
438 return error;
439
440out_error:
441 trace_xfs_refcount_merge_left_extent_error(cur->bc_mp,
442 cur->bc_private.a.agno, error, _RET_IP_);
443 return error;
444}
445
446/*
447 * Merge with the right extent.
448 */
449STATIC int
450xfs_refcount_merge_right_extent(
451 struct xfs_btree_cur *cur,
452 struct xfs_refcount_irec *right,
453 struct xfs_refcount_irec *cright,
454 xfs_agblock_t *agbno,
455 xfs_extlen_t *aglen)
456{
457 int error;
458 int found_rec;
459
460 trace_xfs_refcount_merge_right_extent(cur->bc_mp,
461 cur->bc_private.a.agno, cright, right);
462
463 /*
464 * If the extent ending at agbno+aglen (cright) wasn't synthesized,
465 * remove it.
466 */
467 if (cright->rc_refcount > 1) {
468 error = xfs_refcount_lookup_le(cur, cright->rc_startblock,
469 &found_rec);
470 if (error)
471 goto out_error;
472 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
473 out_error);
474
475 error = xfs_refcount_delete(cur, &found_rec);
476 if (error)
477 goto out_error;
478 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
479 out_error);
480 }
481
482 /* Enlarge the right extent. */
483 error = xfs_refcount_lookup_le(cur, right->rc_startblock,
484 &found_rec);
485 if (error)
486 goto out_error;
487 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
488
489 right->rc_startblock -= cright->rc_blockcount;
490 right->rc_blockcount += cright->rc_blockcount;
491 error = xfs_refcount_update(cur, right);
492 if (error)
493 goto out_error;
494
495 *aglen -= cright->rc_blockcount;
496 return error;
497
498out_error:
499 trace_xfs_refcount_merge_right_extent_error(cur->bc_mp,
500 cur->bc_private.a.agno, error, _RET_IP_);
501 return error;
502}
503
504/*
505 * Find the left extent and the one after it (cleft). This function assumes
506 * that we've already split any extent crossing agbno.
507 */
508STATIC int
509xfs_refcount_find_left_extents(
510 struct xfs_btree_cur *cur,
511 struct xfs_refcount_irec *left,
512 struct xfs_refcount_irec *cleft,
513 xfs_agblock_t agbno,
514 xfs_extlen_t aglen)
515{
516 struct xfs_refcount_irec tmp;
517 int error;
518 int found_rec;
519
520 left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK;
521 error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec);
522 if (error)
523 goto out_error;
524 if (!found_rec)
525 return 0;
526
527 error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
528 if (error)
529 goto out_error;
530 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
531
532 if (xfs_refc_next(&tmp) != agbno)
533 return 0;
534 /* We have a left extent; retrieve (or invent) the next right one */
535 *left = tmp;
536
537 error = xfs_btree_increment(cur, 0, &found_rec);
538 if (error)
539 goto out_error;
540 if (found_rec) {
541 error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
542 if (error)
543 goto out_error;
544 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
545 out_error);
546
547 /* if tmp starts at the end of our range, just use that */
548 if (tmp.rc_startblock == agbno)
549 *cleft = tmp;
550 else {
551 /*
552 * There's a gap in the refcntbt at the start of the
553 * range we're interested in (refcount == 1) so
554 * synthesize the implied extent and pass it back.
555 * We assume here that the agbno/aglen range was
556 * passed in from a data fork extent mapping and
557 * therefore is allocated to exactly one owner.
558 */
559 cleft->rc_startblock = agbno;
560 cleft->rc_blockcount = min(aglen,
561 tmp.rc_startblock - agbno);
562 cleft->rc_refcount = 1;
563 }
564 } else {
565 /*
566 * No extents, so pretend that there's one covering the whole
567 * range.
568 */
569 cleft->rc_startblock = agbno;
570 cleft->rc_blockcount = aglen;
571 cleft->rc_refcount = 1;
572 }
573 trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno,
574 left, cleft, agbno);
575 return error;
576
577out_error:
578 trace_xfs_refcount_find_left_extent_error(cur->bc_mp,
579 cur->bc_private.a.agno, error, _RET_IP_);
580 return error;
581}
582
583/*
584 * Find the right extent and the one before it (cright). This function
585 * assumes that we've already split any extents crossing agbno + aglen.
586 */
587STATIC int
588xfs_refcount_find_right_extents(
589 struct xfs_btree_cur *cur,
590 struct xfs_refcount_irec *right,
591 struct xfs_refcount_irec *cright,
592 xfs_agblock_t agbno,
593 xfs_extlen_t aglen)
594{
595 struct xfs_refcount_irec tmp;
596 int error;
597 int found_rec;
598
599 right->rc_startblock = cright->rc_startblock = NULLAGBLOCK;
600 error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec);
601 if (error)
602 goto out_error;
603 if (!found_rec)
604 return 0;
605
606 error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
607 if (error)
608 goto out_error;
609 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error);
610
611 if (tmp.rc_startblock != agbno + aglen)
612 return 0;
613 /* We have a right extent; retrieve (or invent) the next left one */
614 *right = tmp;
615
616 error = xfs_btree_decrement(cur, 0, &found_rec);
617 if (error)
618 goto out_error;
619 if (found_rec) {
620 error = xfs_refcount_get_rec(cur, &tmp, &found_rec);
621 if (error)
622 goto out_error;
623 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1,
624 out_error);
625
626 /* if tmp ends at the end of our range, just use that */
627 if (xfs_refc_next(&tmp) == agbno + aglen)
628 *cright = tmp;
629 else {
630 /*
631 * There's a gap in the refcntbt at the end of the
632 * range we're interested in (refcount == 1) so
633 * create the implied extent and pass it back.
634 * We assume here that the agbno/aglen range was
635 * passed in from a data fork extent mapping and
636 * therefore is allocated to exactly one owner.
637 */
638 cright->rc_startblock = max(agbno, xfs_refc_next(&tmp));
639 cright->rc_blockcount = right->rc_startblock -
640 cright->rc_startblock;
641 cright->rc_refcount = 1;
642 }
643 } else {
644 /*
645 * No extents, so pretend that there's one covering the whole
646 * range.
647 */
648 cright->rc_startblock = agbno;
649 cright->rc_blockcount = aglen;
650 cright->rc_refcount = 1;
651 }
652 trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno,
653 cright, right, agbno + aglen);
654 return error;
655
656out_error:
657 trace_xfs_refcount_find_right_extent_error(cur->bc_mp,
658 cur->bc_private.a.agno, error, _RET_IP_);
659 return error;
660}
661
662/* Is this extent valid? */
663static inline bool
664xfs_refc_valid(
665 struct xfs_refcount_irec *rc)
666{
667 return rc->rc_startblock != NULLAGBLOCK;
668}
669
670/*
671 * Try to merge with any extents on the boundaries of the adjustment range.
672 */
673STATIC int
674xfs_refcount_merge_extents(
675 struct xfs_btree_cur *cur,
676 xfs_agblock_t *agbno,
677 xfs_extlen_t *aglen,
678 enum xfs_refc_adjust_op adjust,
679 bool *shape_changed)
680{
681 struct xfs_refcount_irec left = {0}, cleft = {0};
682 struct xfs_refcount_irec cright = {0}, right = {0};
683 int error;
684 unsigned long long ulen;
685 bool cequal;
686
687 *shape_changed = false;
688 /*
689 * Find the extent just below agbno [left], just above agbno [cleft],
690 * just below (agbno + aglen) [cright], and just above (agbno + aglen)
691 * [right].
692 */
693 error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno,
694 *aglen);
695 if (error)
696 return error;
697 error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno,
698 *aglen);
699 if (error)
700 return error;
701
702 /* No left or right extent to merge; exit. */
703 if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right))
704 return 0;
705
706 cequal = (cleft.rc_startblock == cright.rc_startblock) &&
707 (cleft.rc_blockcount == cright.rc_blockcount);
708
709 /* Try to merge left, cleft, and right. cleft must == cright. */
710 ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount +
711 right.rc_blockcount;
712 if (xfs_refc_valid(&left) && xfs_refc_valid(&right) &&
713 xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal &&
714 left.rc_refcount == cleft.rc_refcount + adjust &&
715 right.rc_refcount == cleft.rc_refcount + adjust &&
716 ulen < MAXREFCEXTLEN) {
717 *shape_changed = true;
718 return xfs_refcount_merge_center_extents(cur, &left, &cleft,
719 &right, ulen, agbno, aglen);
720 }
721
722 /* Try to merge left and cleft. */
723 ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount;
724 if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) &&
725 left.rc_refcount == cleft.rc_refcount + adjust &&
726 ulen < MAXREFCEXTLEN) {
727 *shape_changed = true;
728 error = xfs_refcount_merge_left_extent(cur, &left, &cleft,
729 agbno, aglen);
730 if (error)
731 return error;
732
733 /*
734 * If we just merged left + cleft and cleft == cright,
735 * we no longer have a cright to merge with right. We're done.
736 */
737 if (cequal)
738 return 0;
739 }
740
741 /* Try to merge cright and right. */
742 ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount;
743 if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) &&
744 right.rc_refcount == cright.rc_refcount + adjust &&
745 ulen < MAXREFCEXTLEN) {
746 *shape_changed = true;
747 return xfs_refcount_merge_right_extent(cur, &right, &cright,
748 agbno, aglen);
749 }
750
751 return error;
752}
753
754/*
755 * While we're adjusting the refcounts records of an extent, we have
756 * to keep an eye on the number of extents we're dirtying -- run too
757 * many in a single transaction and we'll exceed the transaction's
758 * reservation and crash the fs. Each record adds 12 bytes to the
759 * log (plus any key updates) so we'll conservatively assume 24 bytes
760 * per record. We must also leave space for btree splits on both ends
761 * of the range and space for the CUD and a new CUI.
762 *
763 * XXX: This is a pretty hand-wavy estimate. The penalty for guessing
764 * true incorrectly is a shutdown FS; the penalty for guessing false
765 * incorrectly is more transaction rolls than might be necessary.
766 * Be conservative here.
767 */
768static bool
769xfs_refcount_still_have_space(
770 struct xfs_btree_cur *cur)
771{
772 unsigned long overhead;
773
774 overhead = cur->bc_private.a.priv.refc.shape_changes *
775 xfs_allocfree_log_count(cur->bc_mp, 1);
776 overhead *= cur->bc_mp->m_sb.sb_blocksize;
777
778 /*
779 * Only allow 2 refcount extent updates per transaction if the
780 * refcount continue update "error" has been injected.
781 */
782 if (cur->bc_private.a.priv.refc.nr_ops > 2 &&
783 XFS_TEST_ERROR(false, cur->bc_mp,
784 XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE,
785 XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE))
786 return false;
787
788 if (cur->bc_private.a.priv.refc.nr_ops == 0)
789 return true;
790 else if (overhead > cur->bc_tp->t_log_res)
791 return false;
792 return cur->bc_tp->t_log_res - overhead >
793 cur->bc_private.a.priv.refc.nr_ops * 32;
794}
795
796/*
797 * Adjust the refcounts of middle extents. At this point we should have
798 * split extents that crossed the adjustment range; merged with adjacent
799 * extents; and updated agbno/aglen to reflect the merges. Therefore,
800 * all we have to do is update the extents inside [agbno, agbno + aglen].
801 */
802STATIC int
803xfs_refcount_adjust_extents(
804 struct xfs_btree_cur *cur,
805 xfs_agblock_t *agbno,
806 xfs_extlen_t *aglen,
807 enum xfs_refc_adjust_op adj,
808 struct xfs_defer_ops *dfops,
809 struct xfs_owner_info *oinfo)
810{
811 struct xfs_refcount_irec ext, tmp;
812 int error;
813 int found_rec, found_tmp;
814 xfs_fsblock_t fsbno;
815
816 /* Merging did all the work already. */
817 if (*aglen == 0)
818 return 0;
819
820 error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec);
821 if (error)
822 goto out_error;
823
824 while (*aglen > 0 && xfs_refcount_still_have_space(cur)) {
825 error = xfs_refcount_get_rec(cur, &ext, &found_rec);
826 if (error)
827 goto out_error;
828 if (!found_rec) {
829 ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks;
830 ext.rc_blockcount = 0;
831 ext.rc_refcount = 0;
832 }
833
834 /*
835 * Deal with a hole in the refcount tree; if a file maps to
836 * these blocks and there's no refcountbt record, pretend that
837 * there is one with refcount == 1.
838 */
839 if (ext.rc_startblock != *agbno) {
840 tmp.rc_startblock = *agbno;
841 tmp.rc_blockcount = min(*aglen,
842 ext.rc_startblock - *agbno);
843 tmp.rc_refcount = 1 + adj;
844 trace_xfs_refcount_modify_extent(cur->bc_mp,
845 cur->bc_private.a.agno, &tmp);
846
847 /*
848 * Either cover the hole (increment) or
849 * delete the range (decrement).
850 */
851 if (tmp.rc_refcount) {
852 error = xfs_refcount_insert(cur, &tmp,
853 &found_tmp);
854 if (error)
855 goto out_error;
856 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
857 found_tmp == 1, out_error);
858 cur->bc_private.a.priv.refc.nr_ops++;
859 } else {
860 fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
861 cur->bc_private.a.agno,
862 tmp.rc_startblock);
863 xfs_bmap_add_free(cur->bc_mp, dfops, fsbno,
864 tmp.rc_blockcount, oinfo);
865 }
866
867 (*agbno) += tmp.rc_blockcount;
868 (*aglen) -= tmp.rc_blockcount;
869
870 error = xfs_refcount_lookup_ge(cur, *agbno,
871 &found_rec);
872 if (error)
873 goto out_error;
874 }
875
876 /* Stop if there's nothing left to modify */
877 if (*aglen == 0 || !xfs_refcount_still_have_space(cur))
878 break;
879
880 /*
881 * Adjust the reference count and either update the tree
882 * (incr) or free the blocks (decr).
883 */
884 if (ext.rc_refcount == MAXREFCOUNT)
885 goto skip;
886 ext.rc_refcount += adj;
887 trace_xfs_refcount_modify_extent(cur->bc_mp,
888 cur->bc_private.a.agno, &ext);
889 if (ext.rc_refcount > 1) {
890 error = xfs_refcount_update(cur, &ext);
891 if (error)
892 goto out_error;
893 cur->bc_private.a.priv.refc.nr_ops++;
894 } else if (ext.rc_refcount == 1) {
895 error = xfs_refcount_delete(cur, &found_rec);
896 if (error)
897 goto out_error;
898 XFS_WANT_CORRUPTED_GOTO(cur->bc_mp,
899 found_rec == 1, out_error);
900 cur->bc_private.a.priv.refc.nr_ops++;
901 goto advloop;
902 } else {
903 fsbno = XFS_AGB_TO_FSB(cur->bc_mp,
904 cur->bc_private.a.agno,
905 ext.rc_startblock);
906 xfs_bmap_add_free(cur->bc_mp, dfops, fsbno,
907 ext.rc_blockcount, oinfo);
908 }
909
910skip:
911 error = xfs_btree_increment(cur, 0, &found_rec);
912 if (error)
913 goto out_error;
914
915advloop:
916 (*agbno) += ext.rc_blockcount;
917 (*aglen) -= ext.rc_blockcount;
918 }
919
920 return error;
921out_error:
922 trace_xfs_refcount_modify_extent_error(cur->bc_mp,
923 cur->bc_private.a.agno, error, _RET_IP_);
924 return error;
925}
926
927/* Adjust the reference count of a range of AG blocks. */
928STATIC int
929xfs_refcount_adjust(
930 struct xfs_btree_cur *cur,
931 xfs_agblock_t agbno,
932 xfs_extlen_t aglen,
933 xfs_agblock_t *new_agbno,
934 xfs_extlen_t *new_aglen,
935 enum xfs_refc_adjust_op adj,
936 struct xfs_defer_ops *dfops,
937 struct xfs_owner_info *oinfo)
938{
939 bool shape_changed;
940 int shape_changes = 0;
941 int error;
942
943 *new_agbno = agbno;
944 *new_aglen = aglen;
945 if (adj == XFS_REFCOUNT_ADJUST_INCREASE)
946 trace_xfs_refcount_increase(cur->bc_mp, cur->bc_private.a.agno,
947 agbno, aglen);
948 else
949 trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_private.a.agno,
950 agbno, aglen);
951
952 /*
953 * Ensure that no rcextents cross the boundary of the adjustment range.
954 */
955 error = xfs_refcount_split_extent(cur, agbno, &shape_changed);
956 if (error)
957 goto out_error;
958 if (shape_changed)
959 shape_changes++;
960
961 error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed);
962 if (error)
963 goto out_error;
964 if (shape_changed)
965 shape_changes++;
966
967 /*
968 * Try to merge with the left or right extents of the range.
969 */
970 error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj,
971 &shape_changed);
972 if (error)
973 goto out_error;
974 if (shape_changed)
975 shape_changes++;
976 if (shape_changes)
977 cur->bc_private.a.priv.refc.shape_changes++;
978
979 /* Now that we've taken care of the ends, adjust the middle extents */
980 error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen,
981 adj, dfops, oinfo);
982 if (error)
983 goto out_error;
984
985 return 0;
986
987out_error:
988 trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_private.a.agno,
989 error, _RET_IP_);
990 return error;
991}
diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h
index 3d224702fbc0..d9675c646572 100644
--- a/fs/xfs/xfs_error.h
+++ b/fs/xfs/xfs_error.h
@@ -92,7 +92,8 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
92#define XFS_ERRTAG_BMAPIFORMAT 21 92#define XFS_ERRTAG_BMAPIFORMAT 21
93#define XFS_ERRTAG_FREE_EXTENT 22 93#define XFS_ERRTAG_FREE_EXTENT 22
94#define XFS_ERRTAG_RMAP_FINISH_ONE 23 94#define XFS_ERRTAG_RMAP_FINISH_ONE 23
95#define XFS_ERRTAG_MAX 24 95#define XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE 24
96#define XFS_ERRTAG_MAX 25
96 97
97/* 98/*
98 * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. 99 * Random factors for above tags, 1 means always, 2 means 1/2 time, etc.
@@ -121,6 +122,7 @@ extern void xfs_verifier_error(struct xfs_buf *bp);
121#define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT 122#define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT
122#define XFS_RANDOM_FREE_EXTENT 1 123#define XFS_RANDOM_FREE_EXTENT 1
123#define XFS_RANDOM_RMAP_FINISH_ONE 1 124#define XFS_RANDOM_RMAP_FINISH_ONE 1
125#define XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE 1
124 126
125#ifdef DEBUG 127#ifdef DEBUG
126extern int xfs_error_test_active; 128extern int xfs_error_test_active;