]> git.hungrycats.org Git - linux/commitdiff
Btrfs: fix empty symlink after creating symlink and fsync parent dir
authorFilipe Manana <fdmanana@suse.com>
Mon, 25 Apr 2016 03:45:02 +0000 (04:45 +0100)
committerZygo Blaxell <zblaxell@thirteen.furryterror.org>
Sun, 1 May 2016 04:40:49 +0000 (00:40 -0400)
If we create a symlink, fsync its parent directory, crash/power fail and
mount the filesystem, we end up with an empty symlink, which not only is
useless it's also not allowed in linux (the man page symlink(2) is well
explicit about that).  So we just need to make sure to fully log an inode
if it's a symlink, to ensure its inline extent gets logged, ensuring the
same behaviour as ext3, ext4, xfs, reiserfs, f2fs, nilfs2, etc.

Example reproducer:

  $ mkfs.btrfs -f /dev/sdb
  $ mount /dev/sdb /mnt
  $ mkdir /mnt/testdir
  $ sync
  $ ln -s /mnt/foo /mnt/testdir/bar
  $ xfs_io -c fsync /mnt/testdir
  <power fail>
  $ mount /dev/sdb /mnt
  $ readlink /mnt/testdir/bar
  <empty string>

A test case for fstests follows soon.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
(cherry picked from commit adea6cd4f77147f21951d877462cf44ab4a4b25e)

fs/btrfs/tree-log.c

index 2ce88f6705ab9bfaae5b6b061cfc7ad6f713d853..bfa28f299ab15d79a8253216c7cc448e45f06382 100644 (file)
@@ -5152,7 +5152,7 @@ process_leaf:
                        }
 
                        ctx->log_new_dentries = false;
-                       if (type == BTRFS_FT_DIR)
+                       if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK)
                                log_mode = LOG_INODE_ALL;
                        btrfs_release_path(path);
                        ret = btrfs_log_inode(trans, root, di_inode,