X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libbcachefs%2Frecovery.c;h=e4983d144483072af1ece1e8dc69fc07b752f96a;hb=17d1c4f4fe29453fbb4087eb5de8aa6f9e6605c7;hp=8c1aa6d2ce45f02f8cea4c782a45be8aa2237b6e;hpb=71111771690f244d13650c73d52ff601ad914d95;p=bcachefs-tools-debian diff --git a/libbcachefs/recovery.c b/libbcachefs/recovery.c index 8c1aa6d..e4983d1 100644 --- a/libbcachefs/recovery.c +++ b/libbcachefs/recovery.c @@ -228,7 +228,7 @@ int bch2_journal_key_insert_take(struct bch_fs *c, enum btree_id id, if (!new_keys.d) { bch_err(c, "%s: error allocating new key array (size %zu)", __func__, new_keys.size); - return -ENOMEM; + return -BCH_ERR_ENOMEM_journal_key_insert; } /* Since @keys was full, there was no gap: */ @@ -266,7 +266,7 @@ int bch2_journal_key_insert(struct bch_fs *c, enum btree_id id, n = kmalloc(bkey_bytes(&k->k), GFP_KERNEL); if (!n) - return -ENOMEM; + return -BCH_ERR_ENOMEM_journal_key_insert; bkey_copy(n, k); ret = bch2_journal_key_insert_take(c, id, level, n); @@ -476,15 +476,34 @@ void bch2_journal_keys_free(struct journal_keys *keys) keys->nr = keys->gap = keys->size = 0; } +static void __journal_keys_sort(struct journal_keys *keys) +{ + struct journal_key *src, *dst; + + sort(keys->d, keys->nr, sizeof(keys->d[0]), journal_sort_key_cmp, NULL); + + src = dst = keys->d; + while (src < keys->d + keys->nr) { + while (src + 1 < keys->d + keys->nr && + src[0].btree_id == src[1].btree_id && + src[0].level == src[1].level && + bpos_eq(src[0].k->k.p, src[1].k->k.p)) + src++; + + *dst++ = *src++; + } + + keys->nr = dst - keys->d; +} + static int journal_keys_sort(struct bch_fs *c) { struct genradix_iter iter; struct journal_replay *i, **_i; struct jset_entry *entry; - struct bkey_i *k, *_n; + struct bkey_i *k; struct journal_keys *keys = &c->journal_keys; - struct journal_key *src, *dst; - size_t nr_keys = 0; + size_t nr_keys = 0, nr_read = 0; genradix_for_each(&c->journal_entries, iter, _i) { i = *_i; @@ -492,7 +511,7 @@ static int journal_keys_sort(struct bch_fs *c) if (!i || i->ignore) continue; - for_each_jset_key(k, _n, entry, &i->j) + for_each_jset_key(k, entry, &i->j) nr_keys++; } @@ -502,8 +521,21 @@ static int journal_keys_sort(struct bch_fs *c) keys->size = roundup_pow_of_two(nr_keys); keys->d = kvmalloc_array(keys->size, sizeof(keys->d[0]), GFP_KERNEL); - if (!keys->d) - return -ENOMEM; + if (!keys->d) { + bch_err(c, "Failed to allocate buffer for sorted journal keys (%zu keys); trying slowpath", + nr_keys); + + do { + keys->size >>= 1; + keys->d = kvmalloc_array(keys->size, sizeof(keys->d[0]), GFP_KERNEL); + } while (!keys->d && keys->size > nr_keys / 8); + + if (!keys->d) { + bch_err(c, "Failed to allocate %zu size buffer for sorted journal keys; exiting", + keys->size); + return -BCH_ERR_ENOMEM_journal_keys_sort; + } + } genradix_for_each(&c->journal_entries, iter, _i) { i = *_i; @@ -511,7 +543,19 @@ static int journal_keys_sort(struct bch_fs *c) if (!i || i->ignore) continue; - for_each_jset_key(k, _n, entry, &i->j) + cond_resched(); + + for_each_jset_key(k, entry, &i->j) { + if (keys->nr == keys->size) { + __journal_keys_sort(keys); + + if (keys->nr > keys->size * 7 / 8) { + bch_err(c, "Too many journal keys for slowpath; have %zu compacted, buf size %zu, processed %zu/%zu", + keys->nr, keys->size, nr_read, nr_keys); + return -BCH_ERR_ENOMEM_journal_keys_sort; + } + } + keys->d[keys->nr++] = (struct journal_key) { .btree_id = entry->btree_id, .level = entry->level, @@ -519,23 +563,15 @@ static int journal_keys_sort(struct bch_fs *c) .journal_seq = le64_to_cpu(i->j.seq), .journal_offset = k->_data - i->j._data, }; - } - - sort(keys->d, keys->nr, sizeof(keys->d[0]), journal_sort_key_cmp, NULL); - - src = dst = keys->d; - while (src < keys->d + keys->nr) { - while (src + 1 < keys->d + keys->nr && - src[0].btree_id == src[1].btree_id && - src[0].level == src[1].level && - bpos_eq(src[0].k->k.p, src[1].k->k.p)) - src++; - *dst++ = *src++; + nr_read++; + } } - keys->nr = dst - keys->d; + __journal_keys_sort(keys); keys->gap = keys->nr; + + bch_verbose(c, "Journal keys: %zu read, %zu after sorting and compacting", nr_keys, keys->nr); return 0; } @@ -601,7 +637,7 @@ static int bch2_journal_replay(struct bch_fs *c, u64 start_seq, u64 end_seq) keys_sorted = kvmalloc_array(sizeof(*keys_sorted), keys->nr, GFP_KERNEL); if (!keys_sorted) - return -ENOMEM; + return -BCH_ERR_ENOMEM_journal_replay; for (i = 0; i < keys->nr; i++) keys_sorted[i] = &keys->d[i]; @@ -611,8 +647,8 @@ static int bch2_journal_replay(struct bch_fs *c, u64 start_seq, u64 end_seq) journal_sort_seq_cmp, NULL); if (keys->nr) { - ret = bch2_fs_log_msg(c, "Starting journal replay (%zu keys in entries %llu-%llu)", - keys->nr, start_seq, end_seq); + ret = bch2_journal_log_msg(c, "Starting journal replay (%zu keys in entries %llu-%llu)", + keys->nr, start_seq, end_seq); if (ret) goto err; } @@ -646,7 +682,7 @@ static int bch2_journal_replay(struct bch_fs *c, u64 start_seq, u64 end_seq) ret = bch2_journal_error(j); if (keys->nr && !ret) - bch2_fs_log_msg(c, "journal replay finished"); + bch2_journal_log_msg(c, "journal replay finished"); err: kvfree(keys_sorted); return ret; @@ -871,7 +907,7 @@ static int verify_superblock_clean(struct bch_fs *c, IS_ERR(k1) || IS_ERR(k2) || k1->k.u64s != k2->k.u64s || - memcmp(k1, k2, bkey_bytes(k1)) || + memcmp(k1, k2, bkey_bytes(&k1->k)) || l1 != l2, c, "superblock btree root %u doesn't match journal after clean shutdown\n" "sb: l=%u %s\n" @@ -905,7 +941,7 @@ static struct bch_sb_field_clean *read_superblock_clean(struct bch_fs *c) GFP_KERNEL); if (!clean) { mutex_unlock(&c->sb_lock); - return ERR_PTR(-ENOMEM); + return ERR_PTR(-BCH_ERR_ENOMEM_read_superblock_clean); } ret = bch2_sb_clean_validate_late(c, clean, READ); @@ -969,30 +1005,45 @@ static int read_btree_roots(struct bch_fs *c) ? FSCK_CAN_IGNORE : 0, "error reading btree root %s", bch2_btree_ids[i]); - if (i == BTREE_ID_alloc) + if (btree_id_is_alloc(i)) c->sb.compat &= ~(1ULL << BCH_COMPAT_alloc_info); } } - for (i = 0; i < BTREE_ID_NR; i++) - if (!c->btree_roots[i].b) + for (i = 0; i < BTREE_ID_NR; i++) { + struct btree_root *r = &c->btree_roots[i]; + + if (!r->b) { + r->alive = false; + r->level = 0; bch2_btree_root_alloc(c, i); + } + } fsck_err: return ret; } static int bch2_fs_initialize_subvolumes(struct bch_fs *c) { - struct bkey_i_snapshot root_snapshot; - struct bkey_i_subvolume root_volume; + struct bkey_i_snapshot_tree root_tree; + struct bkey_i_snapshot root_snapshot; + struct bkey_i_subvolume root_volume; int ret; + bkey_snapshot_tree_init(&root_tree.k_i); + root_tree.k.p.offset = 1; + root_tree.v.master_subvol = cpu_to_le32(1); + root_tree.v.root_snapshot = cpu_to_le32(U32_MAX); + ret = bch2_btree_insert(c, BTREE_ID_snapshot_trees, + &root_tree.k_i, + NULL, NULL, 0); + bkey_snapshot_init(&root_snapshot.k_i); root_snapshot.k.p.offset = U32_MAX; root_snapshot.v.flags = 0; root_snapshot.v.parent = 0; root_snapshot.v.subvol = BCACHEFS_ROOT_SUBVOL; - root_snapshot.v.pad = 0; + root_snapshot.v.tree = cpu_to_le32(1); SET_BCH_SNAPSHOT_SUBVOL(&root_snapshot.v, true); ret = bch2_btree_insert(c, BTREE_ID_snapshots, @@ -1023,16 +1074,15 @@ static int bch2_fs_upgrade_for_subvolumes(struct btree_trans *trans) struct bch_inode_unpacked inode; int ret; - bch2_trans_iter_init(trans, &iter, BTREE_ID_inodes, - SPOS(0, BCACHEFS_ROOT_INO, U32_MAX), 0); - k = bch2_btree_iter_peek_slot(&iter); + k = bch2_bkey_get_iter(trans, &iter, BTREE_ID_inodes, + SPOS(0, BCACHEFS_ROOT_INO, U32_MAX), 0); ret = bkey_err(k); if (ret) - goto err; + return ret; if (!bkey_is_inode(k.k)) { bch_err(trans->c, "root inode not found"); - ret = -ENOENT; + ret = -BCH_ERR_ENOENT_inode; goto err; } @@ -1094,14 +1144,15 @@ int bch2_fs_recovery(struct bch_fs *c) } if (!c->opts.nochanges) { - if (c->sb.version < bcachefs_metadata_version_backpointers) { - bch_info(c, "version prior to backpointers, upgrade and fsck required"); + if (c->sb.version < bcachefs_metadata_required_upgrade_below) { + bch_info(c, "version %s (%u) prior to %s (%u), upgrade and fsck required", + bch2_metadata_versions[c->sb.version], + c->sb.version, + bch2_metadata_versions[bcachefs_metadata_required_upgrade_below], + bcachefs_metadata_required_upgrade_below); c->opts.version_upgrade = true; c->opts.fsck = true; c->opts.fix_errors = FSCK_OPT_YES; - } else if (c->sb.version < bcachefs_metadata_version_inode_v3) { - bch_info(c, "version prior to inode_v3, upgrade required"); - c->opts.version_upgrade = true; } } @@ -1204,8 +1255,8 @@ use_clean: journal_seq += 8; if (blacklist_seq != journal_seq) { - ret = bch2_fs_log_msg(c, "blacklisting entries %llu-%llu", - blacklist_seq, journal_seq) ?: + ret = bch2_journal_log_msg(c, "blacklisting entries %llu-%llu", + blacklist_seq, journal_seq) ?: bch2_journal_seq_blacklist_add(c, blacklist_seq, journal_seq); if (ret) { @@ -1214,12 +1265,15 @@ use_clean: } } - ret = bch2_fs_log_msg(c, "starting journal at entry %llu, replaying %llu-%llu", - journal_seq, last_seq, blacklist_seq - 1) ?: + ret = bch2_journal_log_msg(c, "starting journal at entry %llu, replaying %llu-%llu", + journal_seq, last_seq, blacklist_seq - 1) ?: bch2_fs_journal_start(&c->journal, journal_seq); if (ret) goto err; + if (c->opts.reconstruct_alloc) + bch2_journal_log_msg(c, "dropping alloc info"); + /* * Skip past versions that might have possibly been used (as nonces), * but hadn't had their pointers written: @@ -1251,7 +1305,19 @@ use_clean: goto err; bch_verbose(c, "stripes_read done"); - bch2_stripes_heap_start(c); + if (c->sb.version < bcachefs_metadata_version_snapshot_2) { + err = "error creating root snapshot node"; + ret = bch2_fs_initialize_subvolumes(c); + if (ret) + goto err; + } + + bch_verbose(c, "reading snapshots table"); + err = "error reading snapshots table"; + ret = bch2_fs_snapshots_start(c); + if (ret) + goto err; + bch_verbose(c, "reading snapshots done"); if (c->opts.fsck) { bool metadata_only = c->opts.norecovery; @@ -1265,20 +1331,6 @@ use_clean: set_bit(BCH_FS_INITIAL_GC_DONE, &c->flags); - if (c->sb.version < bcachefs_metadata_version_snapshot_2) { - err = "error creating root snapshot node"; - ret = bch2_fs_initialize_subvolumes(c); - if (ret) - goto err; - } - - bch_verbose(c, "reading snapshots table"); - err = "error reading snapshots table"; - ret = bch2_fs_snapshots_start(c); - if (ret) - goto err; - bch_verbose(c, "reading snapshots done"); - set_bit(BCH_FS_MAY_GO_RW, &c->flags); bch_info(c, "starting journal replay, %zu keys", c->journal_keys.nr); @@ -1346,20 +1398,6 @@ use_clean: if (c->opts.norecovery) goto out; - if (c->sb.version < bcachefs_metadata_version_snapshot_2) { - err = "error creating root snapshot node"; - ret = bch2_fs_initialize_subvolumes(c); - if (ret) - goto err; - } - - bch_verbose(c, "reading snapshots table"); - err = "error reading snapshots table"; - ret = bch2_fs_snapshots_start(c); - if (ret) - goto err; - bch_verbose(c, "reading snapshots done"); - set_bit(BCH_FS_MAY_GO_RW, &c->flags); bch_verbose(c, "starting journal replay, %zu keys", c->journal_keys.nr); @@ -1635,6 +1673,6 @@ int bch2_fs_initialize(struct bch_fs *c) return 0; err: - pr_err("Error initializing new filesystem: %s (%i)", err, ret); + pr_err("Error initializing new filesystem: %s (%s)", err, bch2_err_str(ret)); return ret; }