* [PATCH 0/2] btrfs: scrub: update last_physical more frequently
@ 2024-03-08 3:25 ` Qu Wenruo
0 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-03-08 3:10 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
There is a report in the mailling list that scrub only updates its
@last_physical at the end of a chunk.
In fact, it can be worse if there is a used stripe (aka, some extents
exist in the stripe) at the chunk boundary.
As it would skip the @last_physical for that chunk at all.
With @last_physical not update for a long time, if we cancel the scrub
halfway and resume, the resumed one scrub would only start at
@last_physical, meaning a lot of scrubbed extents would be re-scrubbed,
wasting quite some IO and CPU.
This patchset would fix it by updateing @last_physical for each finished
stripe (including both P/Q stripe of RAID56, and all data stripes for
all profiles), so that even if the scrub is cancelled, we at most
re-scrub one stripe.
Qu Wenruo (2):
btrfs: extract the stripe length calculation into a helper
btrfs: scrub: update last_physical after scrubing one stripe
fs/btrfs/scrub.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] btrfs: extract the stripe length calculation into a helper
2024-03-08 3:25 ` Qu Wenruo
@ 2024-03-08 3:25 ` Qu Wenruo
-1 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-03-08 3:10 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
Currently there are two location which needs to calculate the real
length of a stripe (which can be at the end of a chunk, and the chunk
size may not always be 64K aligned).
Extract them into a helper as we're going to have a third user soon.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/scrub.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index c4bd0e60db59..8a21214eca35 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1648,14 +1648,21 @@ static void scrub_reset_stripe(struct scrub_stripe *stripe)
}
}
+static u32 stripe_length(struct scrub_stripe *stripe)
+{
+ ASSERT(stripe->bg);
+
+ return min(BTRFS_STRIPE_LEN,
+ stripe->bg->start + stripe->bg->length - stripe->logical);
+
+}
+
static void scrub_submit_extent_sector_read(struct scrub_ctx *sctx,
struct scrub_stripe *stripe)
{
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
struct btrfs_bio *bbio = NULL;
- unsigned int nr_sectors = min(BTRFS_STRIPE_LEN, stripe->bg->start +
- stripe->bg->length - stripe->logical) >>
- fs_info->sectorsize_bits;
+ unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
u64 stripe_len = BTRFS_STRIPE_LEN;
int mirror = stripe->mirror_num;
int i;
@@ -1725,9 +1732,7 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx,
{
struct btrfs_fs_info *fs_info = sctx->fs_info;
struct btrfs_bio *bbio;
- unsigned int nr_sectors = min(BTRFS_STRIPE_LEN, stripe->bg->start +
- stripe->bg->length - stripe->logical) >>
- fs_info->sectorsize_bits;
+ unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
int mirror = stripe->mirror_num;
ASSERT(stripe->bg);
--
2.44.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] btrfs: scrub: update last_physical after scrubing one stripe
2024-03-08 3:25 ` Qu Wenruo
@ 2024-03-08 3:26 ` Qu Wenruo
-1 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-03-08 3:10 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
Currently sctx->stat.last_physical only got updated in the following
cases:
- When the last stripe of a non-RAID56 chunk is scrubbed
This implies a pitfall, if the last stripe is at the chunk boundary,
and we finished the scrub of the whole chunk, we won't update
last_physical at all until the next chunk.
- When a P/Q stripe of a RAID56 chunk is scrubbed
This leads makes sctx->stat.last_physical to be not update for a long
time if we're scrubbing a large data chunk (which can go up to 10GiB).
And if scrub is cancelled halfway, we would restart from last_physical,
but that last_physical is only updated to the last finished chunk end,
we would re-scrub the same chunk again.
This can waste a lot of time especially when the chunk is huge.
Fix the problem by properly updating @last_physical after each stripe is
scrubbed.
And since we're here, for the sake of consistency, use spin lock to
protect the update of @last_physical, just like all the remaining
call sites touching sctx->stat.
Reported-by: Michel Palleau <michel.palleau@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/CAMFk-+igFTv2E8svg=cQ6o3e6CrR5QwgQ3Ok9EyRaEvvthpqCQ@mail.gmail.com/
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/scrub.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 8a21214eca35..3bccd171be61 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1872,6 +1872,8 @@ static int flush_scrub_stripes(struct scrub_ctx *sctx)
stripe = &sctx->stripes[i];
wait_scrub_stripe_io(stripe);
+ sctx->stat.last_physical = stripe->physical +
+ stripe_length(stripe);
scrub_reset_stripe(stripe);
}
out:
@@ -2337,6 +2339,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
stripe_logical += chunk_logical;
ret = scrub_raid56_parity_stripe(sctx, scrub_dev, bg,
map, stripe_logical);
+ sctx->stat.last_physical = min(physical + BTRFS_STRIPE_LEN,
+ physical_end);
if (ret)
goto out;
goto next;
--
2.44.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 0/2] btrfs: scrub: update last_physical more frequently
@ 2024-03-08 3:25 ` Qu Wenruo
0 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-03-08 3:25 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
There is a report in the mailling list that scrub only updates its
@last_physical at the end of a chunk.
In fact, it can be worse if there is a used stripe (aka, some extents
exist in the stripe) at the chunk boundary.
As it would skip the @last_physical for that chunk at all.
With @last_physical not update for a long time, if we cancel the scrub
halfway and resume, the resumed one scrub would only start at
@last_physical, meaning a lot of scrubbed extents would be re-scrubbed,
wasting quite some IO and CPU.
This patchset would fix it by updateing @last_physical for each finished
stripe (including both P/Q stripe of RAID56, and all data stripes for
all profiles), so that even if the scrub is cancelled, we at most
re-scrub one stripe.
Qu Wenruo (2):
btrfs: extract the stripe length calculation into a helper
btrfs: scrub: update last_physical after scrubing one stripe
fs/btrfs/scrub.c | 21 +++++++++++++++------
1 file changed, 15 insertions(+), 6 deletions(-)
--
2.44.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 1/2] btrfs: extract the stripe length calculation into a helper
@ 2024-03-08 3:25 ` Qu Wenruo
0 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-03-08 3:25 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
Currently there are two location which needs to calculate the real
length of a stripe (which can be at the end of a chunk, and the chunk
size may not always be 64K aligned).
Extract them into a helper as we're going to have a third user soon.
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/scrub.c | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index c4bd0e60db59..8a21214eca35 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1648,14 +1648,21 @@ static void scrub_reset_stripe(struct scrub_stripe *stripe)
}
}
+static u32 stripe_length(struct scrub_stripe *stripe)
+{
+ ASSERT(stripe->bg);
+
+ return min(BTRFS_STRIPE_LEN,
+ stripe->bg->start + stripe->bg->length - stripe->logical);
+
+}
+
static void scrub_submit_extent_sector_read(struct scrub_ctx *sctx,
struct scrub_stripe *stripe)
{
struct btrfs_fs_info *fs_info = stripe->bg->fs_info;
struct btrfs_bio *bbio = NULL;
- unsigned int nr_sectors = min(BTRFS_STRIPE_LEN, stripe->bg->start +
- stripe->bg->length - stripe->logical) >>
- fs_info->sectorsize_bits;
+ unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
u64 stripe_len = BTRFS_STRIPE_LEN;
int mirror = stripe->mirror_num;
int i;
@@ -1725,9 +1732,7 @@ static void scrub_submit_initial_read(struct scrub_ctx *sctx,
{
struct btrfs_fs_info *fs_info = sctx->fs_info;
struct btrfs_bio *bbio;
- unsigned int nr_sectors = min(BTRFS_STRIPE_LEN, stripe->bg->start +
- stripe->bg->length - stripe->logical) >>
- fs_info->sectorsize_bits;
+ unsigned int nr_sectors = stripe_length(stripe) >> fs_info->sectorsize_bits;
int mirror = stripe->mirror_num;
ASSERT(stripe->bg);
--
2.44.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/2] btrfs: scrub: update last_physical after scrubing one stripe
@ 2024-03-08 3:26 ` Qu Wenruo
0 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-03-08 3:26 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
Currently sctx->stat.last_physical only got updated in the following
cases:
- When the last stripe of a non-RAID56 chunk is scrubbed
This implies a pitfall, if the last stripe is at the chunk boundary,
and we finished the scrub of the whole chunk, we won't update
last_physical at all until the next chunk.
- When a P/Q stripe of a RAID56 chunk is scrubbed
This leads makes sctx->stat.last_physical to be not update for a long
time if we're scrubbing a large data chunk (which can go up to 10GiB).
And if scrub is cancelled halfway, we would restart from last_physical,
but that last_physical is only updated to the last finished chunk end,
we would re-scrub the same chunk again.
This can waste a lot of time especially when the chunk is huge.
Fix the problem by properly updating @last_physical after each stripe is
scrubbed.
And since we're here, for the sake of consistency, use spin lock to
protect the update of @last_physical, just like all the remaining
call sites touching sctx->stat.
Reported-by: Michel Palleau <michel.palleau@gmail.com>
Link: https://lore.kernel.org/linux-btrfs/CAMFk-+igFTv2E8svg=cQ6o3e6CrR5QwgQ3Ok9EyRaEvvthpqCQ@mail.gmail.com/
Signed-off-by: Qu Wenruo <wqu@suse.com>
---
fs/btrfs/scrub.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 8a21214eca35..3bccd171be61 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -1872,6 +1872,8 @@ static int flush_scrub_stripes(struct scrub_ctx *sctx)
stripe = &sctx->stripes[i];
wait_scrub_stripe_io(stripe);
+ sctx->stat.last_physical = stripe->physical +
+ stripe_length(stripe);
scrub_reset_stripe(stripe);
}
out:
@@ -2337,6 +2339,8 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
stripe_logical += chunk_logical;
ret = scrub_raid56_parity_stripe(sctx, scrub_dev, bg,
map, stripe_logical);
+ sctx->stat.last_physical = min(physical + BTRFS_STRIPE_LEN,
+ physical_end);
if (ret)
goto out;
goto next;
--
2.44.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] btrfs: extract the stripe length calculation into a helper
2024-03-08 3:25 ` Qu Wenruo
(?)
@ 2024-03-08 11:37 ` Johannes Thumshirn
-1 siblings, 0 replies; 8+ messages in thread
From: Johannes Thumshirn @ 2024-03-08 11:37 UTC (permalink / raw)
To: Qu Wenruo, linux-btrfs@vger.kernel.org, michel.palleau@gmail.com
Looks good,
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] btrfs: scrub: update last_physical more frequently
2024-03-08 3:25 ` Qu Wenruo
` (2 preceding siblings ...)
(?)
@ 2024-04-07 21:36 ` Qu Wenruo
-1 siblings, 0 replies; 8+ messages in thread
From: Qu Wenruo @ 2024-04-07 21:36 UTC (permalink / raw)
To: linux-btrfs, michel.palleau
Ping?
Any feedback on this small series?
Thanks,
Qu
在 2024/3/8 13:55, Qu Wenruo 写道:
> There is a report in the mailling list that scrub only updates its
> @last_physical at the end of a chunk.
> In fact, it can be worse if there is a used stripe (aka, some extents
> exist in the stripe) at the chunk boundary.
> As it would skip the @last_physical for that chunk at all.
>
> With @last_physical not update for a long time, if we cancel the scrub
> halfway and resume, the resumed one scrub would only start at
> @last_physical, meaning a lot of scrubbed extents would be re-scrubbed,
> wasting quite some IO and CPU.
>
> This patchset would fix it by updateing @last_physical for each finished
> stripe (including both P/Q stripe of RAID56, and all data stripes for
> all profiles), so that even if the scrub is cancelled, we at most
> re-scrub one stripe.
>
> Qu Wenruo (2):
> btrfs: extract the stripe length calculation into a helper
> btrfs: scrub: update last_physical after scrubing one stripe
>
> fs/btrfs/scrub.c | 21 +++++++++++++++------
> 1 file changed, 15 insertions(+), 6 deletions(-)
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-04-07 21:36 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-03-08 3:10 [PATCH 0/2] btrfs: scrub: update last_physical more frequently Qu Wenruo
2024-03-08 3:25 ` Qu Wenruo
2024-03-08 3:10 ` [PATCH 1/2] btrfs: extract the stripe length calculation into a helper Qu Wenruo
2024-03-08 3:10 ` Qu Wenruo
2024-03-08 3:25 ` Qu Wenruo
2024-03-08 11:37 ` Johannes Thumshirn
2024-03-08 3:10 ` [PATCH 2/2] btrfs: scrub: update last_physical after scrubing one stripe Qu Wenruo
2024-03-08 3:10 ` Qu Wenruo
2024-03-08 3:26 ` Qu Wenruo
2024-04-07 21:36 ` [PATCH 0/2] btrfs: scrub: update last_physical more frequently Qu Wenruo
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.