linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/5] btrfs: Enhancement to tree block validation
@ 2019-01-17  7:48 Qu Wenruo
  2019-01-17  7:48 ` [PATCH 1/5] btrfs: Always output error message when key/level verification fails Qu Wenruo
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  7:48 UTC (permalink / raw)
  To: linux-btrfs

Patchset can be fetched from github:
https://github.com/adam900710/linux/tree/write_time_tree_checker
Which is based on v5.0-rc1 tag.

This patchset has the following two features:
- Tree block validation output enhancement
  * Output validation failure timing (write time or read time)
  * Always output tree block level/key mismatch error message
    This part is already submitted and reviewed.

- Write time tree block validation check
  To catch memory corruption either from hardware or kernel.
  Example output would be:

    BTRFS critical (device dm-3): corrupt leaf: root=2 block=1350630375424 slot=68, bad key order, prev (10510212874240 169 0) current (1714119868416 169 0)
    BTRFS error (device dm-3): write time tree block corruption detected
    BTRFS critical (device dm-3): corrupt leaf: root=2 block=1350630375424 slot=68, bad key order, prev (10510212874240 169 0) current (1714119868416 169 0)
    BTRFS error (device dm-3): write time tree block corruption detected
    BTRFS: error (device dm-3) in btrfs_commit_transaction:2220: errno=-5 IO failure (Error while writing out transaction)
    BTRFS info (device dm-3): forced readonly
    BTRFS warning (device dm-3): Skipping commit of aborted transaction.
    BTRFS: error (device dm-3) in cleanup_transaction:1839: errno=-5 IO failure
    BTRFS info (device dm-3): delayed_refs has NO entry

Qu Wenruo (5):
  btrfs: Always output error message when key/level verification fails
  btrfs: extent_io: Kill the forward declaration of flush_write_bio()
  btrfs: extent_io: Kill the BUG_ON() in flush_write_bio()
  btrfs: disk-io: Show the timing of corrupted tree block explicitly
  btrfs: Do mandatory tree block check before submitting bio

 fs/btrfs/disk-io.c   |  20 +++++--
 fs/btrfs/extent_io.c | 122 ++++++++++++++++++++++++++-----------------
 2 files changed, 90 insertions(+), 52 deletions(-)

-- 
2.20.1


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

* [PATCH 1/5] btrfs: Always output error message when key/level verification fails
  2019-01-17  7:48 [PATCH 0/5] btrfs: Enhancement to tree block validation Qu Wenruo
@ 2019-01-17  7:48 ` Qu Wenruo
  2019-01-17  7:48 ` [PATCH 2/5] btrfs: extent_io: Kill the forward declaration of flush_write_bio() Qu Wenruo
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  7:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Nikolay Borisov

We have internal report of strange transaction abort due to EUCLEAN
without any error message.

Since error message inside verify_level_key() is only enabled for
CONFIG_BTRFS_DEBUG, the error message won't output for most distro.

This patch will make the error message mandatory, so when problem
happens we know what's causing the problem.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/disk-io.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 8da2f380d3c0..659bab9de03b 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -425,10 +425,10 @@ static int verify_level_key(struct btrfs_fs_info *fs_info,
 	if (found_level != level) {
 #ifdef CONFIG_BTRFS_DEBUG
 		WARN_ON(1);
+#endif
 		btrfs_err(fs_info,
 "tree level mismatch detected, bytenr=%llu level expected=%u has=%u",
 			  eb->start, level, found_level);
-#endif
 		return -EIO;
 	}
 
@@ -449,9 +449,10 @@ static int verify_level_key(struct btrfs_fs_info *fs_info,
 		btrfs_item_key_to_cpu(eb, &found_key, 0);
 	ret = btrfs_comp_cpu_keys(first_key, &found_key);
 
-#ifdef CONFIG_BTRFS_DEBUG
 	if (ret) {
+#ifdef CONFIG_BTRFS_DEBUG
 		WARN_ON(1);
+#endif
 		btrfs_err(fs_info,
 "tree first key mismatch detected, bytenr=%llu parent_transid=%llu key expected=(%llu,%u,%llu) has=(%llu,%u,%llu)",
 			  eb->start, parent_transid, first_key->objectid,
@@ -459,7 +460,6 @@ static int verify_level_key(struct btrfs_fs_info *fs_info,
 			  found_key.objectid, found_key.type,
 			  found_key.offset);
 	}
-#endif
 	return ret;
 }
 
-- 
2.20.1


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

* [PATCH 2/5] btrfs: extent_io: Kill the forward declaration of flush_write_bio()
  2019-01-17  7:48 [PATCH 0/5] btrfs: Enhancement to tree block validation Qu Wenruo
  2019-01-17  7:48 ` [PATCH 1/5] btrfs: Always output error message when key/level verification fails Qu Wenruo
@ 2019-01-17  7:48 ` Qu Wenruo
  2019-01-17  7:50   ` Nikolay Borisov
  2019-01-17  7:48 ` [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio() Qu Wenruo
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  7:48 UTC (permalink / raw)
  To: linux-btrfs

There is no need to forward declare flush_write_bio(), as it only
depends on submit_one_bio().

Both of them are pretty small, just move them to kill the forward
declaration.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/extent_io.c | 66 +++++++++++++++++++++-----------------------
 1 file changed, 32 insertions(+), 34 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 52abe4082680..8a2335713a2d 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -147,7 +147,38 @@ static int add_extent_changeset(struct extent_state *state, unsigned bits,
 	return ret;
 }
 
-static void flush_write_bio(struct extent_page_data *epd);
+static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
+				       unsigned long bio_flags)
+{
+	blk_status_t ret = 0;
+	struct bio_vec *bvec = bio_last_bvec_all(bio);
+	struct page *page = bvec->bv_page;
+	struct extent_io_tree *tree = bio->bi_private;
+	u64 start;
+
+	start = page_offset(page) + bvec->bv_offset;
+
+	bio->bi_private = NULL;
+
+	if (tree->ops)
+		ret = tree->ops->submit_bio_hook(tree->private_data, bio,
+					   mirror_num, bio_flags, start);
+	else
+		btrfsic_submit_bio(bio);
+
+	return blk_status_to_errno(ret);
+}
+
+static void flush_write_bio(struct extent_page_data *epd)
+{
+	if (epd->bio) {
+		int ret;
+
+		ret = submit_one_bio(epd->bio, 0, 0);
+		BUG_ON(ret < 0); /* -ENOMEM */
+		epd->bio = NULL;
+	}
+}
 
 int __init extent_io_init(void)
 {
@@ -2692,28 +2723,6 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, int offset, int size)
 	return bio;
 }
 
-static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
-				       unsigned long bio_flags)
-{
-	blk_status_t ret = 0;
-	struct bio_vec *bvec = bio_last_bvec_all(bio);
-	struct page *page = bvec->bv_page;
-	struct extent_io_tree *tree = bio->bi_private;
-	u64 start;
-
-	start = page_offset(page) + bvec->bv_offset;
-
-	bio->bi_private = NULL;
-
-	if (tree->ops)
-		ret = tree->ops->submit_bio_hook(tree->private_data, bio,
-					   mirror_num, bio_flags, start);
-	else
-		btrfsic_submit_bio(bio);
-
-	return blk_status_to_errno(ret);
-}
-
 /*
  * @opf:	bio REQ_OP_* and REQ_* flags as one value
  * @tree:	tree so we can call our merge_bio hook
@@ -4007,17 +4016,6 @@ static int extent_write_cache_pages(struct address_space *mapping,
 	return ret;
 }
 
-static void flush_write_bio(struct extent_page_data *epd)
-{
-	if (epd->bio) {
-		int ret;
-
-		ret = submit_one_bio(epd->bio, 0, 0);
-		BUG_ON(ret < 0); /* -ENOMEM */
-		epd->bio = NULL;
-	}
-}
-
 int extent_write_full_page(struct page *page, struct writeback_control *wbc)
 {
 	int ret;
-- 
2.20.1


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

* [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio()
  2019-01-17  7:48 [PATCH 0/5] btrfs: Enhancement to tree block validation Qu Wenruo
  2019-01-17  7:48 ` [PATCH 1/5] btrfs: Always output error message when key/level verification fails Qu Wenruo
  2019-01-17  7:48 ` [PATCH 2/5] btrfs: extent_io: Kill the forward declaration of flush_write_bio() Qu Wenruo
@ 2019-01-17  7:48 ` Qu Wenruo
  2019-01-17  8:22   ` Nikolay Borisov
  2019-01-17  7:48 ` [PATCH 4/5] btrfs: disk-io: Show the timing of corrupted tree block explicitly Qu Wenruo
  2019-01-17  7:48 ` [PATCH 5/5] btrfs: Do mandatory tree block check before submitting bio Qu Wenruo
  4 siblings, 1 reply; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  7:48 UTC (permalink / raw)
  To: linux-btrfs

This BUG_ON() is really just a crappy way to workaround the _must_check
attribute of submit_one_bio().

Now kill the BUG_ON() and allow flush_write_bio() to return error
number.

Also add _must_check attribute to flush_write_bio(), and modify all
callers to handle the possible error returned.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/extent_io.c | 64 +++++++++++++++++++++++++++++++-------------
 1 file changed, 46 insertions(+), 18 deletions(-)

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 8a2335713a2d..a773bc46badc 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -169,15 +169,15 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
 	return blk_status_to_errno(ret);
 }
 
-static void flush_write_bio(struct extent_page_data *epd)
+static int __must_check flush_write_bio(struct extent_page_data *epd)
 {
-	if (epd->bio) {
-		int ret;
+	int ret = 0;
 
+	if (epd->bio) {
 		ret = submit_one_bio(epd->bio, 0, 0);
-		BUG_ON(ret < 0); /* -ENOMEM */
 		epd->bio = NULL;
 	}
+	return ret;
 }
 
 int __init extent_io_init(void)
@@ -3509,8 +3509,10 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
 	int ret = 0;
 
 	if (!btrfs_try_tree_write_lock(eb)) {
+		ret = flush_write_bio(epd);
+		if (ret < 0)
+			return ret;
 		flush = 1;
-		flush_write_bio(epd);
 		btrfs_tree_lock(eb);
 	}
 
@@ -3519,7 +3521,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
 		if (!epd->sync_io)
 			return 0;
 		if (!flush) {
-			flush_write_bio(epd);
+			ret = flush_write_bio(epd);
+			if (ret < 0)
+				return ret;
 			flush = 1;
 		}
 		while (1) {
@@ -3560,7 +3564,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
 
 		if (!trylock_page(p)) {
 			if (!flush) {
-				flush_write_bio(epd);
+				ret = flush_write_bio(epd);
+				if (ret < 0)
+					return ret;
 				flush = 1;
 			}
 			lock_page(p);
@@ -3751,6 +3757,7 @@ int btree_write_cache_pages(struct address_space *mapping,
 		.sync_io = wbc->sync_mode == WB_SYNC_ALL,
 	};
 	int ret = 0;
+	int flush_ret;
 	int done = 0;
 	int nr_to_write_done = 0;
 	struct pagevec pvec;
@@ -3818,6 +3825,11 @@ int btree_write_cache_pages(struct address_space *mapping,
 
 			prev_eb = eb;
 			ret = lock_extent_buffer_for_io(eb, fs_info, &epd);
+			if (ret < 0) {
+				free_extent_buffer(eb);
+				done = 1;
+				break;
+			}
 			if (!ret) {
 				free_extent_buffer(eb);
 				continue;
@@ -3850,8 +3862,10 @@ int btree_write_cache_pages(struct address_space *mapping,
 		index = 0;
 		goto retry;
 	}
-	flush_write_bio(&epd);
-	return ret;
+	flush_ret = flush_write_bio(&epd);
+	if (ret)
+		return ret;
+	return flush_ret;
 }
 
 /**
@@ -3947,7 +3961,9 @@ static int extent_write_cache_pages(struct address_space *mapping,
 			 * tmpfs file mapping
 			 */
 			if (!trylock_page(page)) {
-				flush_write_bio(epd);
+				ret = flush_write_bio(epd);
+				if (ret < 0)
+					break;
 				lock_page(page);
 			}
 
@@ -3957,8 +3973,11 @@ static int extent_write_cache_pages(struct address_space *mapping,
 			}
 
 			if (wbc->sync_mode != WB_SYNC_NONE) {
-				if (PageWriteback(page))
-					flush_write_bio(epd);
+				if (PageWriteback(page)) {
+					ret = flush_write_bio(epd);
+					if (ret < 0)
+						break;
+				}
 				wait_on_page_writeback(page);
 			}
 
@@ -4019,6 +4038,7 @@ static int extent_write_cache_pages(struct address_space *mapping,
 int extent_write_full_page(struct page *page, struct writeback_control *wbc)
 {
 	int ret;
+	int flush_ret;
 	struct extent_page_data epd = {
 		.bio = NULL,
 		.tree = &BTRFS_I(page->mapping->host)->io_tree,
@@ -4028,14 +4048,17 @@ int extent_write_full_page(struct page *page, struct writeback_control *wbc)
 
 	ret = __extent_writepage(page, wbc, &epd);
 
-	flush_write_bio(&epd);
-	return ret;
+	flush_ret = flush_write_bio(&epd);
+	if (ret)
+		return ret;
+	return flush_ret;
 }
 
 int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
 			      int mode)
 {
 	int ret = 0;
+	int flush_ret;
 	struct address_space *mapping = inode->i_mapping;
 	struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree;
 	struct page *page;
@@ -4068,14 +4091,17 @@ int extent_write_locked_range(struct inode *inode, u64 start, u64 end,
 		start += PAGE_SIZE;
 	}
 
-	flush_write_bio(&epd);
-	return ret;
+	flush_ret = flush_write_bio(&epd);
+	if (ret)
+		return ret;
+	return flush_ret;
 }
 
 int extent_writepages(struct address_space *mapping,
 		      struct writeback_control *wbc)
 {
 	int ret = 0;
+	int flush_ret;
 	struct extent_page_data epd = {
 		.bio = NULL,
 		.tree = &BTRFS_I(mapping->host)->io_tree,
@@ -4084,8 +4110,10 @@ int extent_writepages(struct address_space *mapping,
 	};
 
 	ret = extent_write_cache_pages(mapping, wbc, &epd);
-	flush_write_bio(&epd);
-	return ret;
+	flush_ret = flush_write_bio(&epd);
+	if (ret)
+		return ret;
+	return flush_ret;
 }
 
 int extent_readpages(struct address_space *mapping, struct list_head *pages,
-- 
2.20.1


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

* [PATCH 4/5] btrfs: disk-io: Show the timing of corrupted tree block explicitly
  2019-01-17  7:48 [PATCH 0/5] btrfs: Enhancement to tree block validation Qu Wenruo
                   ` (2 preceding siblings ...)
  2019-01-17  7:48 ` [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio() Qu Wenruo
@ 2019-01-17  7:48 ` Qu Wenruo
  2019-01-17  8:42   ` Nikolay Borisov
  2019-01-17  7:48 ` [PATCH 5/5] btrfs: Do mandatory tree block check before submitting bio Qu Wenruo
  4 siblings, 1 reply; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  7:48 UTC (permalink / raw)
  To: linux-btrfs

Just add one extra line to show when the corruption is detected.
Currently only read time detection is possible.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/disk-io.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 659bab9de03b..bc2379cb2091 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -652,11 +652,14 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
 	 */
 	if (found_level == 0 && btrfs_check_leaf_full(fs_info, eb)) {
 		set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
+		btrfs_err(fs_info, "read time tree block corruption detected");
 		ret = -EIO;
 	}
 
-	if (found_level > 0 && btrfs_check_node(fs_info, eb))
+	if (found_level > 0 && btrfs_check_node(fs_info, eb)) {
+		btrfs_err(fs_info, "read time tree block corruption detected");
 		ret = -EIO;
+	}
 
 	if (!ret)
 		set_extent_buffer_uptodate(eb);
-- 
2.20.1


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

* [PATCH 5/5] btrfs: Do mandatory tree block check before submitting bio
  2019-01-17  7:48 [PATCH 0/5] btrfs: Enhancement to tree block validation Qu Wenruo
                   ` (3 preceding siblings ...)
  2019-01-17  7:48 ` [PATCH 4/5] btrfs: disk-io: Show the timing of corrupted tree block explicitly Qu Wenruo
@ 2019-01-17  7:48 ` Qu Wenruo
  4 siblings, 0 replies; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  7:48 UTC (permalink / raw)
  To: linux-btrfs; +Cc: Leonard Lausen

There are at least 2 reports about memory bit flip sneaking into on-disk
data.

Currently we only have a relaxed check triggered at
btrfs_mark_buffer_dirty() time, as it's not mandatory, only for
CONFIG_BTRFS_FS_CHECK_INTEGRITY enabled build.

This patch will address the hole by triggering comprehensive check on
tree blocks before writing it back to disk.

The timing is set to csum_tree_block() where @verify == 0.
At that timing, we're generation csum for tree blocks before submitting
the metadata bio, so we could avoid all the unnecessary calls at
btrfs_mark_buffer_dirty(), but still catch enough error.

The example error output will be something like:
  BTRFS critical (device dm-3): corrupt leaf: root=2 block=1350630375424 slot=68, bad key order, prev (10510212874240 169 0) current (1714119868416 169 0)
  BTRFS error (device dm-3): write time tree block corruption detected
  BTRFS critical (device dm-3): corrupt leaf: root=2 block=1350630375424 slot=68, bad key order, prev (10510212874240 169 0) current (1714119868416 169 0)
  BTRFS error (device dm-3): write time tree block corruption detected
  BTRFS: error (device dm-3) in btrfs_commit_transaction:2220: errno=-5 IO failure (Error while writing out transaction)
  BTRFS info (device dm-3): forced readonly
  BTRFS warning (device dm-3): Skipping commit of aborted transaction.
  BTRFS: error (device dm-3) in cleanup_transaction:1839: errno=-5 IO failure
  BTRFS info (device dm-3): delayed_refs has NO entry

Reported-by: Leonard Lausen <leonard@lausen.nl>
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/disk-io.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index bc2379cb2091..d95716847870 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -313,6 +313,15 @@ static int csum_tree_block(struct btrfs_fs_info *fs_info,
 			return -EUCLEAN;
 		}
 	} else {
+		if (btrfs_header_level(buf))
+			err = btrfs_check_node(fs_info, buf);
+		else
+			err = btrfs_check_leaf_full(fs_info, buf);
+		if (err < 0) {
+			btrfs_err(fs_info,
+				  "write time tree block corruption detected");
+			return err;
+		}
 		write_extent_buffer(buf, result, 0, csum_size);
 	}
 
-- 
2.20.1


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

* Re: [PATCH 2/5] btrfs: extent_io: Kill the forward declaration of flush_write_bio()
  2019-01-17  7:48 ` [PATCH 2/5] btrfs: extent_io: Kill the forward declaration of flush_write_bio() Qu Wenruo
@ 2019-01-17  7:50   ` Nikolay Borisov
  0 siblings, 0 replies; 11+ messages in thread
From: Nikolay Borisov @ 2019-01-17  7:50 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs



On 17.01.19 г. 9:48 ч., Qu Wenruo wrote:
> There is no need to forward declare flush_write_bio(), as it only
> depends on submit_one_bio().
> 
> Both of them are pretty small, just move them to kill the forward
> declaration.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>

I'm very much in favor of killing forward declarations for static
functions.

Reviewed-by: Nikolay Borisov <nborisov@suse.com>

> ---
>  fs/btrfs/extent_io.c | 66 +++++++++++++++++++++-----------------------
>  1 file changed, 32 insertions(+), 34 deletions(-)
> 
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 52abe4082680..8a2335713a2d 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -147,7 +147,38 @@ static int add_extent_changeset(struct extent_state *state, unsigned bits,
>  	return ret;
>  }
>  
> -static void flush_write_bio(struct extent_page_data *epd);
> +static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
> +				       unsigned long bio_flags)
> +{
> +	blk_status_t ret = 0;
> +	struct bio_vec *bvec = bio_last_bvec_all(bio);
> +	struct page *page = bvec->bv_page;
> +	struct extent_io_tree *tree = bio->bi_private;
> +	u64 start;
> +
> +	start = page_offset(page) + bvec->bv_offset;
> +
> +	bio->bi_private = NULL;
> +
> +	if (tree->ops)
> +		ret = tree->ops->submit_bio_hook(tree->private_data, bio,
> +					   mirror_num, bio_flags, start);
> +	else
> +		btrfsic_submit_bio(bio);
> +
> +	return blk_status_to_errno(ret);
> +}
> +
> +static void flush_write_bio(struct extent_page_data *epd)
> +{
> +	if (epd->bio) {
> +		int ret;
> +
> +		ret = submit_one_bio(epd->bio, 0, 0);
> +		BUG_ON(ret < 0); /* -ENOMEM */
> +		epd->bio = NULL;
> +	}
> +}
>  
>  int __init extent_io_init(void)
>  {
> @@ -2692,28 +2723,6 @@ struct bio *btrfs_bio_clone_partial(struct bio *orig, int offset, int size)
>  	return bio;
>  }
>  
> -static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
> -				       unsigned long bio_flags)
> -{
> -	blk_status_t ret = 0;
> -	struct bio_vec *bvec = bio_last_bvec_all(bio);
> -	struct page *page = bvec->bv_page;
> -	struct extent_io_tree *tree = bio->bi_private;
> -	u64 start;
> -
> -	start = page_offset(page) + bvec->bv_offset;
> -
> -	bio->bi_private = NULL;
> -
> -	if (tree->ops)
> -		ret = tree->ops->submit_bio_hook(tree->private_data, bio,
> -					   mirror_num, bio_flags, start);
> -	else
> -		btrfsic_submit_bio(bio);
> -
> -	return blk_status_to_errno(ret);
> -}
> -
>  /*
>   * @opf:	bio REQ_OP_* and REQ_* flags as one value
>   * @tree:	tree so we can call our merge_bio hook
> @@ -4007,17 +4016,6 @@ static int extent_write_cache_pages(struct address_space *mapping,
>  	return ret;
>  }
>  
> -static void flush_write_bio(struct extent_page_data *epd)
> -{
> -	if (epd->bio) {
> -		int ret;
> -
> -		ret = submit_one_bio(epd->bio, 0, 0);
> -		BUG_ON(ret < 0); /* -ENOMEM */
> -		epd->bio = NULL;
> -	}
> -}
> -
>  int extent_write_full_page(struct page *page, struct writeback_control *wbc)
>  {
>  	int ret;
> 

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

* Re: [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio()
  2019-01-17  7:48 ` [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio() Qu Wenruo
@ 2019-01-17  8:22   ` Nikolay Borisov
  2019-01-17  8:28     ` Qu Wenruo
  0 siblings, 1 reply; 11+ messages in thread
From: Nikolay Borisov @ 2019-01-17  8:22 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs



On 17.01.19 г. 9:48 ч., Qu Wenruo wrote:
> This BUG_ON() is really just a crappy way to workaround the _must_check
> attribute of submit_one_bio().
> 
> Now kill the BUG_ON() and allow flush_write_bio() to return error
> number.
> 
> Also add _must_check attribute to flush_write_bio(), and modify all
> callers to handle the possible error returned.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>
> ---
>  fs/btrfs/extent_io.c | 64 +++++++++++++++++++++++++++++++-------------
>  1 file changed, 46 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
> index 8a2335713a2d..a773bc46badc 100644
> --- a/fs/btrfs/extent_io.c
> +++ b/fs/btrfs/extent_io.c
> @@ -169,15 +169,15 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
>  	return blk_status_to_errno(ret);
>  }
>  
> -static void flush_write_bio(struct extent_page_data *epd)
> +static int __must_check flush_write_bio(struct extent_page_data *epd)
>  {
> -	if (epd->bio) {
> -		int ret;
> +	int ret = 0;
>  
> +	if (epd->bio) {
>  		ret = submit_one_bio(epd->bio, 0, 0);
> -		BUG_ON(ret < 0); /* -ENOMEM */
>  		epd->bio = NULL;
>  	}
> +	return ret;
>  }
>  
>  int __init extent_io_init(void)
> @@ -3509,8 +3509,10 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>  	int ret = 0;
>  
>  	if (!btrfs_try_tree_write_lock(eb)) {
> +		ret = flush_write_bio(epd);
> +		if (ret < 0)
> +			return ret;
>  		flush = 1;
> -		flush_write_bio(epd);
>  		btrfs_tree_lock(eb);
>  	}
>  
> @@ -3519,7 +3521,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>  		if (!epd->sync_io)
>  			return 0;
>  		if (!flush) {
> -			flush_write_bio(epd);
> +			ret = flush_write_bio(epd);
> +			if (ret < 0)
> +				return ret;
>  			flush = 1;
>  		}
>  		while (1) {
> @@ -3560,7 +3564,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>  
>  		if (!trylock_page(p)) {
>  			if (!flush) {
> -				flush_write_bio(epd);
> +				ret = flush_write_bio(epd);
> +				if (ret < 0)
> +					return ret;

Can't you end up with partially locked pages here? Are you sure that
flush_write_bio will ALWAYS be executed when i = 0? If that\'s the case
then I think an assert(i == 0) is in order there.

>  				flush = 1;
>  			}
>  			lock_page(p);

<snip>

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

* Re: [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio()
  2019-01-17  8:22   ` Nikolay Borisov
@ 2019-01-17  8:28     ` Qu Wenruo
  2019-01-17  8:52       ` Nikolay Borisov
  0 siblings, 1 reply; 11+ messages in thread
From: Qu Wenruo @ 2019-01-17  8:28 UTC (permalink / raw)
  To: Nikolay Borisov, linux-btrfs



On 2019/1/17 下午4:22, Nikolay Borisov wrote:
> 
> 
> On 17.01.19 г. 9:48 ч., Qu Wenruo wrote:
>> This BUG_ON() is really just a crappy way to workaround the _must_check
>> attribute of submit_one_bio().
>>
>> Now kill the BUG_ON() and allow flush_write_bio() to return error
>> number.
>>
>> Also add _must_check attribute to flush_write_bio(), and modify all
>> callers to handle the possible error returned.
>>
>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>> ---
>>  fs/btrfs/extent_io.c | 64 +++++++++++++++++++++++++++++++-------------
>>  1 file changed, 46 insertions(+), 18 deletions(-)
>>
>> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
>> index 8a2335713a2d..a773bc46badc 100644
>> --- a/fs/btrfs/extent_io.c
>> +++ b/fs/btrfs/extent_io.c
>> @@ -169,15 +169,15 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
>>  	return blk_status_to_errno(ret);
>>  }
>>  
>> -static void flush_write_bio(struct extent_page_data *epd)
>> +static int __must_check flush_write_bio(struct extent_page_data *epd)
>>  {
>> -	if (epd->bio) {
>> -		int ret;
>> +	int ret = 0;
>>  
>> +	if (epd->bio) {
>>  		ret = submit_one_bio(epd->bio, 0, 0);
>> -		BUG_ON(ret < 0); /* -ENOMEM */
>>  		epd->bio = NULL;
>>  	}
>> +	return ret;
>>  }
>>  
>>  int __init extent_io_init(void)
>> @@ -3509,8 +3509,10 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>>  	int ret = 0;
>>  
>>  	if (!btrfs_try_tree_write_lock(eb)) {
>> +		ret = flush_write_bio(epd);
>> +		if (ret < 0)
>> +			return ret;
>>  		flush = 1;
>> -		flush_write_bio(epd);
>>  		btrfs_tree_lock(eb);
>>  	}
>>  
>> @@ -3519,7 +3521,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>>  		if (!epd->sync_io)
>>  			return 0;
>>  		if (!flush) {
>> -			flush_write_bio(epd);
>> +			ret = flush_write_bio(epd);
>> +			if (ret < 0)
>> +				return ret;
>>  			flush = 1;
>>  		}
>>  		while (1) {
>> @@ -3560,7 +3564,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>>  
>>  		if (!trylock_page(p)) {
>>  			if (!flush) {
>> -				flush_write_bio(epd);
>> +				ret = flush_write_bio(epd);
>> +				if (ret < 0)
>> +					return ret;
> 
> Can't you end up with partially locked pages here? Are you sure that
> flush_write_bio will ALWAYS be executed when i = 0? If that\'s the case
> then I think an assert(i == 0) is in order there.

An ASSERT() indeed makes sense here.

Although I could also make it better by recording the failed page number
and unlock those already locked pages.

I'm OK either way.

Thanks,
Qu

> 
>>  				flush = 1;
>>  			}
>>  			lock_page(p);
> 
> <snip>
> 

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

* Re: [PATCH 4/5] btrfs: disk-io: Show the timing of corrupted tree block explicitly
  2019-01-17  7:48 ` [PATCH 4/5] btrfs: disk-io: Show the timing of corrupted tree block explicitly Qu Wenruo
@ 2019-01-17  8:42   ` Nikolay Borisov
  0 siblings, 0 replies; 11+ messages in thread
From: Nikolay Borisov @ 2019-01-17  8:42 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs



On 17.01.19 г. 9:48 ч., Qu Wenruo wrote:
> Just add one extra line to show when the corruption is detected.
> Currently only read time detection is possible.
> 
> Signed-off-by: Qu Wenruo <wqu@suse.com>

Reviewed-by: Nikolay Borisov <nborisov@suse.com>

> ---
>  fs/btrfs/disk-io.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
> index 659bab9de03b..bc2379cb2091 100644
> --- a/fs/btrfs/disk-io.c
> +++ b/fs/btrfs/disk-io.c
> @@ -652,11 +652,14 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
>  	 */
>  	if (found_level == 0 && btrfs_check_leaf_full(fs_info, eb)) {
>  		set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags);
> +		btrfs_err(fs_info, "read time tree block corruption detected");
>  		ret = -EIO;
>  	}
>  
> -	if (found_level > 0 && btrfs_check_node(fs_info, eb))
> +	if (found_level > 0 && btrfs_check_node(fs_info, eb)) {
> +		btrfs_err(fs_info, "read time tree block corruption detected");
>  		ret = -EIO;
> +	}
>  
>  	if (!ret)
>  		set_extent_buffer_uptodate(eb);
> 

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

* Re: [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio()
  2019-01-17  8:28     ` Qu Wenruo
@ 2019-01-17  8:52       ` Nikolay Borisov
  0 siblings, 0 replies; 11+ messages in thread
From: Nikolay Borisov @ 2019-01-17  8:52 UTC (permalink / raw)
  To: Qu Wenruo, linux-btrfs



On 17.01.19 г. 10:28 ч., Qu Wenruo wrote:
> 
> 
> On 2019/1/17 下午4:22, Nikolay Borisov wrote:
>>
>>
>> On 17.01.19 г. 9:48 ч., Qu Wenruo wrote:
>>> This BUG_ON() is really just a crappy way to workaround the _must_check
>>> attribute of submit_one_bio().
>>>
>>> Now kill the BUG_ON() and allow flush_write_bio() to return error
>>> number.
>>>
>>> Also add _must_check attribute to flush_write_bio(), and modify all
>>> callers to handle the possible error returned.
>>>
>>> Signed-off-by: Qu Wenruo <wqu@suse.com>
>>> ---
>>>  fs/btrfs/extent_io.c | 64 +++++++++++++++++++++++++++++++-------------
>>>  1 file changed, 46 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
>>> index 8a2335713a2d..a773bc46badc 100644
>>> --- a/fs/btrfs/extent_io.c
>>> +++ b/fs/btrfs/extent_io.c
>>> @@ -169,15 +169,15 @@ static int __must_check submit_one_bio(struct bio *bio, int mirror_num,
>>>  	return blk_status_to_errno(ret);
>>>  }
>>>  
>>> -static void flush_write_bio(struct extent_page_data *epd)
>>> +static int __must_check flush_write_bio(struct extent_page_data *epd)
>>>  {
>>> -	if (epd->bio) {
>>> -		int ret;
>>> +	int ret = 0;
>>>  
>>> +	if (epd->bio) {
>>>  		ret = submit_one_bio(epd->bio, 0, 0);
>>> -		BUG_ON(ret < 0); /* -ENOMEM */
>>>  		epd->bio = NULL;
>>>  	}
>>> +	return ret;
>>>  }
>>>  
>>>  int __init extent_io_init(void)
>>> @@ -3509,8 +3509,10 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>>>  	int ret = 0;
>>>  
>>>  	if (!btrfs_try_tree_write_lock(eb)) {
>>> +		ret = flush_write_bio(epd);
>>> +		if (ret < 0)
>>> +			return ret;
>>>  		flush = 1;
>>> -		flush_write_bio(epd);
>>>  		btrfs_tree_lock(eb);
>>>  	}
>>>  
>>> @@ -3519,7 +3521,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>>>  		if (!epd->sync_io)
>>>  			return 0;
>>>  		if (!flush) {
>>> -			flush_write_bio(epd);
>>> +			ret = flush_write_bio(epd);
>>> +			if (ret < 0)
>>> +				return ret;
>>>  			flush = 1;
>>>  		}
>>>  		while (1) {
>>> @@ -3560,7 +3564,9 @@ lock_extent_buffer_for_io(struct extent_buffer *eb,
>>>  
>>>  		if (!trylock_page(p)) {
>>>  			if (!flush) {
>>> -				flush_write_bio(epd);
>>> +				ret = flush_write_bio(epd);
>>> +				if (ret < 0)
>>> +					return ret;
>>
>> Can't you end up with partially locked pages here? Are you sure that
>> flush_write_bio will ALWAYS be executed when i = 0? If that\'s the case
>> then I think an assert(i == 0) is in order there.
> 
> An ASSERT() indeed makes sense here.
> 
> Although I could also make it better by recording the failed page number
> and unlock those already locked pages.

Unlocking is the correct way to handle it, the assert would be there to
prove that you won't ever need the unlocking code. If it triggers then
this case must be handled.

> 
> I'm OK either way.
> 
> Thanks,
> Qu
> 
>>
>>>  				flush = 1;
>>>  			}
>>>  			lock_page(p);
>>
>> <snip>
>>

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

end of thread, other threads:[~2019-01-17  8:52 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-01-17  7:48 [PATCH 0/5] btrfs: Enhancement to tree block validation Qu Wenruo
2019-01-17  7:48 ` [PATCH 1/5] btrfs: Always output error message when key/level verification fails Qu Wenruo
2019-01-17  7:48 ` [PATCH 2/5] btrfs: extent_io: Kill the forward declaration of flush_write_bio() Qu Wenruo
2019-01-17  7:50   ` Nikolay Borisov
2019-01-17  7:48 ` [PATCH 3/5] btrfs: extent_io: Kill the BUG_ON() in flush_write_bio() Qu Wenruo
2019-01-17  8:22   ` Nikolay Borisov
2019-01-17  8:28     ` Qu Wenruo
2019-01-17  8:52       ` Nikolay Borisov
2019-01-17  7:48 ` [PATCH 4/5] btrfs: disk-io: Show the timing of corrupted tree block explicitly Qu Wenruo
2019-01-17  8:42   ` Nikolay Borisov
2019-01-17  7:48 ` [PATCH 5/5] btrfs: Do mandatory tree block check before submitting bio Qu Wenruo

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).