linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] btrfs: Take trans lock before access running trans in check_delayed_ref
@ 2018-04-29  7:59 ethanwu
  2018-05-01 13:30 ` David Sterba
  0 siblings, 1 reply; 8+ messages in thread
From: ethanwu @ 2018-04-29  7:59 UTC (permalink / raw)
  To: linux-btrfs; +Cc: ethanwu

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.

Signed-off-by: ethanwu <ethanwu@synology.com>
---
V2: Use refcount_inc rather than aomitc_inc to increase use_count

 fs/btrfs/extent-tree.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c1618ab..7c302ed 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3149,7 +3149,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;
 
@@ -3158,6 +3162,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;
 	}
 
@@ -3174,6 +3179,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);
@@ -3206,6 +3212,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.9.1


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

* Re: [PATCH v2] btrfs: Take trans lock before access running trans in check_delayed_ref
  2018-04-29  7:59 [PATCH v2] btrfs: Take trans lock before access running trans in check_delayed_ref ethanwu
@ 2018-05-01 13:30 ` David Sterba
  2018-05-02  2:55   ` [PATCH] " ethanwu
  0 siblings, 1 reply; 8+ messages in thread
From: David Sterba @ 2018-05-01 13:30 UTC (permalink / raw)
  To: ethanwu; +Cc: linux-btrfs

On Sun, Apr 29, 2018 at 03:59:42PM +0800, ethanwu wrote:
> In preivous patch:
> Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist

If you know which patch introduced the bug, please add it with the
commit id and as

Fixes: e4c3b2dcd144 ("Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist")

to the tags (signed-off section).

> 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.
> 
> Signed-off-by: ethanwu <ethanwu@synology.com>

Added to next, thanks.

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

* [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref
  2018-05-01 13:30 ` David Sterba
@ 2018-05-02  2:55   ` ethanwu
  0 siblings, 0 replies; 8+ messages in thread
From: ethanwu @ 2018-05-02  2:55 UTC (permalink / raw)
  To: linux-btrfs; +Cc: ethanwu

In preivous patch:
Btrfs: kill trans in run_delalloc_nocow and btrfs_cross_ref_exist
We avoid starting btrfs transaction and get transaction 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
1. protected by trans_lock or
2. holding the transaction, so commit transaction must wait before
   it could finish committing and free the transaction structure

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")
Signed-off-by: ethanwu <ethanwu@synology.com>
Reviewed-by: Liu Bo <bo.liu@linux.alibaba.com>
---
V2: Use refcount_inc rather than aomitc_inc to increase use_count
V3: Add Fixes tag and refine commit log

 fs/btrfs/extent-tree.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c1618ab..7c302ed 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3149,7 +3149,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;
 
@@ -3158,6 +3162,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;
 	}
 
@@ -3174,6 +3179,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);
@@ -3206,6 +3212,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.9.1


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

* Re: [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref
  2018-04-27  9:58 ethanwu
                   ` (2 preceding siblings ...)
  2018-04-28 15:37 ` kbuild test robot
@ 2018-04-28 17:36 ` kbuild test robot
  3 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2018-04-28 17:36 UTC (permalink / raw)
  To: ethanwu; +Cc: kbuild-all, linux-btrfs, bo.li.liu, ethanwu

Hi ethanwu,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on v4.17-rc2]
[also build test WARNING on next-20180426]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/ethanwu/btrfs-Take-trans-lock-before-access-running-trans-in-check_delayed_ref/20180428-223414
reproduce:
        # apt-get install sparse
        make ARCH=x86_64 allmodconfig
        make C=1 CF=-D__CHECK_ENDIAN__


sparse warnings: (new ones prefixed by >>)

   fs/btrfs/extent-tree.c:278:39: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:278:39: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:401:16: sparse: expression using sizeof(void)
>> fs/btrfs/extent-tree.c:3148:29: sparse: incorrect type in argument 1 (different base types) @@    expected struct atomic_t [usertype] *v @@    got ct atomic_t [usertype] *v @@
   fs/btrfs/extent-tree.c:3148:29:    expected struct atomic_t [usertype] *v
   fs/btrfs/extent-tree.c:3148:29:    got struct refcount_struct *<noident>
   fs/btrfs/extent-tree.c:4502:26: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:4850:31: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:4850:31: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5043:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5043:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5043:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5043:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5060:22: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5612:48: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5612:48: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5861:21: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5866:27: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5872:37: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:5872:37: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6308:29: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6308:29: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6737:23: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6737:23: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6740:31: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6740:31: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6782:42: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:6782:42: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:7551:24: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:7551:24: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:7552:24: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:7552:24: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:7716:43: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:7716:43: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8064:37: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8064:37: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8067:37: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8067:37: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8586:35: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8589:35: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:8589:35: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:11035:25: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:11035:25: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:11036:23: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:11036:23: sparse: expression using sizeof(void)
   fs/btrfs/extent-tree.c:2558:20: sparse: context imbalance in 'cleanup_extent_op' - unexpected unlock
   fs/btrfs/extent-tree.c:2590:28: sparse: context imbalance in 'cleanup_ref_head' - unexpected unlock
   fs/btrfs/extent-tree.c:2702:26: sparse: context imbalance in '__btrfs_run_delayed_refs' - different lock contexts for basic block
   fs/btrfs/extent-tree.c:7418:39: sparse: context imbalance in 'btrfs_lock_cluster' - wrong count at exit
   fs/btrfs/extent-tree.c:7695:44: sparse: context imbalance in 'find_free_extent' - unexpected unlock
   fs/btrfs/extent-tree.c:9830:9: sparse: context imbalance in 'btrfs_put_block_group_cache' - wrong count at exit
   fs/btrfs/extent-tree.c: In function 'check_delayed_ref':
   fs/btrfs/extent-tree.c:3148:14: error: passing argument 1 of 'atomic_inc' from incompatible pointer type [-Werror=incompatible-pointer-types]
      atomic_inc(&cur_trans->use_count);
                 ^
   In file included from arch/x86/include/asm/atomic.h:283:0,
                    from include/linux/atomic.h:5,
                    from include/linux/rcupdate.h:38,
                    from include/linux/rculist.h:11,
                    from include/linux/pid.h:5,
                    from include/linux/sched.h:14,
                    from fs/btrfs/extent-tree.c:6:
   include/asm-generic/atomic-instrumented.h:100:29: note: expected 'atomic_t * {aka struct <anonymous> *}' but argument is of type 'refcount_t * {aka struct refcount_struct *}'
    static __always_inline void atomic_inc(atomic_t *v)
                                ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +3148 fs/btrfs/extent-tree.c

  3132	
  3133	static noinline int check_delayed_ref(struct btrfs_root *root,
  3134					      struct btrfs_path *path,
  3135					      u64 objectid, u64 offset, u64 bytenr)
  3136	{
  3137		struct btrfs_delayed_ref_head *head;
  3138		struct btrfs_delayed_ref_node *ref;
  3139		struct btrfs_delayed_data_ref *data_ref;
  3140		struct btrfs_delayed_ref_root *delayed_refs;
  3141		struct btrfs_transaction *cur_trans;
  3142		struct rb_node *node;
  3143		int ret = 0;
  3144	
  3145		spin_lock(&root->fs_info->trans_lock);
  3146		cur_trans = root->fs_info->running_transaction;
  3147		if (cur_trans)
> 3148			atomic_inc(&cur_trans->use_count);
  3149		spin_unlock(&root->fs_info->trans_lock);
  3150		if (!cur_trans)
  3151			return 0;
  3152	
  3153		delayed_refs = &cur_trans->delayed_refs;
  3154		spin_lock(&delayed_refs->lock);
  3155		head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
  3156		if (!head) {
  3157			spin_unlock(&delayed_refs->lock);
  3158			btrfs_put_transaction(cur_trans);
  3159			return 0;
  3160		}
  3161	
  3162		if (!mutex_trylock(&head->mutex)) {
  3163			refcount_inc(&head->refs);
  3164			spin_unlock(&delayed_refs->lock);
  3165	
  3166			btrfs_release_path(path);
  3167	
  3168			/*
  3169			 * Mutex was contended, block until it's released and let
  3170			 * caller try again
  3171			 */
  3172			mutex_lock(&head->mutex);
  3173			mutex_unlock(&head->mutex);
  3174			btrfs_put_delayed_ref_head(head);
  3175			btrfs_put_transaction(cur_trans);
  3176			return -EAGAIN;
  3177		}
  3178		spin_unlock(&delayed_refs->lock);
  3179	
  3180		spin_lock(&head->lock);
  3181		/*
  3182		 * XXX: We should replace this with a proper search function in the
  3183		 * future.
  3184		 */
  3185		for (node = rb_first(&head->ref_tree); node; node = rb_next(node)) {
  3186			ref = rb_entry(node, struct btrfs_delayed_ref_node, ref_node);
  3187			/* If it's a shared ref we know a cross reference exists */
  3188			if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) {
  3189				ret = 1;
  3190				break;
  3191			}
  3192	
  3193			data_ref = btrfs_delayed_node_to_data_ref(ref);
  3194	
  3195			/*
  3196			 * If our ref doesn't match the one we're currently looking at
  3197			 * then we have a cross reference.
  3198			 */
  3199			if (data_ref->root != root->root_key.objectid ||
  3200			    data_ref->objectid != objectid ||
  3201			    data_ref->offset != offset) {
  3202				ret = 1;
  3203				break;
  3204			}
  3205		}
  3206		spin_unlock(&head->lock);
  3207		mutex_unlock(&head->mutex);
  3208		btrfs_put_transaction(cur_trans);
  3209		return ret;
  3210	}
  3211	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

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

* Re: [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref
  2018-04-27  9:58 ethanwu
  2018-04-27 10:16 ` Nikolay Borisov
  2018-04-28 15:36 ` kbuild test robot
@ 2018-04-28 15:37 ` kbuild test robot
  2018-04-28 17:36 ` kbuild test robot
  3 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2018-04-28 15:37 UTC (permalink / raw)
  To: ethanwu; +Cc: kbuild-all, linux-btrfs, bo.li.liu, ethanwu

[-- Attachment #1: Type: text/plain, Size: 4282 bytes --]

Hi ethanwu,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on v4.17-rc2]
[also build test WARNING on next-20180426]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/ethanwu/btrfs-Take-trans-lock-before-access-running-trans-in-check_delayed_ref/20180428-223414
config: i386-randconfig-a0-201816 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All warnings (new ones prefixed by >>):

   fs/btrfs/extent-tree.c: In function 'check_delayed_ref':
>> fs/btrfs/extent-tree.c:3148:14: warning: passing argument 1 of 'atomic_inc' from incompatible pointer type
      atomic_inc(&cur_trans->use_count);
                 ^
   In file included from arch/x86/include/asm/atomic.h:283:0,
                    from include/linux/atomic.h:5,
                    from include/linux/rcupdate.h:38,
                    from include/linux/rculist.h:11,
                    from include/linux/pid.h:5,
                    from include/linux/sched.h:14,
                    from fs/btrfs/extent-tree.c:6:
   include/asm-generic/atomic-instrumented.h:100:29: note: expected 'struct atomic_t *' but argument is of type 'struct refcount_t *'
    static __always_inline void atomic_inc(atomic_t *v)
                                ^

vim +/atomic_inc +3148 fs/btrfs/extent-tree.c

  3132	
  3133	static noinline int check_delayed_ref(struct btrfs_root *root,
  3134					      struct btrfs_path *path,
  3135					      u64 objectid, u64 offset, u64 bytenr)
  3136	{
  3137		struct btrfs_delayed_ref_head *head;
  3138		struct btrfs_delayed_ref_node *ref;
  3139		struct btrfs_delayed_data_ref *data_ref;
  3140		struct btrfs_delayed_ref_root *delayed_refs;
  3141		struct btrfs_transaction *cur_trans;
  3142		struct rb_node *node;
  3143		int ret = 0;
  3144	
  3145		spin_lock(&root->fs_info->trans_lock);
  3146		cur_trans = root->fs_info->running_transaction;
  3147		if (cur_trans)
> 3148			atomic_inc(&cur_trans->use_count);
  3149		spin_unlock(&root->fs_info->trans_lock);
  3150		if (!cur_trans)
  3151			return 0;
  3152	
  3153		delayed_refs = &cur_trans->delayed_refs;
  3154		spin_lock(&delayed_refs->lock);
  3155		head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
  3156		if (!head) {
  3157			spin_unlock(&delayed_refs->lock);
  3158			btrfs_put_transaction(cur_trans);
  3159			return 0;
  3160		}
  3161	
  3162		if (!mutex_trylock(&head->mutex)) {
  3163			refcount_inc(&head->refs);
  3164			spin_unlock(&delayed_refs->lock);
  3165	
  3166			btrfs_release_path(path);
  3167	
  3168			/*
  3169			 * Mutex was contended, block until it's released and let
  3170			 * caller try again
  3171			 */
  3172			mutex_lock(&head->mutex);
  3173			mutex_unlock(&head->mutex);
  3174			btrfs_put_delayed_ref_head(head);
  3175			btrfs_put_transaction(cur_trans);
  3176			return -EAGAIN;
  3177		}
  3178		spin_unlock(&delayed_refs->lock);
  3179	
  3180		spin_lock(&head->lock);
  3181		/*
  3182		 * XXX: We should replace this with a proper search function in the
  3183		 * future.
  3184		 */
  3185		for (node = rb_first(&head->ref_tree); node; node = rb_next(node)) {
  3186			ref = rb_entry(node, struct btrfs_delayed_ref_node, ref_node);
  3187			/* If it's a shared ref we know a cross reference exists */
  3188			if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) {
  3189				ret = 1;
  3190				break;
  3191			}
  3192	
  3193			data_ref = btrfs_delayed_node_to_data_ref(ref);
  3194	
  3195			/*
  3196			 * If our ref doesn't match the one we're currently looking at
  3197			 * then we have a cross reference.
  3198			 */
  3199			if (data_ref->root != root->root_key.objectid ||
  3200			    data_ref->objectid != objectid ||
  3201			    data_ref->offset != offset) {
  3202				ret = 1;
  3203				break;
  3204			}
  3205		}
  3206		spin_unlock(&head->lock);
  3207		mutex_unlock(&head->mutex);
  3208		btrfs_put_transaction(cur_trans);
  3209		return ret;
  3210	}
  3211	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 32550 bytes --]

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

* Re: [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref
  2018-04-27  9:58 ethanwu
  2018-04-27 10:16 ` Nikolay Borisov
@ 2018-04-28 15:36 ` kbuild test robot
  2018-04-28 15:37 ` kbuild test robot
  2018-04-28 17:36 ` kbuild test robot
  3 siblings, 0 replies; 8+ messages in thread
From: kbuild test robot @ 2018-04-28 15:36 UTC (permalink / raw)
  To: ethanwu; +Cc: kbuild-all, linux-btrfs, bo.li.liu, ethanwu

[-- Attachment #1: Type: text/plain, Size: 4407 bytes --]

Hi ethanwu,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on v4.17-rc2]
[also build test ERROR on next-20180426]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/ethanwu/btrfs-Take-trans-lock-before-access-running-trans-in-check_delayed_ref/20180428-223414
config: i386-randconfig-x014-201816 (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=i386 

All errors (new ones prefixed by >>):

   fs/btrfs/extent-tree.c: In function 'check_delayed_ref':
>> fs/btrfs/extent-tree.c:3148:14: error: passing argument 1 of 'atomic_inc' from incompatible pointer type [-Werror=incompatible-pointer-types]
      atomic_inc(&cur_trans->use_count);
                 ^
   In file included from arch/x86/include/asm/atomic.h:283:0,
                    from include/linux/atomic.h:5,
                    from include/linux/rcupdate.h:38,
                    from include/linux/rculist.h:11,
                    from include/linux/pid.h:5,
                    from include/linux/sched.h:14,
                    from fs/btrfs/extent-tree.c:6:
   include/asm-generic/atomic-instrumented.h:100:29: note: expected 'atomic_t * {aka struct <anonymous> *}' but argument is of type 'refcount_t * {aka struct refcount_struct *}'
    static __always_inline void atomic_inc(atomic_t *v)
                                ^~~~~~~~~~
   cc1: some warnings being treated as errors

vim +/atomic_inc +3148 fs/btrfs/extent-tree.c

  3132	
  3133	static noinline int check_delayed_ref(struct btrfs_root *root,
  3134					      struct btrfs_path *path,
  3135					      u64 objectid, u64 offset, u64 bytenr)
  3136	{
  3137		struct btrfs_delayed_ref_head *head;
  3138		struct btrfs_delayed_ref_node *ref;
  3139		struct btrfs_delayed_data_ref *data_ref;
  3140		struct btrfs_delayed_ref_root *delayed_refs;
  3141		struct btrfs_transaction *cur_trans;
  3142		struct rb_node *node;
  3143		int ret = 0;
  3144	
  3145		spin_lock(&root->fs_info->trans_lock);
  3146		cur_trans = root->fs_info->running_transaction;
  3147		if (cur_trans)
> 3148			atomic_inc(&cur_trans->use_count);
  3149		spin_unlock(&root->fs_info->trans_lock);
  3150		if (!cur_trans)
  3151			return 0;
  3152	
  3153		delayed_refs = &cur_trans->delayed_refs;
  3154		spin_lock(&delayed_refs->lock);
  3155		head = btrfs_find_delayed_ref_head(delayed_refs, bytenr);
  3156		if (!head) {
  3157			spin_unlock(&delayed_refs->lock);
  3158			btrfs_put_transaction(cur_trans);
  3159			return 0;
  3160		}
  3161	
  3162		if (!mutex_trylock(&head->mutex)) {
  3163			refcount_inc(&head->refs);
  3164			spin_unlock(&delayed_refs->lock);
  3165	
  3166			btrfs_release_path(path);
  3167	
  3168			/*
  3169			 * Mutex was contended, block until it's released and let
  3170			 * caller try again
  3171			 */
  3172			mutex_lock(&head->mutex);
  3173			mutex_unlock(&head->mutex);
  3174			btrfs_put_delayed_ref_head(head);
  3175			btrfs_put_transaction(cur_trans);
  3176			return -EAGAIN;
  3177		}
  3178		spin_unlock(&delayed_refs->lock);
  3179	
  3180		spin_lock(&head->lock);
  3181		/*
  3182		 * XXX: We should replace this with a proper search function in the
  3183		 * future.
  3184		 */
  3185		for (node = rb_first(&head->ref_tree); node; node = rb_next(node)) {
  3186			ref = rb_entry(node, struct btrfs_delayed_ref_node, ref_node);
  3187			/* If it's a shared ref we know a cross reference exists */
  3188			if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) {
  3189				ret = 1;
  3190				break;
  3191			}
  3192	
  3193			data_ref = btrfs_delayed_node_to_data_ref(ref);
  3194	
  3195			/*
  3196			 * If our ref doesn't match the one we're currently looking at
  3197			 * then we have a cross reference.
  3198			 */
  3199			if (data_ref->root != root->root_key.objectid ||
  3200			    data_ref->objectid != objectid ||
  3201			    data_ref->offset != offset) {
  3202				ret = 1;
  3203				break;
  3204			}
  3205		}
  3206		spin_unlock(&head->lock);
  3207		mutex_unlock(&head->mutex);
  3208		btrfs_put_transaction(cur_trans);
  3209		return ret;
  3210	}
  3211	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 26036 bytes --]

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

* Re: [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref
  2018-04-27  9:58 ethanwu
@ 2018-04-27 10:16 ` Nikolay Borisov
  2018-04-28 15:36 ` kbuild test robot
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 8+ messages in thread
From: Nikolay Borisov @ 2018-04-27 10:16 UTC (permalink / raw)
  To: ethanwu, linux-btrfs; +Cc: bo.li.liu



On 27.04.2018 12:58, ethanwu wrote:
> 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 incrementing the use_count.

Yep, looking at how ->running_transaction is set/cleared, holding the
trans_lock is correct here. However there is one point which you need to
fix.

> 
> Signed-off-by: ethanwu <ethanwu@synology.com>
> ---
>  fs/btrfs/extent-tree.c | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
> index c1618ab..c8fd37b 100644
> --- a/fs/btrfs/extent-tree.c
> +++ b/fs/btrfs/extent-tree.c
> @@ -3149,7 +3149,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)
> +		atomic_inc(&cur_trans->use_count);

The ->use_count is using refcount_inc now, not atomic_inc. Please base
all further upstream patches on upstream code

> +	spin_unlock(&root->fs_info->trans_lock);
>  	if (!cur_trans)
>  		return 0;
>  
> @@ -3158,6 +3162,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;
>  	}
>  
> @@ -3174,6 +3179,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);
> @@ -3206,6 +3212,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;
>  }
>  
> 

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

* [PATCH] btrfs: Take trans lock before access running trans in check_delayed_ref
@ 2018-04-27  9:58 ethanwu
  2018-04-27 10:16 ` Nikolay Borisov
                   ` (3 more replies)
  0 siblings, 4 replies; 8+ messages in thread
From: ethanwu @ 2018-04-27  9:58 UTC (permalink / raw)
  To: linux-btrfs; +Cc: bo.li.liu, ethanwu

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 incrementing the use_count.

Signed-off-by: ethanwu <ethanwu@synology.com>
---
 fs/btrfs/extent-tree.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c1618ab..c8fd37b 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -3149,7 +3149,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)
+		atomic_inc(&cur_trans->use_count);
+	spin_unlock(&root->fs_info->trans_lock);
 	if (!cur_trans)
 		return 0;
 
@@ -3158,6 +3162,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;
 	}
 
@@ -3174,6 +3179,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);
@@ -3206,6 +3212,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.9.1


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

end of thread, other threads:[~2018-05-02  2:55 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-29  7:59 [PATCH v2] btrfs: Take trans lock before access running trans in check_delayed_ref ethanwu
2018-05-01 13:30 ` David Sterba
2018-05-02  2:55   ` [PATCH] " ethanwu
  -- strict thread matches above, loose matches on Subject: below --
2018-04-27  9:58 ethanwu
2018-04-27 10:16 ` Nikolay Borisov
2018-04-28 15:36 ` kbuild test robot
2018-04-28 15:37 ` kbuild test robot
2018-04-28 17:36 ` kbuild test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).