Linux Btrfs filesystem development
 help / color / mirror / Atom feed
* [PATCH] Btrfs: fix wrong dentries after fsync of file that got its parent replaced
@ 2018-10-09 14:05 fdmanana
  2018-10-09 16:18 ` David Sterba
  0 siblings, 1 reply; 2+ messages in thread
From: fdmanana @ 2018-10-09 14:05 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

In a scenario like the following:

  mkdir /mnt/A               # inode 258
  mkdir /mnt/B               # inode 259
  touch /mnt/B/bar           # inode 260

  sync

  mv /mnt/B/bar /mnt/A/bar
  mv -T /mnt/A /mnt/B
  fsync /mnt/B/bar

  <power fail>

After replaying the log we end up with file bar having 2 hard links, both
with the name 'bar' and one in the directory with inode number 258 and the
other in the directory with inode number 259. Also, we end up with the
directory inode 259 still existing and with the directory inode 258 still
named as 'A', instead of 'B'. In this scenario, file 'bar' should only
have one hard link, located at directory inode 258, the directory inode
259 should not exist anymore and the name for directory inode 258 should
be 'B'.

This incorrect behaviour happens because when attempting to log the old
parents of an inode, we skip any parents that no longer exist. Fix this
by forcing a full commit if an old parent no longer exists.

A test case for fstests follows soon.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/tree-log.c | 30 +++++++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 5e83991eb064..eeeeed455dba 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -5580,9 +5580,33 @@ static int btrfs_log_all_parents(struct btrfs_trans_handle *trans,
 
 			dir_inode = btrfs_iget(fs_info->sb, &inode_key,
 					       root, NULL);
-			/* If parent inode was deleted, skip it. */
-			if (IS_ERR(dir_inode))
-				continue;
+			/*
+			 * If the parent inode was deleted, return an error to
+			 * fallback to a transaction commit. This is to prevent
+			 * getting an inode that was moved from one parent A to
+			 * a parent B, got its former parent A deleted and then
+			 * it got fsync'ed, from existing at both parents after
+			 * a log replay (and the old parent still existing).
+			 * Example:
+			 *
+			 * mkdir /mnt/A
+			 * mkdir /mnt/B
+			 * touch /mnt/B/bar
+			 * sync
+			 * mv /mnt/B/bar /mnt/A/bar
+			 * mv -T /mnt/A /mnt/B
+			 * fsync /mnt/B/bar
+			 * <power fail>
+			 *
+			 * If we ignore the old parent B which got deleted,
+			 * after a log replay we would have file bar linked
+			 * at both parents and the old parent B would still
+			 * exist.
+			 */
+			if (IS_ERR(dir_inode)) {
+				ret = PTR_ERR(dir_inode);
+				goto out;
+			}
 
 			if (ctx)
 				ctx->log_new_dentries = false;
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCH] Btrfs: fix wrong dentries after fsync of file that got its parent replaced
  2018-10-09 14:05 [PATCH] Btrfs: fix wrong dentries after fsync of file that got its parent replaced fdmanana
@ 2018-10-09 16:18 ` David Sterba
  0 siblings, 0 replies; 2+ messages in thread
From: David Sterba @ 2018-10-09 16:18 UTC (permalink / raw)
  To: fdmanana; +Cc: linux-btrfs

On Tue, Oct 09, 2018 at 03:05:29PM +0100, fdmanana@kernel.org wrote:
> From: Filipe Manana <fdmanana@suse.com>
> 
> In a scenario like the following:
> 
>   mkdir /mnt/A               # inode 258
>   mkdir /mnt/B               # inode 259
>   touch /mnt/B/bar           # inode 260
> 
>   sync
> 
>   mv /mnt/B/bar /mnt/A/bar
>   mv -T /mnt/A /mnt/B
>   fsync /mnt/B/bar
> 
>   <power fail>
> 
> After replaying the log we end up with file bar having 2 hard links, both
> with the name 'bar' and one in the directory with inode number 258 and the
> other in the directory with inode number 259. Also, we end up with the
> directory inode 259 still existing and with the directory inode 258 still
> named as 'A', instead of 'B'. In this scenario, file 'bar' should only
> have one hard link, located at directory inode 258, the directory inode
> 259 should not exist anymore and the name for directory inode 258 should
> be 'B'.
> 
> This incorrect behaviour happens because when attempting to log the old
> parents of an inode, we skip any parents that no longer exist. Fix this
> by forcing a full commit if an old parent no longer exists.
> 
> A test case for fstests follows soon.
> 
> Signed-off-by: Filipe Manana <fdmanana@suse.com>

Thanks, queued for 4.20 with CC: stable 4.4+ .

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-10-09 16:18 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-10-09 14:05 [PATCH] Btrfs: fix wrong dentries after fsync of file that got its parent replaced fdmanana
2018-10-09 16:18 ` David Sterba

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox