diff mbox series

[RFC,v3,10/11] btrfs: check for leaks of ordered stripes on umount

Message ID c939c2fdd361800a4361707bf9d5cc68e30e7907.1666007330.git.johannes.thumshirn@wdc.com (mailing list archive)
State New, archived
Headers show
Series btrfs: raid-stripe-tree draft patches | expand

Commit Message

Johannes Thumshirn Oct. 17, 2022, 11:55 a.m. UTC
Check if we're leaking any ordered stripes when unmounting a filesystem
with an stripe tree.

This check is gated behind CONFIG_BTRFS_DEBUG to not affect any production
type systems.

Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
---
 fs/btrfs/disk-io.c          |  2 ++
 fs/btrfs/raid-stripe-tree.c | 29 +++++++++++++++++++++++++++++
 fs/btrfs/raid-stripe-tree.h |  1 +
 3 files changed, 32 insertions(+)

Comments

Josef Bacik Oct. 20, 2022, 3:37 p.m. UTC | #1
On Mon, Oct 17, 2022 at 04:55:28AM -0700, Johannes Thumshirn wrote:
> Check if we're leaking any ordered stripes when unmounting a filesystem
> with an stripe tree.
> 
> This check is gated behind CONFIG_BTRFS_DEBUG to not affect any production
> type systems.
> 
> Signed-off-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
> ---
>  fs/btrfs/disk-io.c          |  2 ++
>  fs/btrfs/raid-stripe-tree.c | 29 +++++++++++++++++++++++++++++
>  fs/btrfs/raid-stripe-tree.h |  1 +
>  3 files changed, 32 insertions(+)
> 
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 190caabf5fb7..e479e9829c3e 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -43,6 +43,7 @@
>  #include "space-info.h"
>  #include "zoned.h"
>  #include "subpage.h"
> +#include "raid-stripe-tree.h"
>  
>  #define BTRFS_SUPER_FLAG_SUPP	(BTRFS_HEADER_FLAG_WRITTEN |\
>  				 BTRFS_HEADER_FLAG_RELOC |\
> @@ -1480,6 +1481,7 @@ void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
>  	btrfs_put_root(fs_info->stripe_root);
>  	btrfs_check_leaked_roots(fs_info);
>  	btrfs_extent_buffer_leak_debug_check(fs_info);
> +	btrfs_check_ordered_stripe_leak(fs_info);
>  	kfree(fs_info->super_copy);
>  	kfree(fs_info->super_for_commit);
>  	kfree(fs_info->subpage_info);
> diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
> index 91e67600e01a..9a913c4cd44e 100644
> --- a/fs/btrfs/raid-stripe-tree.c
> +++ b/fs/btrfs/raid-stripe-tree.c
> @@ -30,6 +30,35 @@ static int ordered_stripe_less(struct rb_node *rba, const struct rb_node *rbb)
>  	return ordered_stripe_cmp(&stripe->logical, rbb);
>  }
>  
> +void btrfs_check_ordered_stripe_leak(struct btrfs_fs_info *fs_info)
> +{
> +#ifdef CONFIG_BTRFS_DEBUG
> +	struct rb_node *node;
> +
> +	if (!fs_info->stripe_root ||
> +	    RB_EMPTY_ROOT(&fs_info->stripe_update_tree))
> +		return;
> +
> +	mutex_lock(&fs_info->stripe_update_lock);
> +	while ((node = rb_first_postorder(&fs_info->stripe_update_tree))
> +	       != NULL) {
> +		struct btrfs_ordered_stripe *stripe =
> +			rb_entry(node, struct btrfs_ordered_stripe, rb_node);
> +

Can we get a WARN_ON_ONCE() in here?  That way xfstests failures will get
noticed as we'll get the dmesg failures.  Thanks,

Josef
Johannes Thumshirn Oct. 21, 2022, 8:17 a.m. UTC | #2
On 20.10.22 17:37, Josef Bacik wrote:
+void btrfs_check_ordered_stripe_leak(struct btrfs_fs_info *fs_info)
>> +{
>> +#ifdef CONFIG_BTRFS_DEBUG
>> +	struct rb_node *node;
>> +
>> +	if (!fs_info->stripe_root ||
>> +	    RB_EMPTY_ROOT(&fs_info->stripe_update_tree))
>> +		return;
>> +
>> +	mutex_lock(&fs_info->stripe_update_lock);
>> +	while ((node = rb_first_postorder(&fs_info->stripe_update_tree))
>> +	       != NULL) {
>> +		struct btrfs_ordered_stripe *stripe =
>> +			rb_entry(node, struct btrfs_ordered_stripe, rb_node);
>> +
> 
> Can we get a WARN_ON_ONCE() in here?  That way xfstests failures will get
> noticed as we'll get the dmesg failures.  Thanks,

Sure.
diff mbox series

Patch

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 190caabf5fb7..e479e9829c3e 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -43,6 +43,7 @@ 
 #include "space-info.h"
 #include "zoned.h"
 #include "subpage.h"
+#include "raid-stripe-tree.h"
 
 #define BTRFS_SUPER_FLAG_SUPP	(BTRFS_HEADER_FLAG_WRITTEN |\
 				 BTRFS_HEADER_FLAG_RELOC |\
@@ -1480,6 +1481,7 @@  void btrfs_free_fs_info(struct btrfs_fs_info *fs_info)
 	btrfs_put_root(fs_info->stripe_root);
 	btrfs_check_leaked_roots(fs_info);
 	btrfs_extent_buffer_leak_debug_check(fs_info);
+	btrfs_check_ordered_stripe_leak(fs_info);
 	kfree(fs_info->super_copy);
 	kfree(fs_info->super_for_commit);
 	kfree(fs_info->subpage_info);
diff --git a/fs/btrfs/raid-stripe-tree.c b/fs/btrfs/raid-stripe-tree.c
index 91e67600e01a..9a913c4cd44e 100644
--- a/fs/btrfs/raid-stripe-tree.c
+++ b/fs/btrfs/raid-stripe-tree.c
@@ -30,6 +30,35 @@  static int ordered_stripe_less(struct rb_node *rba, const struct rb_node *rbb)
 	return ordered_stripe_cmp(&stripe->logical, rbb);
 }
 
+void btrfs_check_ordered_stripe_leak(struct btrfs_fs_info *fs_info)
+{
+#ifdef CONFIG_BTRFS_DEBUG
+	struct rb_node *node;
+
+	if (!fs_info->stripe_root ||
+	    RB_EMPTY_ROOT(&fs_info->stripe_update_tree))
+		return;
+
+	mutex_lock(&fs_info->stripe_update_lock);
+	while ((node = rb_first_postorder(&fs_info->stripe_update_tree))
+	       != NULL) {
+		struct btrfs_ordered_stripe *stripe =
+			rb_entry(node, struct btrfs_ordered_stripe, rb_node);
+
+		mutex_unlock(&fs_info->stripe_update_lock);
+		btrfs_err(fs_info,
+			  "ordered_stripe [%llu, %llu] leaked, refcount=%d",
+			  stripe->logical, stripe->logical + stripe->num_bytes,
+			  refcount_read(&stripe->ref));
+		while (refcount_read(&stripe->ref) > 1)
+			btrfs_put_ordered_stripe(fs_info, stripe);
+		btrfs_put_ordered_stripe(fs_info, stripe);
+		mutex_lock(&fs_info->stripe_update_lock);
+	}
+	mutex_unlock(&fs_info->stripe_update_lock);
+#endif
+}
+
 int btrfs_add_ordered_stripe(struct btrfs_io_context *bioc)
 {
 	struct btrfs_fs_info *fs_info = bioc->fs_info;
diff --git a/fs/btrfs/raid-stripe-tree.h b/fs/btrfs/raid-stripe-tree.h
index d1885b428cd4..5ffb10bf219e 100644
--- a/fs/btrfs/raid-stripe-tree.h
+++ b/fs/btrfs/raid-stripe-tree.h
@@ -31,6 +31,7 @@  struct btrfs_ordered_stripe *btrfs_lookup_ordered_stripe(
 int btrfs_add_ordered_stripe(struct btrfs_io_context *bioc);
 void btrfs_put_ordered_stripe(struct btrfs_fs_info *fs_info,
 					    struct btrfs_ordered_stripe *stripe);
+void btrfs_check_ordered_stripe_leak(struct btrfs_fs_info *fs_info);
 
 static inline bool btrfs_need_stripe_tree_update(struct btrfs_fs_info *fs_info,
 						 u64 map_type)