• Coly Li's avatar
    badblocks: improve badblocks_set() for multiple ranges handling · 1726c774
    Coly Li authored
    Recently I received a bug report that current badblocks code does not
    properly handle multiple ranges. For example,
            badblocks_set(bb, 32, 1, true);
            badblocks_set(bb, 34, 1, true);
            badblocks_set(bb, 36, 1, true);
            badblocks_set(bb, 32, 12, true);
    Then indeed badblocks_show() reports,
            32 3
            36 1
    But the expected bad blocks table should be,
            32 12
    Obviously only the first 2 ranges are merged and badblocks_set() returns
    and ignores the rest setting range.
    
    This behavior is improper, if the caller of badblocks_set() wants to set
    a range of blocks into bad blocks table, all of the blocks in the range
    should be handled even the previous part encountering failure.
    
    The desired way to set bad blocks range by badblocks_set() is,
    - Set as many as blocks in the setting range into bad blocks table.
    - Merge the bad blocks ranges and occupy as less as slots in the bad
      blocks table.
    - Fast.
    
    Indeed the above proposal is complicated, especially with the following
    restrictions,
    - The setting bad blocks range can be acknowledged or not acknowledged.
    - The bad blocks table size is limited.
    - Memory allocation should be avoided.
    
    The basic idea of the patch is to categorize all possible bad blocks
    range setting combinations into much less simplified and more less
    special conditions. Inside badblocks_set() there is an implicit loop
    composed by jumping between labels 're_insert' and 'update_sectors'. No
    matter how large the setting bad blocks range is, in every loop just a
    minimized range from the head is handled by a pre-defined behavior from
    one of the categorized conditions. The logic is simple and code flow is
    manageable.
    
    The different relative layout between the setting range and existing bad
    block range are checked and handled (merge, combine, overwrite, insert)
    by the helpers in previous patch. This patch is to make all the helpers
    work together with the above idea.
    
    This patch only has the algorithm improvement for badblocks_set(). There
    are following patches contain improvement for badblocks_clear() and
    badblocks_check(). But the algorithm in badblocks_set() is fundamental
    and typical, other improvement in clear and check routines are based on
    all the helpers and ideas in this patch.
    
    In order to make the change to be more clear for code review, this patch
    does not directly modify existing badblocks_set(), and just add a new
    one named _badblocks_set(). Later patch will remove current existing
    badblocks_set() code and make it as a wrapper of _badblocks_set(). So
    the new added change won't be mixed with deleted code, the code review
    can be easier.
    Signed-off-by: default avatarColy Li <colyli@suse.de>
    Cc: Dan Williams <dan.j.williams@intel.com>
    Cc: Geliang Tang <geliang.tang@suse.com>
    Cc: Hannes Reinecke <hare@suse.de>
    Cc: Jens Axboe <axboe@kernel.dk>
    Cc: NeilBrown <neilb@suse.de>
    Cc: Vishal L Verma <vishal.l.verma@intel.com>
    Cc: Wols Lists <antlists@youngman.org.uk>
    Cc: Xiao Ni <xni@redhat.com>
    Reviewed-by: default avatarXiao Ni <xni@redhat.com>
    Acked-by: default avatarGeliang Tang <geliang.tang@suse.com>
    Link: https://lore.kernel.org/r/20230811170513.2300-4-colyli@suse.deSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
    1726c774
badblocks.c 44.3 KB