Current backup root handling has extra check on super generation:

static int find_best_backup_root(struct btrfs_super_block *super)
{
        u64 orig_gen = btrfs_super_generation(super);
...
                if (btrfs_backup_tree_root_gen(backup) != orig_gen &&
                    btrfs_backup_tree_root_gen(backup) > gen) {
                        best_index = i;
                        gen = btrfs_backup_tree_root_gen(backup);

This check is to ensure we don't get backup root with current
generation, but it can still return backup root newer than current root.

So for the following super:
generation:             10
backup[0] generation:   8
backup[1] generation:   9
backup[2] generation:   10
backup[3] generation:   11

If we're calling find_best_backup_root() then we can pick up slot 3
which is newer than current generation.

This patch introduce a new parameter for find_best_backup_root() to
specify the max generation.

So with above superblock, calling find_best_backup_root(sb, sb_gen - 1)
will ensure we get slot 1, other than slot 3.
This also affects how we update backup roots.

Furthermore, due to the change in the return value,
find_best_backup_root() can now return -1 to indicates error (no valid
backup found), so change callers to co-operate.

Signed-off-by: Qu Wenruo <w...@suse.com>
---
 disk-io.c | 34 ++++++++++++++++++++++++++--------
 1 file changed, 26 insertions(+), 8 deletions(-)

diff --git a/disk-io.c b/disk-io.c
index be44eead5cef..36db1be264cd 100644
--- a/disk-io.c
+++ b/disk-io.c
@@ -845,17 +845,22 @@ int btrfs_check_fs_compatibility(struct btrfs_super_block 
*sb,
        return 0;
 }
 
-static int find_best_backup_root(struct btrfs_super_block *super)
+/*
+ * Find the newest backup slot whose generation <= @max_gen
+ *
+ * Can return <0 for error, indicating no valid backup slot for @max_gen.
+ */
+static int find_best_backup_root(struct btrfs_super_block *super,
+                                u64 max_gen)
 {
        struct btrfs_root_backup *backup;
-       u64 orig_gen = btrfs_super_generation(super);
        u64 gen = 0;
-       int best_index = 0;
+       int best_index = -1;
        int i;
 
        for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) {
                backup = super->super_roots + i;
-               if (btrfs_backup_tree_root_gen(backup) != orig_gen &&
+               if (btrfs_backup_tree_root_gen(backup) <= max_gen &&
                    btrfs_backup_tree_root_gen(backup) > gen) {
                        best_index = i;
                        gen = btrfs_backup_tree_root_gen(backup);
@@ -908,9 +913,10 @@ int btrfs_setup_all_roots(struct btrfs_fs_info *fs_info, 
u64 root_tree_bytenr,
                root_tree_bytenr = btrfs_super_root(sb);
        } else if (flags & OPEN_CTREE_BACKUP_ROOT) {
                struct btrfs_root_backup *backup;
-               int index = find_best_backup_root(sb);
-               if (index >= BTRFS_NUM_BACKUP_ROOTS) {
-                       fprintf(stderr, "Invalid backup root number\n");
+               int index = find_best_backup_root(sb,
+                                       btrfs_super_generation(sb) - 1);
+               if (index < 0) {
+                       error("can't find any valid backup root");
                        return -EIO;
                }
                backup = fs_info->super_copy->super_roots + index;
@@ -1707,10 +1713,22 @@ static int write_dev_supers(struct btrfs_fs_info 
*fs_info,
 static void backup_super_roots(struct btrfs_fs_info *info)
 {
        struct btrfs_root_backup *root_backup;
+       u64 current_gen = btrfs_super_generation(info->super_copy);
        int next_backup;
        int last_backup;
 
-       last_backup = find_best_backup_root(info->super_copy);
+       last_backup = find_best_backup_root(info->super_copy, current_gen - 1);
+       /* No older backups, retry current gen */
+       if (last_backup < 0) {
+               last_backup = find_best_backup_root(info->super_copy,
+                                                   current_gen);
+               /*
+                * Still failed, means no valid backup root at all, restart
+                * from slot 0.
+                */
+               if (last_backup < 0)
+                       last_backup = 0;
+       }
        next_backup = (last_backup + 1) % BTRFS_NUM_BACKUP_ROOTS;
 
        /* just overwrite the last backup if we're at the same generation */
-- 
2.23.0

Reply via email to