--- /dev/null
+From d0e64a981fd841cb0f28fcd6afcac55e6f1e6994 Mon Sep 17 00:00:00 2001
+From: Filipe Manana <fdmanana@suse.com>
+Date: Thu, 21 Apr 2022 10:56:39 +0100
+Subject: btrfs: always log symlinks in full mode
+
+From: Filipe Manana <fdmanana@suse.com>
+
+commit d0e64a981fd841cb0f28fcd6afcac55e6f1e6994 upstream.
+
+On Linux, empty symlinks are invalid, and attempting to create one with
+the system call symlink(2) results in an -ENOENT error and this is
+explicitly documented in the man page.
+
+If we rename a symlink that was created in the current transaction and its
+parent directory was logged before, we actually end up logging the symlink
+without logging its content, which is stored in an inline extent. That
+means that after a power failure we can end up with an empty symlink,
+having no content and an i_size of 0 bytes.
+
+It can be easily reproduced like this:
+
+ $ mkfs.btrfs -f /dev/sdc
+ $ mount /dev/sdc /mnt
+
+ $ mkdir /mnt/testdir
+ $ sync
+
+ # Create a file inside the directory and fsync the directory.
+ $ touch /mnt/testdir/foo
+ $ xfs_io -c "fsync" /mnt/testdir
+
+ # Create a symlink inside the directory and then rename the symlink.
+ $ ln -s /mnt/testdir/foo /mnt/testdir/bar
+ $ mv /mnt/testdir/bar /mnt/testdir/baz
+
+ # Now fsync again the directory, this persist the log tree.
+ $ xfs_io -c "fsync" /mnt/testdir
+
+ <power failure>
+
+ $ mount /dev/sdc /mnt
+ $ stat -c %s /mnt/testdir/baz
+ 0
+ $ readlink /mnt/testdir/baz
+ $
+
+Fix this by always logging symlinks in full mode (LOG_INODE_ALL), so that
+their content is also logged.
+
+A test case for fstests will follow.
+
+CC: stable@vger.kernel.org # 4.9+
+Signed-off-by: Filipe Manana <fdmanana@suse.com>
+Signed-off-by: David Sterba <dsterba@suse.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/btrfs/tree-log.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+--- a/fs/btrfs/tree-log.c
++++ b/fs/btrfs/tree-log.c
+@@ -5295,6 +5295,18 @@ static int btrfs_log_inode(struct btrfs_
+ }
+
+ /*
++ * For symlinks, we must always log their content, which is stored in an
++ * inline extent, otherwise we could end up with an empty symlink after
++ * log replay, which is invalid on linux (symlink(2) returns -ENOENT if
++ * one attempts to create an empty symlink).
++ * We don't need to worry about flushing delalloc, because when we create
++ * the inline extent when the symlink is created (we never have delalloc
++ * for symlinks).
++ */
++ if (S_ISLNK(inode->vfs_inode.i_mode))
++ inode_only = LOG_INODE_ALL;
++
++ /*
+ * a brute force approach to making sure we get the most uptodate
+ * copies of everything.
+ */
+@@ -5707,7 +5719,7 @@ process_leaf:
+ }
+
+ ctx->log_new_dentries = false;
+- if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK)
++ if (type == BTRFS_FT_DIR)
+ log_mode = LOG_INODE_ALL;
+ ret = btrfs_log_inode(trans, root, BTRFS_I(di_inode),
+ log_mode, 0, LLONG_MAX, ctx);