]> git.ipfire.org Git - thirdparty/kernel/stable.git/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)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 8 Jun 2016 01:18:55 +0000 (18:18 -0700)
commit 3f9749f6e9edcf8ec569fb542efc3be35e06e84a upstream.

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>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/btrfs/tree-log.c

index 23df70e7f884e8fe4be25e42d367a04d93b0606a..a2cd421079454e46f2b75b51dc7820ccfa6b3f40 100644 (file)
@@ -5157,7 +5157,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,