• Filipe Manana's avatar
    Btrfs: fix fsync after succession of renames of different files · 6b5fc433
    Filipe Manana authored
    After a succession of rename operations of different files and fsyncing
    one of them, such that each file gets a new name that corresponds to an
    old name of another file, we can end up with a log that will cause a
    failure when attempted to replay at mount time (an EEXIST error).
    We currently have correct behaviour when such succession of renames
    involves only two files, but if there are more files involved, we end up
    not logging all the inodes that are needed, therefore resulting in a
    failure when attempting to replay the log.
    
    Example:
    
      $ mkfs.btrfs -f /dev/sdb
      $ mount /dev/sdb /mnt
    
      $ mkdir /mnt/testdir
      $ touch /mnt/testdir/fname1
      $ touch /mnt/testdir/fname2
    
      $ sync
    
      $ mv /mnt/testdir/fname1 /mnt/testdir/fname3
      $ mv /mnt/testdir/fname2 /mnt/testdir/fname4
      $ ln /mnt/testdir/fname3 /mnt/testdir/fname2
    
      $ touch /mnt/testdir/fname1
      $ xfs_io -c "fsync" /mnt/testdir/fname1
    
      <power failure>
    
      $ mount /dev/sdb /mnt
      mount: mount /dev/sdb on /mnt failed: File exists
    
    So fix this by checking all inode dependencies when logging an inode. That
    is, if one logged inode A has a new name that matches the old name of some
    other inode B, check if inode B has a new name that matches the old name
    of some other inode C, and so on. This fix is implemented not by doing any
    recursive function calls but by using an iterative method using a linked
    list that is used in a first-in-first-out fashion.
    
    A test case for fstests follows soon.
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    6b5fc433
tree-log.c 167 KB