Skip to contentSkip to conversation

FAILED: patch "[PATCH] btrfs: Take trans lock before access running trans in" failed to apply to 4.14-stable tree

PATCH In review [email protected] 2 participants 3 messages May 6, 2018 – May 17, 2018

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 4.14-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

Quoted 1 line

From 998ac6d21cfd6efd58f5edf420bae8839dda9f2a Mon Sep 17 00:00:00 2001

From: ethanwu <[email protected]>
Date: Sun, 29 Apr 2018 15:59:42 +0800
Subject: [PATCH] btrfs: Take trans lock before access running trans in
check_delayed_ref

In preivous patch:
Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist We avoid starting btrfs transaction and get this information from fs_info->running_transaction directly.

When accessing running_transaction in check_delayed_ref, there's a chance that current transaction will be freed by commit transaction after the NULL pointer check of running_transaction is passed.

After looking all the other places using fs_info->running_transaction, they are either protected by trans_lock or holding the transactions.

Fix this by using trans_lock and increasing the use_count.

Fixes e4c3b2dcd144 ("Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist")
fs/btrfs/extent-tree.c +7 -0
index f99102063366..3871658b6ab1 100644
@@ -3142,7 +3142,11 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 	struct rb_node *node;
 	int ret = 0;
 
+	spin_lock(&root->fs_info->trans_lock);
 	cur_trans = root->fs_info->running_transaction;
+	if (cur_trans)
+		refcount_inc(&cur_trans->use_count);
+	spin_unlock(&root->fs_info->trans_lock);
 	if (!cur_trans)
 		return 0;
 
@@ -3151,6 +3155,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 	head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
 	if (!head) {
 		spin_unlock(&delayed_refs->lock);
+		btrfs_put_transaction(cur_trans);
 		return 0;
 	}
 
@@ -3167,6 +3172,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 		mutex_lock(&head->mutex);
 		mutex_unlock(&head->mutex);
 		btrfs_put_delayed_ref_head(head);
+		btrfs_put_transaction(cur_trans);
 		return -EAGAIN;
 	}
 	spin_unlock(&delayed_refs->lock);
@@ -3199,6 +3205,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 	}
 	spin_unlock(&head->lock);
 	mutex_unlock(&head->mutex);
+	btrfs_put_transaction(cur_trans);
 	return ret;
 }
 
#1 lore raw

PATCH 1/1 btrfs: Take trans lock before access running trans in check_delayed_ref

commit 998ac6d21cfd6efd58f5edf420bae8839dda9f2a upstream

In preivous patch:
Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist We avoid starting btrfs transaction and get this information from fs_info->running_transaction directly.

When accessing running_transaction in check_delayed_ref, there's a chance that current transaction will be freed by commit transaction after the NULL pointer check of running_transaction is passed.

After looking all the other places using fs_info->running_transaction, they are either protected by trans_lock or holding the transactions.

Fix this by using trans_lock and increasing the use_count.

Fixes e4c3b2dcd144 ("Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist")
---
 fs/btrfs/extent-tree.c | 7 +++++++
 1 file changed, 7 insertions(+)
fs/btrfs/extent-tree.c +7 -0
index d227d85..1bc6229 100644
@@ -3171,7 +3171,11 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 	struct btrfs_transaction *cur_trans;
 	int ret = 0;
 
+	spin_lock(&root->fs_info->trans_lock);
 	cur_trans = root->fs_info->running_transaction;
+	if (cur_trans)
+		refcount_inc(&cur_trans->use_count);
+	spin_unlock(&root->fs_info->trans_lock);
 	if (!cur_trans)
 		return 0;
 
@@ -3180,6 +3184,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 	head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
 	if (!head) {
 		spin_unlock(&delayed_refs->lock);
+		btrfs_put_transaction(cur_trans);
 		return 0;
 	}
 
@@ -3196,6 +3201,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 		mutex_lock(&head->mutex);
 		mutex_unlock(&head->mutex);
 		btrfs_put_delayed_ref(&head->node);
+		btrfs_put_transaction(cur_trans);
 		return -EAGAIN;
 	}
 	spin_unlock(&delayed_refs->lock);
@@ -3223,6 +3229,7 @@ static noinline int check_delayed_ref(struct btrfs_root *root,
 	}
 	spin_unlock(&head->lock);
 	mutex_unlock(&head->mutex);
+	btrfs_put_transaction(cur_trans);
 	return ret;
 }
 
Signature · 1 line
1.9.1
author maintainer
#2 lore raw

Re: [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref

Quoted 16 lines · ethanwu

commit 998ac6d21cfd6efd58f5edf420bae8839dda9f2a upstream

In preivous patch:
Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist We avoid starting btrfs transaction and get this information from fs_info->running_transaction directly.

When accessing running_transaction in check_delayed_ref, there's a chance that current transaction will be freed by commit transaction after the NULL pointer check of running_transaction is passed.

After looking all the other places using fs_info->running_transaction, they are either protected by trans_lock or holding the transactions.

Fix this by using trans_lock and increasing the use_count.

Quoted 7 lines
Fixes e4c3b2dcd144 ("Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist")
---
 fs/btrfs/extent-tree.c | 7 +++++++
 1 file changed, 7 insertions(+)

Thanks for the backport, now queued up.

greg k-h