73cd9de fsck.gfs2: major duplicate reference reform

Authored and Committed by rpeterso 11 years ago
    fsck.gfs2: major duplicate reference reform
    
    This patch is a large set of changes designed to rework how pass1b
    resolves duplicate block references. There are basically two major
    changes with this patch:
    
    First, the metawalk functions were trying to attribute too much
    information to the return codes of its callback functions: (1) Was
    there an error? (2) Was the inode valid? (3) Was a duplicate block
    reference encountered? (4) Should we keep going and process more of
    its metadata? This often led to bad decisions made by metawalk:
    For example, it would stop processing metadata when it should have
    continued, thereby forgetting to mark blocks free that were no longer
    in use. This patch introduces two new variables to the metatree
    functions, *is_valid and *was_duplicate. The first one indicates
    whether the dinode was valid or whether there is good cause to
    delete it. The second indicates whether a duplicate block reference
    was encountered. With this patch, the return code indicates simply
    whether metadata processing should be skipped or not, and nothing
    more. This is especially useful in pass1. For example, if it
    encounters major corruption in a dinode, it doesn't do any good to
    mark all its blocks as duplicates and have the undo functions try
    to reverse all those decisions.
    
    The second major change with this patch has to do with the
    philosophy of how duplicate references are resolved. Before, pass1
    would flag the duplicates and pass1b would try to resolve them all,
    marking dinodes that should be deleted as "bad", and pass2 would
    delete the bad dinodes. This becomes very problematic and messy
    in pass1b, especially in cases where you have a number of duplicate
    references that are common between multiple dinodes. For example,
    suppose files A, B and C share some of the same blocks, but not
    others:
    
    A - 0x3000 0x3001 0x1233 0x1234 0x3004
    B - 0x4000 0x4001 0x4002 0x1234 0x1235
    C - 0x1231 0x1232 0x1233 0x1234 0x1235
    
    The old strategy that got us into trouble was to log the three
    duplicate blocks, delete invalid dinodes A and B, but leave the
    duplicate reference structure around for 0x1233, 0x1234 and 0x1235
    so that C would be left intact with the only references to all five
    blocks. But in cleaning up the leftover duplicate structure often
    led to bad decisions where C wouldn't have all its blocks marked
    as referenced. Often, you would end up with blocks that were marked
    as free which were still in use, and blocks that were marked as
    in use that should have been freed, and it was all due to the
    existence of those duplicate structures that were still on the list
    until pass2.
    
    The new strategy is to resolve-as-you-go. In other words, pass1b
    considers the three duplicate blocks, but when it decides that
    file A should be deleted, it removes all its references from the
    list, thereby making the decision between B and C easier: it no
    longer has to worry about block 1233, and there's only one thing
    to consider about block 0x1234 and 0x1235. When B is deleted, it
    removes all its duplicate references, so block 0x1235 is no longer
    considered to be in conflict. Once a file is deleted, all its
    duplicate reference structures are removed so as not to confuse
    other duplicates being resolved. The duplicate handler structure,
    struct dup_handler, is revised with every reference that's resolved
    so it's not working off a long list of possibles, most of
    which were already taken care of by previous actions.
    
    rhbz#902920
    
        
file modified
+0 -2
file modified
+1 -1
file modified
+150 -67
file modified
+28 -3
file modified
+62 -39
file modified
+334 -474
file modified
+0 -60
file modified
+34 -3
file modified
+2 -1