|
73 | 73 | * extent search so that it overlaps in flight discard IO.
|
74 | 74 | */
|
75 | 75 |
|
| 76 | +#define XFS_DISCARD_MAX_EXAMINE (100) |
| 77 | + |
76 | 78 | struct workqueue_struct *xfs_discard_wq;
|
77 | 79 |
|
78 | 80 | static void
|
@@ -185,7 +187,7 @@ xfs_trim_gather_extents(
|
185 | 187 | struct xfs_buf *agbp;
|
186 | 188 | int error;
|
187 | 189 | int i;
|
188 |
| - int batch = 100; |
| 190 | + int batch = XFS_DISCARD_MAX_EXAMINE; |
189 | 191 |
|
190 | 192 | /*
|
191 | 193 | * Force out the log. This means any transactions that might have freed
|
@@ -565,6 +567,7 @@ xfs_trim_gather_rtextent(
|
565 | 567 | return 0;
|
566 | 568 | }
|
567 | 569 |
|
| 570 | +/* Trim extents on an !rtgroups realtime device */ |
568 | 571 | static int
|
569 | 572 | xfs_trim_rtextents(
|
570 | 573 | struct xfs_rtgroup *rtg,
|
@@ -619,6 +622,140 @@ xfs_trim_rtextents(
|
619 | 622 | return error;
|
620 | 623 | }
|
621 | 624 |
|
| 625 | +struct xfs_trim_rtgroup { |
| 626 | + /* list of rtgroup extents to free */ |
| 627 | + struct xfs_busy_extents *extents; |
| 628 | + |
| 629 | + /* minimum length that caller allows us to trim */ |
| 630 | + xfs_rtblock_t minlen_fsb; |
| 631 | + |
| 632 | + /* restart point for the rtbitmap walk */ |
| 633 | + xfs_rtxnum_t restart_rtx; |
| 634 | + |
| 635 | + /* number of extents to examine before stopping to issue discard ios */ |
| 636 | + int batch; |
| 637 | + |
| 638 | + /* number of extents queued for discard */ |
| 639 | + int queued; |
| 640 | +}; |
| 641 | + |
| 642 | +static int |
| 643 | +xfs_trim_gather_rtgroup_extent( |
| 644 | + struct xfs_rtgroup *rtg, |
| 645 | + struct xfs_trans *tp, |
| 646 | + const struct xfs_rtalloc_rec *rec, |
| 647 | + void *priv) |
| 648 | +{ |
| 649 | + struct xfs_trim_rtgroup *tr = priv; |
| 650 | + xfs_rgblock_t rgbno; |
| 651 | + xfs_extlen_t len; |
| 652 | + |
| 653 | + if (--tr->batch <= 0) { |
| 654 | + /* |
| 655 | + * If we've checked a large number of extents, update the |
| 656 | + * cursor to point at this extent so we restart the next batch |
| 657 | + * from this extent. |
| 658 | + */ |
| 659 | + tr->restart_rtx = rec->ar_startext; |
| 660 | + return -ECANCELED; |
| 661 | + } |
| 662 | + |
| 663 | + rgbno = xfs_rtx_to_rgbno(rtg, rec->ar_startext); |
| 664 | + len = xfs_rtxlen_to_extlen(rtg_mount(rtg), rec->ar_extcount); |
| 665 | + |
| 666 | + /* Ignore too small. */ |
| 667 | + if (len < tr->minlen_fsb) { |
| 668 | + trace_xfs_discard_toosmall(rtg_group(rtg), rgbno, len); |
| 669 | + return 0; |
| 670 | + } |
| 671 | + |
| 672 | + /* |
| 673 | + * If any blocks in the range are still busy, skip the discard and try |
| 674 | + * again the next time. |
| 675 | + */ |
| 676 | + if (xfs_extent_busy_search(rtg_group(rtg), rgbno, len)) { |
| 677 | + trace_xfs_discard_busy(rtg_group(rtg), rgbno, len); |
| 678 | + return 0; |
| 679 | + } |
| 680 | + |
| 681 | + xfs_extent_busy_insert_discard(rtg_group(rtg), rgbno, len, |
| 682 | + &tr->extents->extent_list); |
| 683 | + |
| 684 | + tr->queued++; |
| 685 | + tr->restart_rtx = rec->ar_startext + rec->ar_extcount; |
| 686 | + return 0; |
| 687 | +} |
| 688 | + |
| 689 | +/* Trim extents in this rtgroup using the busy extent machinery. */ |
| 690 | +static int |
| 691 | +xfs_trim_rtgroup_extents( |
| 692 | + struct xfs_rtgroup *rtg, |
| 693 | + xfs_rtxnum_t low, |
| 694 | + xfs_rtxnum_t high, |
| 695 | + xfs_daddr_t minlen) |
| 696 | +{ |
| 697 | + struct xfs_mount *mp = rtg_mount(rtg); |
| 698 | + struct xfs_trim_rtgroup tr = { |
| 699 | + .minlen_fsb = XFS_BB_TO_FSB(mp, minlen), |
| 700 | + }; |
| 701 | + struct xfs_trans *tp; |
| 702 | + int error; |
| 703 | + |
| 704 | + error = xfs_trans_alloc_empty(mp, &tp); |
| 705 | + if (error) |
| 706 | + return error; |
| 707 | + |
| 708 | + /* |
| 709 | + * Walk the free ranges between low and high. The query_range function |
| 710 | + * trims the extents returned. |
| 711 | + */ |
| 712 | + do { |
| 713 | + tr.extents = kzalloc(sizeof(*tr.extents), GFP_KERNEL); |
| 714 | + if (!tr.extents) { |
| 715 | + error = -ENOMEM; |
| 716 | + break; |
| 717 | + } |
| 718 | + |
| 719 | + tr.queued = 0; |
| 720 | + tr.batch = XFS_DISCARD_MAX_EXAMINE; |
| 721 | + tr.extents->owner = tr.extents; |
| 722 | + INIT_LIST_HEAD(&tr.extents->extent_list); |
| 723 | + |
| 724 | + xfs_rtgroup_lock(rtg, XFS_RTGLOCK_BITMAP_SHARED); |
| 725 | + error = xfs_rtalloc_query_range(rtg, tp, low, high, |
| 726 | + xfs_trim_gather_rtgroup_extent, &tr); |
| 727 | + xfs_rtgroup_unlock(rtg, XFS_RTGLOCK_BITMAP_SHARED); |
| 728 | + if (error == -ECANCELED) |
| 729 | + error = 0; |
| 730 | + if (error) { |
| 731 | + kfree(tr.extents); |
| 732 | + break; |
| 733 | + } |
| 734 | + |
| 735 | + if (!tr.queued) |
| 736 | + break; |
| 737 | + |
| 738 | + /* |
| 739 | + * We hand the extent list to the discard function here so the |
| 740 | + * discarded extents can be removed from the busy extent list. |
| 741 | + * This allows the discards to run asynchronously with |
| 742 | + * gathering the next round of extents to discard. |
| 743 | + * |
| 744 | + * However, we must ensure that we do not reference the extent |
| 745 | + * list after this function call, as it may have been freed by |
| 746 | + * the time control returns to us. |
| 747 | + */ |
| 748 | + error = xfs_discard_extents(rtg_mount(rtg), tr.extents); |
| 749 | + if (error) |
| 750 | + break; |
| 751 | + |
| 752 | + low = tr.restart_rtx; |
| 753 | + } while (!xfs_trim_should_stop() && low <= high); |
| 754 | + |
| 755 | + xfs_trans_cancel(tp); |
| 756 | + return error; |
| 757 | +} |
| 758 | + |
622 | 759 | static int
|
623 | 760 | xfs_trim_rtdev_extents(
|
624 | 761 | struct xfs_mount *mp,
|
@@ -657,7 +794,12 @@ xfs_trim_rtdev_extents(
|
657 | 794 | if (rtg_rgno(rtg) == end_rgno)
|
658 | 795 | rtg_end = min(rtg_end, end_rtx);
|
659 | 796 |
|
660 |
| - error = xfs_trim_rtextents(rtg, start_rtx, rtg_end, minlen); |
| 797 | + if (xfs_has_rtgroups(mp)) |
| 798 | + error = xfs_trim_rtgroup_extents(rtg, start_rtx, |
| 799 | + rtg_end, minlen); |
| 800 | + else |
| 801 | + error = xfs_trim_rtextents(rtg, start_rtx, rtg_end, |
| 802 | + minlen); |
661 | 803 | if (error)
|
662 | 804 | last_error = error;
|
663 | 805 |
|
|
0 commit comments