• Boris Burkov's avatar
    btrfs: dynamic block_group reclaim threshold · f5ff64cc
    Boris Burkov authored
    We can currently recover allocated block_groups by:
    
    - explicitly starting balance operations
    - "auto reclaim" via bg_reclaim_threshold
    
    The latter works by checking against a fixed threshold on frees. If we
    pass from above the threshold to below, relocation triggers and the
    block group will get reclaimed by the cleaner thread (assuming it is
    still eligible)
    
    Picking a threshold is challenging. Too high, and you end up trying to
    reclaim very full block_groups which is quite costly, and you don't do
    reclaim on block_groups that don't get quite THAT full, but could still
    be quite fragmented and stranding a lot of space. Too low, and you
    similarly miss out on reclaim even if you badly need it to avoid running
    out of unallocated space, if you have heavily fragmented block groups
    living above the threshold.
    
    No matter the threshold, it suffers from a workload that happens to
    bounce around that threshold, which can introduce arbitrary amounts of
    reclaim waste.
    
    To improve this situation, introduce a dynamic threshold. The basic idea
    behind this threshold is that it should be very lax when there is plenty
    of unallocated space, and increasingly aggressive as we approach zero
    unallocated space. To that end, it sets a target for unallocated space
    (10 chunks) and then linearly increases the threshold as the amount of
    space short of the target we are increases. The formula is:
    (target - unalloc) / target
    
    I tested this by running it on three interesting workloads:
    
      1. bounce allocations around X% full.
      2. fill up all the way and introduce full fragmentation.
      3. write in a fragmented way until the filesystem is just about full.
    
    1. and 2. attack the weaknesses of a fixed threshold; fixed either works
    perfectly or fully falls apart, depending on the threshold. Dynamic
    always handles these cases well.
    
    3. attacks dynamic by checking whether it is too zealous to reclaim in
    conditions with low unallocated and low unused. It tends to claw back
    1GiB of unallocated fairly aggressively, but not much more. Early
    versions of dynamic threshold struggled on this test.
    
    Additional work could be done to intelligently ratchet up the urgency of
    reclaim in very low unallocated conditions. Existing mechanisms are
    already useless in that case anyway.
    Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarBoris Burkov <boris@bur.io>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    f5ff64cc
space-info.c 62.8 KB