From: Nikolay Borisov <nborisov@suse.com>
To: linux-btrfs@vger.kernel.org
Cc: Nikolay Borisov <nborisov@suse.com>
Subject: [PATCH 4/4] btrfs: Don't trim returned range based on input value in find_first_clear_extent_bit
Date: Mon, 3 Jun 2019 13:06:02 +0300 [thread overview]
Message-ID: <20190603100602.19362-5-nborisov@suse.com> (raw)
In-Reply-To: <20190603100602.19362-1-nborisov@suse.com>
Currently find_first_clear_extent_bit always returns a range whose
starting value is >= passed 'start'. This implicit trimming behavior is
somewhat subtle and an implementation detail. Instead, this patch
modifies the function such that now it always returns the range which
contains passed 'start' and has the given bits unset. This range could
either be due to presence of existing records which contains 'start'
but have the bits unset or because there are no records that contain
the given starting offset.
This patch also adds test cases which cover find_first_clear_extent_bit
since they were missing up until now.
Signed-off-by: Nikolay Borisov <nborisov@suse.com>
---
fs/btrfs/extent_io.c | 51 +++++++++++++++---
fs/btrfs/tests/extent-io-tests.c | 89 ++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index d5979558c96f..1dd900cfb7ea 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -1553,8 +1553,8 @@ int find_first_extent_bit(struct extent_io_tree *tree, u64 start,
}
/**
- * find_first_clear_extent_bit - finds the first range that has @bits not set
- * and that starts after @start
+ * find_first_clear_extent_bit - finds the first range that has @bits not set.
+ * This range could start before @start.
*
* @tree - the tree to search
* @start - the offset at/after which the found extent should start
@@ -1594,12 +1594,51 @@ void find_first_clear_extent_bit(struct extent_io_tree *tree, u64 start,
goto out;
}
}
+ /*
+ * At this point 'node' either contains 'start' or start is
+ * before 'node'
+ */
state = rb_entry(node, struct extent_state, rb_node);
- if (in_range(start, state->start, state->end - state->start + 1) &&
- (state->state & bits)) {
- start = state->end + 1;
+
+ if (in_range(start, state->start, state->end - state->start + 1)) {
+ if (state->state & bits) {
+ /*
+ * |--range with bits sets--|
+ * |
+ * start
+ */
+ start = state->end + 1;
+ } else {
+ /*
+ * 'start' falls within a range that doesn't
+ * have the bits set, so take its start as
+ * the beginning of the desire range
+ *
+ * |--range with bits cleared----|
+ * |
+ * start
+ */
+ *start_ret = state->start;
+ break;
+ }
} else {
- *start_ret = start;
+ /*
+ * |---prev range---|---hole/unset---|---node range---|
+ * |
+ * start
+ *
+ * or
+ *
+ * |---hole/unset--||--first node--|
+ * 0 |
+ * start
+ */
+ if (prev) {
+ state = rb_entry(prev, struct extent_state, rb_node);
+ *start_ret = state->end + 1;
+ } else {
+ *start_ret = 0;
+ }
break;
}
}
diff --git a/fs/btrfs/tests/extent-io-tests.c b/fs/btrfs/tests/extent-io-tests.c
index 7bf4d5734dbe..36fe720fc823 100644
--- a/fs/btrfs/tests/extent-io-tests.c
+++ b/fs/btrfs/tests/extent-io-tests.c
@@ -432,6 +432,91 @@ static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
return ret;
}
+static int test_find_first_clear_extent_bit(void)
+{
+
+ struct extent_io_tree tree;
+ u64 start, end;
+
+ test_msg("Running find_first_clear_extent_bit test");
+ extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST, NULL);
+
+ /*
+ * Set 1m-4m alloc/discard and 32m-64m thus leaving a hole
+ * between 4m-32m
+ */
+ set_extent_bits(&tree, SZ_1M, SZ_4M - 1,
+ CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+
+ find_first_clear_extent_bit(&tree, SZ_512K, &start, &end,
+ CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+ if (start != 0 || end != SZ_1M -1)
+ test_err("Error finding beginning range: start: %llu end: %llu\n",
+ start, end);
+
+ /* Now add 32m-64m so that we have a hole between 4m-32m */
+ set_extent_bits(&tree, SZ_32M, SZ_64M - 1,
+ CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+ /*
+ * Request first hole starting at 12m, we should get 4m-32m
+ */
+ find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end,
+ CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+ if (start != SZ_4M || end != SZ_32M - 1)
+ test_err("Error finding trimmed range: start: %llu end: %llu",
+ start, end);
+
+ /*
+ * Search in the middle of allocated range, should get next available,
+ * which happens to be unallocated -> 4m-32m
+ */
+ find_first_clear_extent_bit(&tree, SZ_2M, &start, &end,
+ CHUNK_TRIMMED | CHUNK_ALLOCATED);
+
+ if (start != SZ_4M || end != SZ_32M -1)
+ test_err("Error finding next unalloc range: start: %llu end: %llu",
+ start, end);
+
+ /*
+ * Set 64M-72M with CHUNK_ALLOC flag, then search for CHUNK_TRIMMED flag
+ * being unset in this range, we should get the entry in range 64m-72M
+ */
+ set_extent_bits(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED);
+ find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end,
+ CHUNK_TRIMMED);
+
+ if (start != SZ_64M || end != SZ_64M + SZ_8M - 1)
+ test_err("Error finding exact range: start: %llu end: %llu",
+ start, end);
+
+ find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end,
+ CHUNK_TRIMMED);
+
+ /*
+ * Search in the middle of set range whose immediate neighbour doesn't
+ * have the bits set so it must be returned
+ */
+ if (start != SZ_64M || end != SZ_64M + SZ_8M - 1)
+ test_err("Error finding next alloc range: start: %llu end: %llu",
+ start, end);
+
+ /*
+ * Search beyond any known range, shall return after last known range
+ * and end should be -1
+ */
+ find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED);
+ if (start != SZ_64M+SZ_8M || end != -1)
+ test_err("Error handling beyond end of range search: start: %llu"
+ " end: %llu\n", start, end);
+
+ return 0;
+
+}
+
int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
{
int ret;
@@ -442,6 +527,10 @@ int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
if (ret)
goto out;
+ ret = test_find_first_clear_extent_bit();
+ if (ret)
+ goto out;
+
ret = test_eb_bitmaps(sectorsize, nodesize);
out:
return ret;
--
2.17.1
next prev parent reply other threads:[~2019-06-03 10:06 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-06-03 10:05 [PATCH 0/4] Further FITRIM improvements Nikolay Borisov
2019-06-03 10:05 ` [PATCH 1/4] btrfs: Document __etree_search Nikolay Borisov
2019-06-05 8:04 ` Johannes Thumshirn
2019-06-05 9:13 ` Qu Wenruo
2019-06-05 11:50 ` [PATCH v2] " Nikolay Borisov
2019-06-05 11:51 ` Johannes Thumshirn
2019-06-03 10:06 ` [PATCH 2/4] btrfs: Always trim all unallocated space in btrfs_trim_free_extents Nikolay Borisov
2019-06-05 9:13 ` Qu Wenruo
2019-06-03 10:06 ` [PATCH 3/4] btrfs: Skip first megabyte on device when trimming Nikolay Borisov
2019-06-05 8:06 ` Johannes Thumshirn
2019-06-05 9:14 ` Qu Wenruo
2019-06-05 11:18 ` Nikolay Borisov
2019-06-03 10:06 ` Nikolay Borisov [this message]
2019-06-05 9:25 ` [PATCH 4/4] btrfs: Don't trim returned range based on input value in find_first_clear_extent_bit Qu Wenruo
2019-06-07 13:28 ` [PATCH 0/4] Further FITRIM improvements David Sterba
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190603100602.19362-5-nborisov@suse.com \
--to=nborisov@suse.com \
--cc=linux-btrfs@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox