btrfs: btrfs_super_block::log_root_transid related enhancement
cover btrfs: btrfs_super_block::log_root_transid related enhancement
Even we have btrfs_super_block::log_root_transid, it's never really populated.
This patchset will populate that member and use it to detect corrupted log tree early.
Qu Wenruo (2):
btrfs: Populate btrfs_super_block::log_root_transid
btrfs: Validate btrfs_super_block::log_root_transid
fs/btrfs/disk-io.c | 28 ++++++++++++++++++++++------ fs/btrfs/transaction.c | 1 + fs/btrfs/tree-log.c | 2 ++ 3 files changed, 25 insertions(+), 6 deletions(-)
Signature · 1 line
2.19.0
PATCH 1/2 btrfs: Populate btrfs_super_block::log_root_transid
We have btrfs_super_block::log_root_transid to record the transid of log tree root.
However it's never populated and it's always 0, just as the following dump-super:
log_root 30572544 log_root_transid 0 log_root_level 0
This patch will populate it with log tree root correctly, so the result will be:
log_root 30572544 log_root_transid 6 log_root_level 0
This won't affect current kernel behavior or btrfs check result as we already expect log tree root generation always to be super block genration + 1.
But it could be later used to detect log tree corruption early.
--- fs/btrfs/transaction.c | 1 + fs/btrfs/tree-log.c | 2 ++ 2 files changed, 3 insertions(+)
fs/btrfs/transaction.c +1 -0
@@ -2211,6 +2211,7 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans)btrfs_set_super_log_root (fs_info->super_copy,0 );btrfs_set_super_log_root_level (fs_info->super_copy,0 ); +btrfs_set_super_log_root_transid (fs_info->super_copy,0 );memcpy (fs_info->super_for_commit, fs_info->super_copy,sizeof (*fs_info->super_copy));
fs/btrfs/tree-log.c +2 -0
@@ -3131,6 +3131,8 @@ int btrfs_sync_log(struct btrfs_trans_handle *trans, log_root_tree->node->start);btrfs_set_super_log_root_level (fs_info->super_for_commit,btrfs_header_level (log_root_tree->node)); +btrfs_set_super_log_root_transid (fs_info->super_for_commit, +btrfs_header_generation (log_root_tree->node)); log_root_tree->log_transid++;mutex_unlock (&log_root_tree->log_mutex);
Signature · 1 line
2.19.0
Re: [PATCH 1/2] btrfs: Populate btrfs_super_block::log_root_transid
Quoted 4 lines
we
already expect log tree root generation always to be super block genration + 1.
This is close to what I was looking for by reading the cover-letter, basically what is the impact/bug by not populating it? but can you explain more, I wonder how was check working so long then?
Quoted 1 line
But it could be later used to detect log tree corruption early.
If there is no impact/bug its rather a good idea to change this when the early log tree corruption detection part is ready. So that there is absolute clarity.
The reason why I am grossly wary is - we have incomplete business about how do we handle the write-hole, say raid1 to begin with.
Thanks, Anand
Re: [PATCH 1/2] btrfs: Populate btrfs_super_block::log_root_transid
Quoted 7 lines · Anand Jain
Quoted 4 lines
we
already expect log tree root generation always to be super block genration + 1.This is close to what I was looking for by reading the cover-letter, basically what is the impact/bug by not populating it?
Nothing really.
Both kernel and btrfs-progs completely ignore it.
Quoted 2 lines
but can you
explain more, I wonder how was check working so long then?
For btrfs-progs, the behavior will not change at all.
It still assume log tree root's generation is super geneartion + 1. And if doesn't match reports a transid mismatch error.
For kernel, super validation checker will do such generation check earlier.
So instead of reporting transid mismatch and then btrfs_log_recover error, it will report log tree is bad.
Quoted 9 lines
Quoted 2 lines
But it could be later used to detect log tree corruption early.
If there is no impact/bug its rather a good idea to change this when the early log tree corruption detection part is ready. So that there is absolute clarity.
The reason why I am grossly wary is - we have incomplete business about how do we handle the write-hole, say raid1 to begin with.
If the solution is going to rely on log tree, then the patch shouldn't affect anyone.
The main purpose here is to make the log_root_transid to follow all other generation behavior (root, chunk).
Nothing to really affect users.
Thanks,
Qu
Quoted 2 lines
Thanks, Anand
Re: [PATCH 1/2] btrfs: Populate btrfs_super_block::log_root_transid
In reply to Qu WenruoQuoted 15 lines · Qu Wenruo
We have
btrfs_super_block::log_root_transidto record the transid of log tree root.However it's never populated and it's always 0, just as the following dump-super:
log_root 30572544 log_root_transid 0 log_root_level 0This patch will populate it with log tree root correctly, so the result will be:
log_root 30572544 log_root_transid 6 log_root_level 0
Quoted 5 lines
This won't affect current kernel behavior or btrfs check result as we already expect log tree root generation always to be super block genration + 1.
But it could be later used to detect log tree corruption early.
The backward compatibility seems to be ok in general, I found one scenario where the check will fail:
* mount with unpatched kernel, log_root_transid = 0
* mount with patched kernel, log_root_transid 100, generation 101
* mount with unpatched kernel, log_root_transid 100 (unchanged), generation 201
* mount with patched kernel -> check fails
So the problem is when log_root_transid is not 0 and changes out of sync with the generation. The above sequence of kernels can simply happen when switching between old stable and current releases.
Re: [PATCH 1/2] btrfs: Populate btrfs_super_block::log_root_transid
Quoted 22 lines · David Sterba
Quoted 15 lines · Qu Wenruo
We have
btrfs_super_block::log_root_transidto record the transid of log tree root.However it's never populated and it's always 0, just as the following dump-super:
log_root 30572544 log_root_transid 0 log_root_level 0This patch will populate it with log tree root correctly, so the result will be:
log_root 30572544 log_root_transid 6 log_root_level 0Quoted 5 lines
This won't affect current kernel behavior or btrfs check result as we already expect log tree root generation always to be super block genration + 1.
But it could be later used to detect log tree corruption early.
Quoted 7 lines
The backward compatibility seems to be ok in general, I found one scenario where the check will fail:
* mount with unpatched kernel,
log_root_transid= 0
* mount with patched kernel,log_root_transid100, generation 101
* mount with unpatched kernel,log_root_transid100 (unchanged), generation 201
* mount with patched kernel -> check fails
Indeed, this is a problem I missed.
It provides the old principle, if we're going to change how kernel use/interprete a on-disk memeber, we have to introduce a new incompatible flag.
Please just drop the series of patch.
Thanks,
Qu
Quoted 5 lines
So the problem is when
log_root_transidis not 0 and changes out of sync with the generation. The above sequence of kernels can simply happen when switching between old stable and current releases.
Re: [PATCH 1/2] btrfs: Populate btrfs_super_block::log_root_transid
Quoted 33 lines · Qu Wenruo
Quoted 22 lines · David Sterba
Quoted 15 lines · Qu Wenruo
We have
btrfs_super_block::log_root_transidto record the transid of log tree root.However it's never populated and it's always 0, just as the following dump-super:
log_root 30572544 log_root_transid 0 log_root_level 0This patch will populate it with log tree root correctly, so the result will be:
log_root 30572544 log_root_transid 6 log_root_level 0Quoted 5 lines
This won't affect current kernel behavior or btrfs check result as we already expect log tree root generation always to be super block genration + 1.
But it could be later used to detect log tree corruption early.
Quoted 7 lines
The backward compatibility seems to be ok in general, I found one scenario where the check will fail:
* mount with unpatched kernel,
log_root_transid= 0
* mount with patched kernel,log_root_transid100, generation 101
* mount with unpatched kernel,log_root_transid100 (unchanged), generation 201
* mount with patched kernel -> check fails
Quoted 7 lines
Indeed, this is a problem I missed.
It provides the old principle, if we're going to change how kernel use/interprete a on-disk memeber, we have to introduce a new incompatible flag.
Please just drop the series of patch.
Since this member really doesn't have any purpose now I think the prudent thing to do is to rename it to "reserved1" or "padding" or whatever but basically signal that it's no longer in used. In the future when a new incompaat bit will be required for some feature it can be re-used.
Quoted 9 lines
Thanks,
QuQuoted 5 lines
So the problem is when
log_root_transidis not 0 and changes out of sync with the generation. The above sequence of kernels can simply happen when switching between old stable and current releases.
Re: [PATCH 1/2] btrfs: Populate btrfs_super_block::log_root_transid
Quoted 42 lines · Nikolay Borisov
Quoted 39 lines · Qu Wenruo
Quoted 22 lines · David Sterba
Quoted 15 lines · Qu Wenruo
We have
btrfs_super_block::log_root_transidto record the transid of log tree root.However it's never populated and it's always 0, just as the following dump-super:
log_root 30572544 log_root_transid 0 log_root_level 0This patch will populate it with log tree root correctly, so the result will be:
log_root 30572544 log_root_transid 6 log_root_level 0Quoted 5 lines
This won't affect current kernel behavior or btrfs check result as we already expect log tree root generation always to be super block genration + 1.
But it could be later used to detect log tree corruption early.
Quoted 7 lines
The backward compatibility seems to be ok in general, I found one scenario where the check will fail:
* mount with unpatched kernel,
log_root_transid= 0
* mount with patched kernel,log_root_transid100, generation 101
* mount with unpatched kernel,log_root_transid100 (unchanged), generation 201
* mount with patched kernel -> check failsIndeed, this is a problem I missed.
It provides the old principle, if we're going to change how kernel use/interprete a on-disk memeber, we have to introduce a new incompatible flag.
Quoted 7 lines
Quoted 1 line
Please just drop the series of patch.
Since this member really doesn't have any purpose now I think the prudent thing to do is to rename it to "reserved1" or "padding" or whatever but basically signal that it's no longer in used. In the future when a new incompaat bit will be required for some feature it can be re-used.
Makes sense.
I'll craft a patch for that.
Thanks,
Qu
Quoted 10 lines
Quoted 10 lines
Thanks,
QuQuoted 5 lines
So the problem is when
log_root_transidis not 0 and changes out of sync with the generation. The above sequence of kernels can simply happen when switching between old stable and current releases.
PATCH 2/2 btrfs: Validate btrfs_super_block::log_root_transid
In reply to Qu WenruoSo we can detect log root related problem early and report the error more meaningfully other than hitting it log root read time.
--- fs/btrfs/disk-io.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)
fs/btrfs/disk-io.c +22 -6
@@ -2408,6 +2408,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, {u64 nodesize =btrfs_super_nodesize (sb);u64 sectorsize =btrfs_super_sectorsize (sb); +u64 generation;int ret =0 ;if (btrfs_super_magic (sb) !=BTRFS_MAGIC ) {
@@ -2534,21 +2535,36 @@ static int validate_super(struct btrfs_fs_info *fs_info, ret = -EINVAL ; } + generation =btrfs_super_generation (sb);/* * The generation is a global counter, we'll trust it more than the others * but it's still possible that it's the one that's wrong. */ -if (btrfs_super_generation (sb) <btrfs_super_chunk_root_generation (sb)) +if (generation <btrfs_super_chunk_root_generation (sb))btrfs_warn (fs_info,"suspicious: generation < chunk_root_generation: %llu < %llu" , -btrfs_super_generation (sb), -btrfs_super_chunk_root_generation (sb)); -if (btrfs_super_generation (sb) <btrfs_super_cache_generation (sb) + generation,btrfs_super_chunk_root_generation (sb)); +if (generation <btrfs_super_cache_generation (sb) &&btrfs_super_cache_generation (sb) != (u64)-1 )btrfs_warn (fs_info,"suspicious: generation < cache_generation: %llu < %llu" , -btrfs_super_generation (sb), -btrfs_super_cache_generation (sb)); + generation,btrfs_super_cache_generation (sb)); + +/* +* Check log root transid against super block generation. +* +* Older kernel doesn't populate log_root_transid, only need to check +* it when it's not zero. +* Since replaying suspicious log tree can cause serious problem, refuse +* to mount if it doesn't match. +*/ +if (btrfs_super_log_root_transid (sb) && +btrfs_super_log_root_transid (sb) != generation +1 ) { +btrfs_err (fs_info, +"bad log tree, log_root_transid != generation + 1: %llu != %llu + 1" , +btrfs_super_log_root_transid (sb), generation); + ret = -EINVAL ; + }return ret; }
Signature · 1 line
2.19.0
Re: [PATCH 2/2] btrfs: Validate btrfs_super_block::log_root_transid
Quoted 45 lines · Qu Wenruo
So we can detect log root related problem early and report the error more meaningfully other than hitting it log root read time.
Signed-off-by Qu Wenruo <[email protected]>--- fs/btrfs/disk-io.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)fs/btrfs/disk-io.c +7
-6@@ -2408,6 +2408,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, {u64 nodesize =btrfs_super_nodesize (sb);u64 sectorsize =btrfs_super_sectorsize (sb); +u64 generation;int ret =0 ;if (btrfs_super_magic (sb) !=BTRFS_MAGIC ) {@@ -2534,21 +2535,36 @@ static int validate_super(struct btrfs_fs_info *fs_info, ret = -EINVAL ; } + generation =btrfs_super_generation (sb);/* * The generation is a global counter, we'll trust it more than the others * but it's still possible that it's the one that's wrong. */ -if (btrfs_super_generation (sb) <btrfs_super_chunk_root_generation (sb)) +if (generation <btrfs_super_chunk_root_generation (sb))btrfs_warn (fs_info,"suspicious: generation < chunk_root_generation: %llu < %llu" , -btrfs_super_generation (sb), -btrfs_super_chunk_root_generation (sb)); -if (btrfs_super_generation (sb) <btrfs_super_cache_generation (sb) + generation,btrfs_super_chunk_root_generation (sb)); +if (generation <btrfs_super_cache_generation (sb) &&btrfs_super_cache_generation (sb) != (u64)-1 )btrfs_warn (fs_info,"suspicious: generation < cache_generation: %llu < %llu" , -btrfs_super_generation (sb), -btrfs_super_cache_generation (sb)); + generation,btrfs_super_cache_generation (sb)); +
fs/btrfs/disk-io.c static int validate_super(struct btrfs_fs_info *fs_info, · line 2562
Quoted 10 lines
fs/btrfs/disk-io.c +10
-0+/* +* Check log root transid against super block generation. +* +* Older kernel doesn't populate log_root_transid, only need to check +* it when it's not zero. +* Since replaying suspicious log tree can cause serious problem, refuse +* to mount if it doesn't match. +*/ +if (btrfs_super_log_root_transid (sb) && +btrfs_super_log_root_transid (sb) != generation +1 ) {
nit: in the same vein as you do for btrfs_super_generation just assign super_log_root_Transid to a local var and use that. IMO it's more consistent with what's happening in this function.
Quoted 9 lines
fs/btrfs/disk-io.c +5
-0+btrfs_err (fs_info, +"bad log tree, log_root_transid != generation + 1: %llu != %llu + 1" , +btrfs_super_log_root_transid (sb), generation); + ret = -EINVAL ; + }return ret; }
Re: [PATCH 2/2] btrfs: Validate btrfs_super_block::log_root_transid
Quoted 54 lines · Nikolay Borisov
Quoted 51 lines · Qu Wenruo
So we can detect log root related problem early and report the error more meaningfully other than hitting it log root read time.
Signed-off-by Qu Wenruo <[email protected]>--- fs/btrfs/disk-io.c | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-)fs/btrfs/disk-io.c +13
-6@@ -2408,6 +2408,7 @@ static int validate_super(struct btrfs_fs_info *fs_info, {u64 nodesize =btrfs_super_nodesize (sb);u64 sectorsize =btrfs_super_sectorsize (sb); +u64 generation;int ret =0 ;if (btrfs_super_magic (sb) !=BTRFS_MAGIC ) {@@ -2534,21 +2535,36 @@ static int validate_super(struct btrfs_fs_info *fs_info, ret = -EINVAL ; } + generation =btrfs_super_generation (sb);/* * The generation is a global counter, we'll trust it more than the others * but it's still possible that it's the one that's wrong. */ -if (btrfs_super_generation (sb) <btrfs_super_chunk_root_generation (sb)) +if (generation <btrfs_super_chunk_root_generation (sb))btrfs_warn (fs_info,"suspicious: generation < chunk_root_generation: %llu < %llu" , -btrfs_super_generation (sb), -btrfs_super_chunk_root_generation (sb)); -if (btrfs_super_generation (sb) <btrfs_super_cache_generation (sb) + generation,btrfs_super_chunk_root_generation (sb)); +if (generation <btrfs_super_cache_generation (sb) &&btrfs_super_cache_generation (sb) != (u64)-1 )btrfs_warn (fs_info,"suspicious: generation < cache_generation: %llu < %llu" , -btrfs_super_generation (sb), -btrfs_super_cache_generation (sb)); + generation,btrfs_super_cache_generation (sb)); + +/* +* Check log root transid against super block generation. +* +* Older kernel doesn't populate log_root_transid, only need to check +* it when it's not zero. +* Since replaying suspicious log tree can cause serious problem, refuse
Quoted 8 lines
fs/btrfs/disk-io.c static int validate_super(struct btrfs_fs_info *fs_info, · line 2562
Quoted 4 lines
fs/btrfs/disk-io.c +4
-0+* to mount if it doesn't match. +*/ +if (btrfs_super_log_root_transid (sb) && +btrfs_super_log_root_transid (sb) != generation +1 ) {nit: in the same vein as you do for
btrfs_super_generationjust assignsuper_log_root_Transidto a local var and use that. IMO it's more consistent with what's happening in this function.
@generation is used for more than one location (chunk generation and cache generation), while log root transid (along with chunk generation and cache generation) isn't used more than twice.
Thus I only assign generation to @generation.
Thanks,
Qu
Quoted 10 lines
Quoted 10 lines
fs/btrfs/disk-io.c +5
-0+btrfs_err (fs_info, +"bad log tree, log_root_transid != generation + 1: %llu != %llu + 1" , +btrfs_super_log_root_transid (sb), generation); + ret = -EINVAL ; + }return ret; }
Re: [PATCH 2/2] btrfs: Validate btrfs_super_block::log_root_transid
In reply to Nikolay BorisovQuoted 6 lines · Nikolay Borisov
Quoted 6 lines
fs/btrfs/disk-io.c +6
-0+/* +* Check log root transid against super block generation. +* +* Older kernel doesn't populate log_root_transid, only need to check +* it when it's not zero. +* Since replaying suspicious log tree can cause serious problem, refuse
Quoted 8 lines
fs/btrfs/disk-io.c static int validate_super(struct btrfs_fs_info *fs_info, · line 2562
Quoted 4 lines
fs/btrfs/disk-io.c +4
-0+* to mount if it doesn't match. +*/ +if (btrfs_super_log_root_transid (sb) && +btrfs_super_log_root_transid (sb) != generation +1 ) {nit: in the same vein as you do for
btrfs_super_generationjust assignsuper_log_root_Transidto a local var and use that. IMO it's more consistent with what's happening in this function.
While I see your point I think the way Qu did it is also fine, there's not much duplication and I find it readable.