+// SPDX-License-Identifier: GPL-2.0
#include "bcachefs.h"
#include "alloc_background.h"
#include "dirent.h"
#include "ec.h"
#include "error.h"
+#include "fs-common.h"
#include "fsck.h"
#include "journal_io.h"
#include "journal_reclaim.h"
#define QSTR(n) { { { .len = strlen(n) } }, .name = n }
+/* iterate over keys read from the journal: */
+
+struct journal_iter bch2_journal_iter_init(struct journal_keys *keys,
+ enum btree_id id)
+{
+ return (struct journal_iter) {
+ .keys = keys,
+ .k = keys->d,
+ .btree_id = id,
+ };
+}
+
+struct bkey_s_c bch2_journal_iter_peek(struct journal_iter *iter)
+{
+ while (1) {
+ if (iter->k == iter->keys->d + iter->keys->nr)
+ return bkey_s_c_null;
+
+ if (iter->k->btree_id == iter->btree_id)
+ return bkey_i_to_s_c(iter->k->k);
+
+ iter->k++;
+ }
+
+ return bkey_s_c_null;
+}
+
+struct bkey_s_c bch2_journal_iter_next(struct journal_iter *iter)
+{
+ if (iter->k == iter->keys->d + iter->keys->nr)
+ return bkey_s_c_null;
+
+ iter->k++;
+ return bch2_journal_iter_peek(iter);
+}
+
/* sort and dedup all keys in the journal: */
static void journal_entries_free(struct list_head *list)
bch2_journal_pin_put(j, j->replay_journal_seq++);
}
-static int bch2_extent_replay_key(struct bch_fs *c, struct bkey_i *k)
+static int bch2_extent_replay_key(struct bch_fs *c, enum btree_id btree_id,
+ struct bkey_i *k)
{
struct btree_trans trans;
struct btree_iter *iter, *split_iter;
struct disk_reservation disk_res =
bch2_disk_reservation_init(c, 0);
struct bkey_i *split;
- bool split_compressed = false;
+ struct bpos atomic_end;
+ /*
+ * Some extents aren't equivalent - w.r.t. what the triggers do
+ * - if they're split:
+ */
+ bool remark_if_split = bch2_extent_is_compressed(bkey_i_to_s_c(k)) ||
+ k->k.type == KEY_TYPE_reflink_p;
+ bool remark = false;
int ret;
bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0);
retry:
bch2_trans_begin(&trans);
- iter = bch2_trans_get_iter(&trans, BTREE_ID_EXTENTS,
+ iter = bch2_trans_get_iter(&trans, btree_id,
bkey_start_pos(&k->k),
BTREE_ITER_INTENT);
if (ret)
goto err;
+ atomic_end = bpos_min(k->k.p, iter->l[0].b->key.k.p);
+
split_iter = bch2_trans_copy_iter(&trans, iter);
ret = PTR_ERR_OR_ZERO(split_iter);
if (ret)
if (ret)
goto err;
- if (!split_compressed &&
- bch2_extent_is_compressed(bkey_i_to_s_c(k)) &&
- !bch2_extent_is_atomic(k, split_iter)) {
+ if (!remark &&
+ remark_if_split &&
+ bkey_cmp(atomic_end, k->k.p) < 0) {
ret = bch2_disk_reservation_add(c, &disk_res,
k->k.size *
bch2_bkey_nr_dirty_ptrs(bkey_i_to_s_c(k)),
BCH_DISK_RESERVATION_NOFAIL);
BUG_ON(ret);
- split_compressed = true;
+ remark = true;
}
bkey_copy(split, k);
bch2_cut_front(split_iter->pos, split);
- bch2_extent_trim_atomic(split, split_iter);
+ bch2_cut_back(atomic_end, &split->k);
- bch2_trans_update(&trans, BTREE_INSERT_ENTRY(split_iter, split));
+ bch2_trans_update(&trans, split_iter, split);
bch2_btree_iter_set_pos(iter, split->k.p);
} while (bkey_cmp(iter->pos, k->k.p) < 0);
- if (split_compressed) {
+ if (remark) {
ret = bch2_trans_mark_key(&trans, bkey_i_to_s_c(k),
- -((s64) k->k.size),
+ 0, -((s64) k->k.size),
BCH_BUCKET_MARK_OVERWRITE) ?:
bch2_trans_commit(&trans, &disk_res, NULL,
BTREE_INSERT_ATOMIC|
for_each_journal_key(keys, i) {
replay_now_at(j, keys.journal_seq_base + i->journal_seq);
- switch (i->btree_id) {
- case BTREE_ID_ALLOC:
+ if (i->btree_id == BTREE_ID_ALLOC)
ret = bch2_alloc_replay_key(c, i->k);
- break;
- case BTREE_ID_EXTENTS:
- ret = bch2_extent_replay_key(c, i->k);
- break;
- default:
+ else if (btree_node_type_is_extents(i->btree_id))
+ ret = bch2_extent_replay_key(c, i->btree_id, i->k);
+ else
ret = bch2_btree_insert(c, i->btree_id, i->k,
NULL, NULL,
BTREE_INSERT_NOFAIL|
BTREE_INSERT_LAZY_RW|
BTREE_INSERT_JOURNAL_REPLAY|
BTREE_INSERT_NOMARK);
- break;
- }
if (ret) {
bch_err(c, "journal replay: error %d while replaying key",
switch (entry->type) {
case BCH_JSET_ENTRY_btree_root: {
- struct btree_root *r = &c->btree_roots[entry->btree_id];
+ struct btree_root *r;
+
+ if (entry->btree_id >= BTREE_ID_NR) {
+ bch_err(c, "filesystem has unknown btree type %u",
+ entry->btree_id);
+ return -EINVAL;
+ }
+
+ r = &c->btree_roots[entry->btree_id];
if (entry->u64s) {
r->level = entry->level;
continue;
if (i == BTREE_ID_ALLOC &&
- test_reconstruct_alloc(c)) {
+ c->opts.reconstruct_alloc) {
c->sb.compat &= ~(1ULL << BCH_COMPAT_FEAT_ALLOC_INFO);
continue;
}
ret = bch2_blacklist_table_initialize(c);
- ret = verify_journal_entries_not_blacklisted_or_missing(c,
- &journal_entries);
- if (ret)
- goto err;
+ if (!list_empty(&journal_entries)) {
+ ret = verify_journal_entries_not_blacklisted_or_missing(c,
+ &journal_entries);
+ if (ret)
+ goto err;
+ }
ret = bch2_fs_journal_start(&c->journal, journal_seq,
&journal_entries);
ret = 0;
err:
fsck_err:
+ set_bit(BCH_FS_FSCK_DONE, &c->flags);
bch2_flush_fsck_errs(c);
+
journal_keys_free(&journal_keys);
journal_entries_free(&journal_entries);
kfree(clean);
{
struct bch_inode_unpacked root_inode, lostfound_inode;
struct bkey_inode_buf packed_inode;
- struct bch_hash_info root_hash_info;
struct qstr lostfound = QSTR("lost+found");
const char *err = "cannot allocate memory";
struct bch_dev *ca;
bch2_inode_init(c, &root_inode, 0, 0,
S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0, NULL);
root_inode.bi_inum = BCACHEFS_ROOT_INO;
- root_inode.bi_nlink++; /* lost+found */
bch2_inode_pack(&packed_inode, &root_inode);
err = "error creating root directory";
if (ret)
goto err;
- bch2_inode_init(c, &lostfound_inode, 0, 0,
- S_IFDIR|S_IRWXU|S_IRUGO|S_IXUGO, 0,
- &root_inode);
- lostfound_inode.bi_inum = BCACHEFS_ROOT_INO + 1;
- bch2_inode_pack(&packed_inode, &lostfound_inode);
+ bch2_inode_init_early(c, &lostfound_inode);
err = "error creating lost+found";
- ret = bch2_btree_insert(c, BTREE_ID_INODES,
- &packed_inode.inode.k_i,
- NULL, NULL, 0);
- if (ret)
- goto err;
-
- root_hash_info = bch2_hash_info_init(c, &root_inode);
-
- ret = bch2_dirent_create(c, BCACHEFS_ROOT_INO, &root_hash_info, DT_DIR,
- &lostfound, lostfound_inode.bi_inum, NULL,
- BTREE_INSERT_NOFAIL);
+ ret = bch2_trans_do(c, NULL, BTREE_INSERT_ATOMIC,
+ bch2_create_trans(&trans, BCACHEFS_ROOT_INO,
+ &root_inode, &lostfound_inode,
+ &lostfound,
+ 0, 0, 0755, 0,
+ NULL, NULL));
if (ret)
goto err;